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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt36
-rw-r--r--build_files/build_environment/cmake/download.cmake5
-rw-r--r--build_files/build_environment/cmake/usd.cmake14
-rw-r--r--build_files/cmake/Modules/FindUSD.cmake5
-rw-r--r--build_files/cmake/Modules/FindWebP.cmake77
-rw-r--r--build_files/cmake/macros.cmake2
-rw-r--r--build_files/cmake/platform/platform_apple.cmake9
-rw-r--r--build_files/cmake/platform/platform_unix.cmake8
-rw-r--r--build_files/cmake/platform/platform_win32.cmake82
-rw-r--r--doc/license/LGPL2.1-license.txt502
-rw-r--r--doc/license/SPDX-license-identifiers.txt1
-rw-r--r--intern/cycles/CMakeLists.txt19
-rw-r--r--intern/cycles/app/CMakeLists.txt10
-rw-r--r--intern/cycles/app/cycles_xml.cpp31
-rw-r--r--intern/cycles/blender/addon/__init__.py11
-rw-r--r--intern/cycles/blender/addon/properties.py8
-rw-r--r--intern/cycles/blender/addon/ui.py9
-rw-r--r--intern/cycles/blender/object.cpp2
-rw-r--r--intern/cycles/blender/shader.cpp3
-rw-r--r--intern/cycles/blender/sync.cpp23
-rw-r--r--intern/cycles/bvh/binning.cpp2
-rw-r--r--intern/cycles/cmake/macros.cmake1
-rw-r--r--intern/cycles/device/CMakeLists.txt3
-rw-r--r--intern/cycles/device/hip/util.h2
-rw-r--r--intern/cycles/hydra/CMakeLists.txt174
-rw-r--r--intern/cycles/hydra/attribute.cpp71
-rw-r--r--intern/cycles/hydra/attribute.h21
-rw-r--r--intern/cycles/hydra/camera.cpp297
-rw-r--r--intern/cycles/hydra/camera.h43
-rw-r--r--intern/cycles/hydra/config.h44
-rw-r--r--intern/cycles/hydra/curves.cpp210
-rw-r--r--intern/cycles/hydra/curves.h42
-rw-r--r--intern/cycles/hydra/display_driver.cpp240
-rw-r--r--intern/cycles/hydra/display_driver.h61
-rw-r--r--intern/cycles/hydra/field.cpp88
-rw-r--r--intern/cycles/hydra/field.h34
-rw-r--r--intern/cycles/hydra/geometry.h54
-rw-r--r--intern/cycles/hydra/geometry.inl247
-rw-r--r--intern/cycles/hydra/instancer.cpp138
-rw-r--r--intern/cycles/hydra/instancer.h45
-rw-r--r--intern/cycles/hydra/light.cpp399
-rw-r--r--intern/cycles/hydra/light.h35
-rw-r--r--intern/cycles/hydra/material.cpp589
-rw-r--r--intern/cycles/hydra/material.h60
-rw-r--r--intern/cycles/hydra/mesh.cpp524
-rw-r--r--intern/cycles/hydra/mesh.h49
-rw-r--r--intern/cycles/hydra/node_util.cpp561
-rw-r--r--intern/cycles/hydra/node_util.h18
-rw-r--r--intern/cycles/hydra/output_driver.cpp78
-rw-r--r--intern/cycles/hydra/output_driver.h23
-rw-r--r--intern/cycles/hydra/plugInfo.json3
-rw-r--r--intern/cycles/hydra/plugin.cpp71
-rw-r--r--intern/cycles/hydra/plugin.h25
-rw-r--r--intern/cycles/hydra/pointcloud.cpp199
-rw-r--r--intern/cycles/hydra/pointcloud.h40
-rw-r--r--intern/cycles/hydra/render_buffer.cpp276
-rw-r--r--intern/cycles/hydra/render_buffer.h85
-rw-r--r--intern/cycles/hydra/render_delegate.cpp514
-rw-r--r--intern/cycles/hydra/render_delegate.h98
-rw-r--r--intern/cycles/hydra/render_pass.cpp175
-rw-r--r--intern/cycles/hydra/render_pass.h34
-rw-r--r--intern/cycles/hydra/resources/plugInfo.json22
-rw-r--r--intern/cycles/hydra/session.cpp170
-rw-r--r--intern/cycles/hydra/session.h59
-rw-r--r--intern/cycles/hydra/volume.cpp91
-rw-r--r--intern/cycles/hydra/volume.h33
-rw-r--r--intern/cycles/integrator/render_scheduler.cpp8
-rw-r--r--intern/cycles/kernel/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/device/cpu/image.h582
-rw-r--r--intern/cycles/kernel/device/cuda/compat.h1
-rw-r--r--intern/cycles/kernel/device/gpu/parallel_reduce.h74
-rw-r--r--intern/cycles/kernel/device/hip/compat.h3
-rw-r--r--intern/cycles/kernel/device/optix/compat.h1
-rw-r--r--intern/cycles/kernel/film/accumulate.h12
-rw-r--r--intern/cycles/kernel/film/read.h2
-rw-r--r--intern/cycles/kernel/geom/curve.h8
-rw-r--r--intern/cycles/kernel/geom/patch.h12
-rw-r--r--intern/cycles/kernel/geom/point.h6
-rw-r--r--intern/cycles/kernel/geom/primitive.h8
-rw-r--r--intern/cycles/kernel/geom/subd_triangle.h14
-rw-r--r--intern/cycles/kernel/geom/triangle.h6
-rw-r--r--intern/cycles/kernel/geom/volume.h2
-rw-r--r--intern/cycles/kernel/integrator/intersect_volume_stack.h4
-rw-r--r--intern/cycles/kernel/integrator/shade_surface.h8
-rw-r--r--intern/cycles/kernel/light/sample.h44
-rw-r--r--intern/cycles/kernel/osl/services.cpp4
-rw-r--r--intern/cycles/kernel/osl/shaders/node_float_curve.osl4
-rw-r--r--intern/cycles/kernel/osl/shaders/node_rgb_curves.osl7
-rw-r--r--intern/cycles/kernel/osl/shaders/node_vector_curves.osl7
-rw-r--r--intern/cycles/kernel/svm/image.h2
-rw-r--r--intern/cycles/kernel/svm/ramp.h16
-rw-r--r--intern/cycles/kernel/svm/vertex_color.h51
-rw-r--r--intern/cycles/kernel/svm/voronoi.h22
-rw-r--r--intern/cycles/kernel/svm/voxel.h2
-rw-r--r--intern/cycles/scene/integrator.cpp6
-rw-r--r--intern/cycles/scene/mesh.cpp8
-rw-r--r--intern/cycles/scene/mesh.h2
-rw-r--r--intern/cycles/scene/shader_nodes.cpp19
-rw-r--r--intern/cycles/scene/shader_nodes.h2
-rw-r--r--intern/cycles/session/session.h4
-rw-r--r--intern/cycles/session/tile.cpp2
-rw-r--r--intern/cycles/util/math_float4.h4
-rw-r--r--intern/cycles/util/math_matrix.h4
-rw-r--r--intern/cycles/util/tbb.h1
-rw-r--r--intern/dualcon/intern/octree.cpp4
-rw-r--r--intern/ghost/GHOST_C-api.h4
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.mm6
-rw-r--r--intern/ghost/intern/GHOST_ImeWin32.cpp11
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm2
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp6
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h9
-rw-r--r--intern/ghost/intern/GHOST_XrControllerModel.cpp2
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h18
-rw-r--r--intern/itasc/Armature.cpp11
-rw-r--r--intern/itasc/Armature.hpp10
-rw-r--r--intern/itasc/Cache.cpp12
-rw-r--r--intern/itasc/Cache.hpp10
-rw-r--r--intern/itasc/ConstraintSet.cpp11
-rw-r--r--intern/itasc/ConstraintSet.hpp10
-rw-r--r--intern/itasc/ControlledObject.cpp11
-rw-r--r--intern/itasc/ControlledObject.hpp10
-rw-r--r--intern/itasc/CopyPose.cpp11
-rw-r--r--intern/itasc/CopyPose.hpp10
-rw-r--r--intern/itasc/Distance.cpp11
-rw-r--r--intern/itasc/Distance.hpp10
-rw-r--r--intern/itasc/FixedObject.cpp11
-rw-r--r--intern/itasc/FixedObject.hpp10
-rw-r--r--intern/itasc/MovingFrame.cpp11
-rw-r--r--intern/itasc/MovingFrame.hpp10
-rw-r--r--intern/itasc/Object.hpp10
-rw-r--r--intern/itasc/Scene.cpp17
-rw-r--r--intern/itasc/Scene.hpp10
-rw-r--r--intern/itasc/Solver.hpp10
-rw-r--r--intern/itasc/UncontrolledObject.cpp11
-rw-r--r--intern/itasc/UncontrolledObject.hpp10
-rw-r--r--intern/itasc/WDLSSolver.cpp11
-rw-r--r--intern/itasc/WDLSSolver.hpp10
-rw-r--r--intern/itasc/WSDLSSolver.cpp11
-rw-r--r--intern/itasc/WSDLSSolver.hpp10
-rw-r--r--intern/itasc/WorldObject.cpp11
-rw-r--r--intern/itasc/WorldObject.hpp10
-rw-r--r--intern/itasc/eigen_types.cpp11
-rw-r--r--intern/itasc/eigen_types.hpp10
-rw-r--r--intern/itasc/ublas_types.hpp10
-rw-r--r--intern/mantaflow/intern/MANTA_main.cpp2
-rw-r--r--intern/mantaflow/intern/strings/fluid_script.h8
-rw-r--r--intern/mikktspace/mikktspace.c8
-rw-r--r--intern/opencolorio/fallback_impl.cc10
-rw-r--r--intern/opencolorio/ocio_capi.cc10
-rw-r--r--intern/opencolorio/ocio_capi.h2
-rw-r--r--intern/opencolorio/ocio_impl.cc9
-rw-r--r--intern/opencolorio/ocio_impl.h6
-rw-r--r--intern/opencolorio/ocio_impl_glsl.cc33
-rw-r--r--release/datafiles/blender_icons16/icon16_curves.dat (renamed from release/datafiles/blender_icons16/icon16_hair.dat)bin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_curves_data.dat (renamed from release/datafiles/blender_icons16/icon16_hair_data.dat)bin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_force_boid.datbin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_outliner_data_curves.dat (renamed from release/datafiles/blender_icons16/icon16_outliner_data_hair.dat)bin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons16/icon16_outliner_ob_curves.dat (renamed from release/datafiles/blender_icons16/icon16_outliner_ob_hair.dat)bin1048 -> 1048 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_curves.dat (renamed from release/datafiles/blender_icons32/icon32_hair.dat)bin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_curves_data.dat (renamed from release/datafiles/blender_icons32/icon32_hair_data.dat)bin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_force_boid.datbin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_outliner_data_curves.dat (renamed from release/datafiles/blender_icons32/icon32_outliner_data_hair.dat)bin4120 -> 4120 bytes
-rw-r--r--release/datafiles/blender_icons32/icon32_outliner_ob_curves.dat (renamed from release/datafiles/blender_icons32/icon32_outliner_ob_hair.dat)bin4120 -> 4120 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_add.datbin0 -> 2132 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_comb.datbin0 -> 4472 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_cut.datbin0 -> 2456 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_delete.datbin0 -> 2060 bytes
-rw-r--r--release/datafiles/icons/ops.curves.sculpt_grow.datbin0 -> 1736 bytes
m---------release/scripts/addons0
-rw-r--r--release/scripts/modules/rna_manual_reference.py1
-rw-r--r--release/scripts/presets/keyconfig/Blender.py36
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/blender_default.py70
-rw-r--r--release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py4
-rw-r--r--release/scripts/startup/bl_operators/wm.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_object.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_output.py36
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py3
-rw-r--r--release/scripts/startup/bl_ui/space_node.py2
-rw-r--r--release/scripts/startup/bl_ui/space_outliner.py9
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py12
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py34
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py2
-rw-r--r--release/scripts/startup/nodeitems_builtins.py72
-rw-r--r--source/blender/CMakeLists.txt2
-rw-r--r--source/blender/blenfont/BLF_api.h4
-rw-r--r--source/blender/blenfont/intern/blf.c14
-rw-r--r--source/blender/blenfont/intern/blf_dir.c4
-rw-r--r--source/blender/blenfont/intern/blf_font.c18
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c4
-rw-r--r--source/blender/blenfont/intern/blf_internal.h4
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h4
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c12
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh36
-rw-r--r--source/blender/blenkernel/BKE_attribute_math.hh76
-rw-r--r--source/blender/blenkernel/BKE_brush.h3
-rw-r--r--source/blender/blenkernel/BKE_curve.h2
-rw-r--r--source/blender/blenkernel/BKE_curves.hh346
-rw-r--r--source/blender/blenkernel/BKE_customdata.h11
-rw-r--r--source/blender/blenkernel/BKE_dynamicpaint.h2
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh54
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h3
-rw-r--r--source/blender/blenkernel/BKE_image.h48
-rw-r--r--source/blender/blenkernel/BKE_image_format.h97
-rw-r--r--source/blender/blenkernel/BKE_image_partial_update.hh6
-rw-r--r--source/blender/blenkernel/BKE_image_save.h28
-rw-r--r--source/blender/blenkernel/BKE_key.h4
-rw-r--r--source/blender/blenkernel/BKE_layer.h35
-rw-r--r--source/blender/blenkernel/BKE_lib_query.h14
-rw-r--r--source/blender/blenkernel/BKE_lib_remap.h10
-rw-r--r--source/blender/blenkernel/BKE_mesh.h15
-rw-r--r--source/blender/blenkernel/BKE_mesh_sample.hh8
-rw-r--r--source/blender/blenkernel/BKE_node.h45
-rw-r--r--source/blender/blenkernel/BKE_packedFile.h6
-rw-r--r--source/blender/blenkernel/BKE_scene.h4
-rw-r--r--source/blender/blenkernel/BKE_spline.hh22
-rw-r--r--source/blender/blenkernel/BKE_subdiv_modifier.h4
-rw-r--r--source/blender/blenkernel/BKE_tracking.h1
-rw-r--r--source/blender/blenkernel/BKE_type_conversions.hh8
-rw-r--r--source/blender/blenkernel/CMakeLists.txt22
-rw-r--r--source/blender/blenkernel/intern/appdir.c12
-rw-r--r--source/blender/blenkernel/intern/armature.c4
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc101
-rw-r--r--source/blender/blenkernel/intern/bpath_test.cc12
-rw-r--r--source/blender/blenkernel/intern/brush.c23
-rw-r--r--source/blender/blenkernel/intern/collection.c2
-rw-r--r--source/blender/blenkernel/intern/curve.cc96
-rw-r--r--source/blender/blenkernel/intern/curve_bezier.cc139
-rw-r--r--source/blender/blenkernel/intern/curve_catmull_rom.cc114
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc8
-rw-r--r--source/blender/blenkernel/intern/curve_nurbs.cc251
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc3
-rw-r--r--source/blender/blenkernel/intern/curves.cc10
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc594
-rw-r--r--source/blender/blenkernel/intern/curves_geometry_test.cc322
-rw-r--r--source/blender/blenkernel/intern/customdata.cc239
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c8
-rw-r--r--source/blender/blenkernel/intern/fluid.c8
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc8
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curves.cc6
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc8
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc89
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc1
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc10
-rw-r--r--source/blender/blenkernel/intern/image.cc981
-rw-r--r--source/blender/blenkernel/intern/image_format.cc966
-rw-r--r--source/blender/blenkernel/intern/image_partial_update.cc2
-rw-r--r--source/blender/blenkernel/intern/image_save.c441
-rw-r--r--source/blender/blenkernel/intern/image_save.cc822
-rw-r--r--source/blender/blenkernel/intern/image_test.cc186
-rw-r--r--source/blender/blenkernel/intern/key.c113
-rw-r--r--source/blender/blenkernel/intern/lib_override.c148
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c218
-rw-r--r--source/blender/blenkernel/intern/mesh.cc3
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c8
-rw-r--r--source/blender/blenkernel/intern/mesh_mirror.c2
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc68
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.cc1
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.cc60
-rw-r--r--source/blender/blenkernel/intern/movieclip.c5
-rw-r--r--source/blender/blenkernel/intern/multires_unsubdivide.c1
-rw-r--r--source/blender/blenkernel/intern/node.cc90
-rw-r--r--source/blender/blenkernel/intern/node_tree_update.cc10
-rw-r--r--source/blender/blenkernel/intern/object.cc6
-rw-r--r--source/blender/blenkernel/intern/ocean.c1
-rw-r--r--source/blender/blenkernel/intern/packedFile.c19
-rw-r--r--source/blender/blenkernel/intern/paint.c1
-rw-r--r--source/blender/blenkernel/intern/particle.c8
-rw-r--r--source/blender/blenkernel/intern/particle_child.c6
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c6
-rw-r--r--source/blender/blenkernel/intern/particle_system.c14
-rw-r--r--source/blender/blenkernel/intern/scene.c52
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc11
-rw-r--r--source/blender/blenkernel/intern/spline_bezier.cc2
-rw-r--r--source/blender/blenkernel/intern/spline_nurbs.cc2
-rw-r--r--source/blender/blenkernel/intern/spline_poly.cc2
-rw-r--r--source/blender/blenkernel/intern/studiolight.c17
-rw-r--r--source/blender/blenkernel/intern/subdiv.c2
-rw-r--r--source/blender/blenkernel/intern/subdiv_modifier.c4
-rw-r--r--source/blender/blenkernel/intern/text.c5
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c78
-rw-r--r--source/blender/blenkernel/intern/type_conversions.cc31
-rw-r--r--source/blender/blenlib/BLI_cpp_type.hh (renamed from source/blender/functions/FN_cpp_type.hh)126
-rw-r--r--source/blender/blenlib/BLI_cpp_type_make.hh (renamed from source/blender/functions/FN_cpp_type_make.hh)19
-rw-r--r--source/blender/blenlib/BLI_generic_array.hh (renamed from source/blender/functions/FN_generic_array.hh)11
-rw-r--r--source/blender/blenlib/BLI_generic_pointer.hh (renamed from source/blender/functions/FN_generic_pointer.hh)6
-rw-r--r--source/blender/blenlib/BLI_generic_span.hh (renamed from source/blender/functions/FN_generic_span.hh)9
-rw-r--r--source/blender/blenlib/BLI_generic_value_map.hh (renamed from source/blender/functions/FN_generic_value_map.hh)7
-rw-r--r--source/blender/blenlib/BLI_generic_vector_array.hh (renamed from source/blender/functions/FN_generic_vector_array.hh)9
-rw-r--r--source/blender/blenlib/BLI_generic_virtual_array.hh (renamed from source/blender/functions/FN_generic_virtual_array.hh)15
-rw-r--r--source/blender/blenlib/BLI_generic_virtual_vector_array.hh (renamed from source/blender/functions/FN_generic_virtual_vector_array.hh)13
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h29
-rw-r--r--source/blender/blenlib/BLI_math_geom.h24
-rw-r--r--source/blender/blenlib/BLI_math_statistics.h8
-rw-r--r--source/blender/blenlib/BLI_math_vector.h7
-rw-r--r--source/blender/blenlib/BLI_rand.hh6
-rw-r--r--source/blender/blenlib/BLI_sort.hh32
-rw-r--r--source/blender/blenlib/BLI_timeit.hh35
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh10
-rw-r--r--source/blender/blenlib/CMakeLists.txt22
-rw-r--r--source/blender/blenlib/intern/BLI_filelist.c16
-rw-r--r--source/blender/blenlib/intern/cpp_type.cc28
-rw-r--r--source/blender/blenlib/intern/delaunay_2d.cc9
-rw-r--r--source/blender/blenlib/intern/expr_pylike_eval.c12
-rw-r--r--source/blender/blenlib/intern/fileops.c6
-rw-r--r--source/blender/blenlib/intern/generic_vector_array.cc (renamed from source/blender/functions/intern/generic_vector_array.cc)8
-rw-r--r--source/blender/blenlib/intern/generic_virtual_array.cc (renamed from source/blender/functions/intern/generic_virtual_array.cc)11
-rw-r--r--source/blender/blenlib/intern/generic_virtual_vector_array.cc (renamed from source/blender/functions/intern/generic_virtual_vector_array.cc)6
-rw-r--r--source/blender/blenlib/intern/math_geom.c38
-rw-r--r--source/blender/blenlib/intern/math_statistics.c24
-rw-r--r--source/blender/blenlib/intern/math_vector.c13
-rw-r--r--source/blender/blenlib/intern/mesh_intersect.cc11
-rw-r--r--source/blender/blenlib/intern/path_util.c4
-rw-r--r--source/blender/blenlib/intern/rand.cc9
-rw-r--r--source/blender/blenlib/intern/timeit.cc18
-rw-r--r--source/blender/blenlib/tests/BLI_cpp_type_test.cc (renamed from source/blender/functions/tests/FN_cpp_type_test.cc)38
-rw-r--r--source/blender/blenlib/tests/BLI_generic_array_test.cc (renamed from source/blender/functions/tests/FN_generic_array_test.cc)7
-rw-r--r--source/blender/blenlib/tests/BLI_generic_span_test.cc (renamed from source/blender/functions/tests/FN_generic_span_test.cc)6
-rw-r--r--source/blender/blenlib/tests/BLI_generic_vector_array_test.cc (renamed from source/blender/functions/tests/FN_generic_vector_array_test.cc)6
-rw-r--r--source/blender/blenlib/tests/BLI_math_vector_test.cc2
-rw-r--r--source/blender/blenlib/tests/BLI_mesh_boolean_test.cc10
-rw-r--r--source/blender/blenlib/tests/BLI_mesh_intersect_test.cc10
-rw-r--r--source/blender/blenlib/tests/performance/BLI_ghash_performance_test.cc62
-rw-r--r--source/blender/blenlib/tests/performance/BLI_task_performance_test.cc6
-rw-r--r--source/blender/blenloader/intern/versioning_290.c104
-rw-r--r--source/blender/blenloader/intern/versioning_300.c241
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c4
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.cc2
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.h13
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_normals.c16
-rw-r--r--source/blender/bmesh/intern/bmesh_query.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c6
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c2
-rw-r--r--source/blender/compositor/COM_compositor.h8
-rw-r--r--source/blender/compositor/intern/COM_CompositorContext.cc2
-rw-r--r--source/blender/compositor/intern/COM_CompositorContext.h36
-rw-r--r--source/blender/compositor/intern/COM_Debug.cc6
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cc4
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.h2
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cc5
-rw-r--r--source/blender/compositor/intern/COM_compositor.cc14
-rw-r--r--source/blender/compositor/nodes/COM_OutputFileNode.cc29
-rw-r--r--source/blender/compositor/nodes/COM_OutputFileNode.h1
-rw-r--r--source/blender/compositor/nodes/COM_SplitViewerNode.cc5
-rw-r--r--source/blender/compositor/nodes/COM_TextureNode.cc3
-rw-r--r--source/blender/compositor/nodes/COM_ViewerNode.cc5
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.cc2
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc48
-rw-r--r--source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h12
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cc32
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.h12
-rw-r--r--source/blender/draw/CMakeLists.txt11
-rw-r--r--source/blender/draw/DRW_engine.h1
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c2
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows_cascade.c22
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_dof_setup_frag.glsl8
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl2
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_engine.cc110
-rw-r--r--source/blender/draw/engines/eevee_next/eevee_engine.h19
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c22
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_defines.h8
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_data.c35
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c14
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h61
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader.c171
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader_shared.h113
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl47
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl3
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl2
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl70
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl13
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_mask_invert_frag.glsl5
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl138
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl60
-rw-r--r--source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh138
-rw-r--r--source/blender/draw/engines/gpencil/shaders/infos/gpencil_vfx_info.hh94
-rw-r--r--source/blender/draw/engines/image/image_drawing_mode.hh21
-rw-r--r--source/blender/draw/engines/overlay/overlay_metaball.c5
-rw-r--r--source/blender/draw/engines/overlay/shaders/background_frag.glsl4
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl2
-rw-r--r--source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl4
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl2
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl4
-rw-r--r--source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl2
-rw-r--r--source/blender/draw/intern/DRW_gpu_wrapper.hh184
-rw-r--r--source/blender/draw/intern/DRW_render.h19
-rw-r--r--source/blender/draw/intern/draw_cache_impl_curves.cc20
-rw-r--r--source/blender/draw/intern/draw_cache_impl_gpencil.c4
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc151
-rw-r--r--source/blender/draw/intern/draw_manager.c10
-rw-r--r--source/blender/draw/intern/draw_manager.h38
-rw-r--r--source/blender/draw/intern/draw_manager_data.c68
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c25
-rw-r--r--source/blender/draw/intern/draw_shader_shared.h12
-rw-r--r--source/blender/draw/intern/draw_texture_pool.cc73
-rw-r--r--source/blender/draw/intern/draw_texture_pool.h11
-rw-r--r--source/blender/draw/intern/draw_view_data.cc3
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc7
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc18
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc2
-rw-r--r--source/blender/draw/intern/shaders/common_gpencil_lib.glsl409
-rw-r--r--source/blender/draw/intern/shaders/common_hair_lib.glsl4
-rw-r--r--source/blender/draw/intern/shaders/common_math_geom_lib.glsl2
-rw-r--r--source/blender/draw/intern/shaders/common_math_lib.glsl104
-rw-r--r--source/blender/draw/intern/shaders/common_view_lib.glsl4
-rw-r--r--source/blender/draw/intern/shaders/draw_object_infos_info.hh1
-rw-r--r--source/blender/draw/intern/shaders/draw_view_info.hh24
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c2
-rw-r--r--source/blender/editors/animation/keyframes_edit.c4
-rw-r--r--source/blender/editors/animation/keyframes_general.c62
-rw-r--r--source/blender/editors/animation/keyingsets.c67
-rw-r--r--source/blender/editors/armature/armature_relations.c9
-rw-r--r--source/blender/editors/armature/armature_select.c239
-rw-r--r--source/blender/editors/armature/pose_select.c154
-rw-r--r--source/blender/editors/armature/pose_slide.c4
-rw-r--r--source/blender/editors/armature/pose_transform.c2
-rw-r--r--source/blender/editors/asset/intern/asset_indexer.cc7
-rw-r--r--source/blender/editors/curve/curve_intern.h1
-rw-r--r--source/blender/editors/curve/editcurve.c175
-rw-r--r--source/blender/editors/curve/editfont.c33
-rw-r--r--source/blender/editors/curves/intern/curves_add.cc4
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt13
-rw-r--r--source/blender/editors/geometry/geometry_attributes.cc4
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c56
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c9
-rw-r--r--source/blender/editors/include/ED_armature.h28
-rw-r--r--source/blender/editors/include/ED_curve.h18
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h2
-rw-r--r--source/blender/editors/include/ED_lattice.h9
-rw-r--r--source/blender/editors/include/ED_mask.h1
-rw-r--r--source/blender/editors/include/ED_mball.h16
-rw-r--r--source/blender/editors/include/ED_mesh.h15
-rw-r--r--source/blender/editors/include/ED_particle.h6
-rw-r--r--source/blender/editors/include/ED_select_utils.h25
-rw-r--r--source/blender/editors/include/UI_interface.h10
-rw-r--r--source/blender/editors/interface/interface.c12
-rw-r--r--source/blender/editors/interface/interface_draw.c4
-rw-r--r--source/blender/editors/interface/interface_handlers.c11
-rw-r--r--source/blender/editors/interface/interface_intern.h3
-rw-r--r--source/blender/editors/interface/interface_layout.c4
-rw-r--r--source/blender/editors/interface/interface_ops.c3
-rw-r--r--source/blender/editors/interface/interface_templates.c7
-rw-r--r--source/blender/editors/interface/interface_utils.c24
-rw-r--r--source/blender/editors/interface/interface_widgets.c3
-rw-r--r--source/blender/editors/io/io_collada.c8
-rw-r--r--source/blender/editors/io/io_obj.c9
-rw-r--r--source/blender/editors/lattice/editlattice_select.c93
-rw-r--r--source/blender/editors/mask/mask_draw.c15
-rw-r--r--source/blender/editors/mesh/editface.c94
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c1
-rw-r--r--source/blender/editors/mesh/editmesh_path.c6
-rw-r--r--source/blender/editors/mesh/editmesh_rip_edge.c3
-rw-r--r--source/blender/editors/mesh/editmesh_select.c181
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c9
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c1
-rw-r--r--source/blender/editors/metaball/mball_edit.c242
-rw-r--r--source/blender/editors/object/CMakeLists.txt2
-rw-r--r--source/blender/editors/object/object_bake_api.c1
-rw-r--r--source/blender/editors/object/object_gpencil_modifier.c2
-rw-r--r--source/blender/editors/object/object_intern.h2
-rw-r--r--source/blender/editors/object/object_modifier.c2
-rw-r--r--source/blender/editors/object/object_transform.cc (renamed from source/blender/editors/object/object_transform.c)341
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c14
-rw-r--r--source/blender/editors/physics/particle_edit.c165
-rw-r--r--source/blender/editors/render/render_internal.cc15
-rw-r--r--source/blender/editors/render/render_opengl.cc12
-rw-r--r--source/blender/editors/render/render_preview.cc24
-rw-r--r--source/blender/editors/scene/CMakeLists.txt2
-rw-r--r--source/blender/editors/screen/screendump.c3
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt10
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc232
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_add.cc792
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_comb.cc377
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_delete.cc105
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_intern.hh53
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_ops.cc345
-rw-r--r--source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc163
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c14
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_dyntopo.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c2
-rw-r--r--source/blender/editors/space_action/action_edit.c4
-rw-r--r--source/blender/editors/space_action/space_action.c4
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c30
-rw-r--r--source/blender/editors/space_clip/tracking_ops_track.c2
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_file/filelist.c171
-rw-r--r--source/blender/editors/space_file/fsmenu.c12
-rw-r--r--source/blender/editors/space_graph/graph_intern.h1
-rw-r--r--source/blender/editors/space_graph/graph_ops.c1
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c134
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_image/image_buttons.c31
-rw-r--r--source/blender/editors/space_image/image_ops.c50
-rw-r--r--source/blender/editors/space_nla/space_nla.c6
-rw-r--r--source/blender/editors/space_node/link_drag_search.cc3
-rw-r--r--source/blender/editors/space_node/node_add.cc107
-rw-r--r--source/blender/editors/space_node/node_draw.cc7
-rw-r--r--source/blender/editors/space_node/node_edit.cc35
-rw-r--r--source/blender/editors/space_node/node_intern.hh2
-rw-r--r--source/blender/editors/space_node/node_ops.cc2
-rw-r--r--source/blender/editors/space_node/node_templates.cc7
-rw-r--r--source/blender/editors/space_node/node_view.cc86
-rw-r--r--source/blender/editors/space_node/space_node.cc11
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.cc2
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.cc127
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.cc11
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.hh2
-rw-r--r--source/blender/editors/space_outliner/outliner_select.cc2
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.cc35
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.cc1
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.cc6
-rw-r--r--source/blender/editors/space_outliner/space_outliner.cc2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.hh3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_override_library.cc145
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_view_layer.cc9
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.cc1
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element.hh3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.cc11
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_id.hh1
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.cc9
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.hh12
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_rna.cc2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c4
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc5
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh11
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc14
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh4
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc2
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c1226
-rw-r--r--source/blender/editors/transform/transform.c6
-rw-r--r--source/blender/editors/transform/transform_snap.c4
-rw-r--r--source/blender/editors/transform/transform_snap_object.c67
-rw-r--r--source/blender/editors/util/select_utils.c14
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c4
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c235
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c1
-rw-r--r--source/blender/freestyle/CMakeLists.txt2
-rw-r--r--source/blender/freestyle/intern/application/Controller.cpp4
-rw-r--r--source/blender/freestyle/intern/python/BPy_Freestyle.cpp14
-rw-r--r--source/blender/freestyle/intern/python/BPy_MediumType.cpp2
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp16
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapIO.cpp1294
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapIO.h89
-rw-r--r--source/blender/freestyle/intern/winged_edge/WEdge.h73
-rw-r--r--source/blender/functions/CMakeLists.txt16
-rw-r--r--source/blender/functions/FN_field.hh8
-rw-r--r--source/blender/functions/FN_field_cpp_type.hh8
-rw-r--r--source/blender/functions/FN_multi_function.hh3
-rw-r--r--source/blender/functions/FN_multi_function_data_type.hh2
-rw-r--r--source/blender/functions/FN_multi_function_params.hh6
-rw-r--r--source/blender/functions/intern/cpp_types.cc29
-rw-r--r--source/blender/functions/intern/field.cc36
-rw-r--r--source/blender/functions/tests/FN_field_test.cc2
-rw-r--r--source/blender/geometry/intern/mesh_to_curve_convert.cc24
-rw-r--r--source/blender/geometry/intern/realize_instances.cc17
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt1
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencildash.c32
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c628
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_util.c2
-rw-r--r--source/blender/gpu/CMakeLists.txt74
-rw-r--r--source/blender/gpu/GPU_capabilities.h1
-rw-r--r--source/blender/gpu/GPU_compute.h3
-rw-r--r--source/blender/gpu/GPU_context.h15
-rw-r--r--source/blender/gpu/GPU_platform.h14
-rw-r--r--source/blender/gpu/GPU_storage_buffer.h52
-rw-r--r--source/blender/gpu/GPU_texture.h11
-rw-r--r--source/blender/gpu/intern/gpu_backend.hh11
-rw-r--r--source/blender/gpu/intern/gpu_capabilities.cc5
-rw-r--r--source/blender/gpu/intern/gpu_capabilities_private.hh9
-rw-r--r--source/blender/gpu/intern/gpu_compute.cc15
-rw-r--r--source/blender/gpu/intern/gpu_context.cc73
-rw-r--r--source/blender/gpu/intern/gpu_platform.cc13
-rw-r--r--source/blender/gpu/intern/gpu_platform_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc10
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.cc4
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.hh12
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc15
-rw-r--r--source/blender/gpu/intern/gpu_shader_log.cc3
-rw-r--r--source/blender/gpu/intern/gpu_storage_buffer.cc106
-rw-r--r--source/blender/gpu/intern/gpu_storage_buffer_private.hh65
-rw-r--r--source/blender/gpu/intern/gpu_texture.cc38
-rw-r--r--source/blender/gpu/intern/gpu_texture_private.hh9
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c6
-rw-r--r--source/blender/gpu/metal/mtl_backend.hh79
-rw-r--r--source/blender/gpu/metal/mtl_backend.mm408
-rw-r--r--source/blender/gpu/metal/mtl_capabilities.hh47
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc16
-rw-r--r--source/blender/gpu/opengl/gl_backend.hh24
-rw-r--r--source/blender/gpu/opengl/gl_compute.cc2
-rw-r--r--source/blender/gpu/opengl/gl_context.hh3
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc20
-rw-r--r--source/blender/gpu/opengl/gl_shader.hh5
-rw-r--r--source/blender/gpu/opengl/gl_storage_buffer.cc149
-rw-r--r--source/blender/gpu/opengl/gl_storage_buffer.hh50
-rw-r--r--source/blender/gpu/opengl/gl_texture.cc20
-rw-r--r--source/blender/gpu/opengl/gl_texture.hh1
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl27
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_frag.glsl4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_vert.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl9
-rw-r--r--source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl17
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp16
-rw-r--r--source/blender/imbuf/CMakeLists.txt14
-rw-r--r--source/blender/imbuf/IMB_colormanagement.h23
-rw-r--r--source/blender/imbuf/IMB_imbuf.h8
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h3
-rw-r--r--source/blender/imbuf/IMB_openexr.h (renamed from source/blender/imbuf/intern/openexr/openexr_multi.h)10
-rw-r--r--source/blender/imbuf/intern/IMB_colormanagement_intern.h3
-rw-r--r--source/blender/imbuf/intern/IMB_filetype.h13
-rw-r--r--source/blender/imbuf/intern/colormanagement.c123
-rw-r--r--source/blender/imbuf/intern/dds/Stream.cpp14
-rw-r--r--source/blender/imbuf/intern/dds/Stream.h2
-rw-r--r--source/blender/imbuf/intern/filetype.c14
-rw-r--r--source/blender/imbuf/intern/indexer.c6
-rw-r--r--source/blender/imbuf/intern/iris.c6
-rw-r--r--source/blender/imbuf/intern/openexr/CMakeLists.txt4
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp38
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_stub.cpp9
-rw-r--r--source/blender/imbuf/intern/radiance_hdr.c20
-rw-r--r--source/blender/imbuf/intern/stereoimbuf.c42
-rw-r--r--source/blender/imbuf/intern/util.c13
-rw-r--r--source/blender/imbuf/intern/webp.c129
-rw-r--r--source/blender/io/alembic/ABC_alembic.h2
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_mesh.cc1
-rw-r--r--source/blender/io/alembic/intern/abc_customdata.cc10
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.h6
-rw-r--r--source/blender/io/alembic/intern/abc_reader_object.cc2
-rw-r--r--source/blender/io/alembic/intern/abc_reader_object.h2
-rw-r--r--source/blender/io/alembic/intern/alembic_capi.cc8
-rw-r--r--source/blender/io/avi/intern/avi_mjpeg.c10
-rw-r--r--source/blender/io/collada/GeometryExporter.cpp2
-rw-r--r--source/blender/io/collada/ImageExporter.cpp3
-rw-r--r--source/blender/io/collada/collada_utils.cpp1
-rw-r--r--source/blender/io/gpencil/gpencil_io.h4
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_base.cc6
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_base.hh6
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_capi.cc12
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc16
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh2
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_svg.cc16
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_svg.hh2
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_import_svg.cc6
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_import_svg.hh2
-rw-r--r--source/blender/io/usd/intern/usd_capi_import.cc2
-rw-r--r--source/blender/io/usd/intern/usd_reader_geom.h2
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc2
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.h2
-rw-r--r--source/blender/io/usd/intern/usd_reader_volume.cc12
-rw-r--r--source/blender/io/usd/intern/usd_writer_material.cc5
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc146
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh19
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc50
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh26
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_exporter.cc3
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc34
-rw-r--r--source/blender/makesdna/DNA_brush_enums.h9
-rw-r--r--source/blender/makesdna/DNA_brush_types.h9
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h2
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_defaults.h9
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h41
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h2
-rw-r--r--source/blender/makesdna/DNA_layer_types.h2
-rw-r--r--source/blender/makesdna/DNA_node_types.h250
-rw-r--r--source/blender/makesdna/DNA_particle_defaults.h4
-rw-r--r--source/blender/makesdna/DNA_particle_types.h2
-rw-r--r--source/blender/makesdna/DNA_pointcache_types.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h26
-rw-r--r--source/blender/makesdna/DNA_space_types.h11
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h5
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt2
-rw-r--r--source/blender/makesdna/intern/dna_defaults.c2
-rw-r--r--source/blender/makesdna/intern/dna_rename_defs.h3
-rw-r--r--source/blender/makesrna/RNA_types.h2
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt4
-rw-r--r--source/blender/makesrna/intern/rna_ID.c6
-rw-r--r--source/blender/makesrna/intern/rna_access.c2
-rw-r--r--source/blender/makesrna/intern/rna_brush.c23
-rw-r--r--source/blender/makesrna/intern/rna_color.c17
-rw-r--r--source/blender/makesrna/intern/rna_curve_api.c5
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c6
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c146
-rw-r--r--source/blender/makesrna/intern/rna_image.c7
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c22
-rw-r--r--source/blender/makesrna/intern/rna_internal.h8
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c8
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c1096
-rw-r--r--source/blender/makesrna/intern/rna_particle.c8
-rw-r--r--source/blender/makesrna/intern/rna_scene.c69
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c17
-rw-r--r--source/blender/makesrna/intern/rna_shader_fx.c1
-rw-r--r--source/blender/makesrna/intern/rna_space.c7
-rw-r--r--source/blender/makesrna/intern/rna_text.c8
-rw-r--r--source/blender/makesrna/intern/rna_texture.c16
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c89
-rw-r--r--source/blender/modifiers/CMakeLists.txt2
-rw-r--r--source/blender/modifiers/intern/MOD_array.c12
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c1
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.cc1
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c5
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c1
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.cc (renamed from source/blender/modifiers/intern/MOD_meshsequencecache.c)95
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc22
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc19
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.hh5
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c10
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c18
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c1
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c1
-rw-r--r--source/blender/nodes/NOD_composite.h2
-rw-r--r--source/blender/nodes/NOD_function.h2
-rw-r--r--source/blender/nodes/NOD_geometry.h41
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh9
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh11
-rw-r--r--source/blender/nodes/NOD_static_types.h44
-rw-r--r--source/blender/nodes/composite/CMakeLists.txt2
-rw-r--r--source/blender/nodes/composite/node_composite_tree.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_output_file.cc35
-rw-r--r--source/blender/nodes/function/CMakeLists.txt2
-rw-r--r--source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc74
-rw-r--r--source/blender/nodes/function/nodes/node_fn_rotate_euler.cc15
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt45
-rw-r--r--source/blender/nodes/geometry/node_geometry_exec.cc8
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc23
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh37
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc228
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc267
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc123
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc137
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc345
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc179
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc208
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc151
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc422
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc308
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc245
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc237
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc333
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_remove.cc61
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc124
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc157
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc515
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc559
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc335
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc207
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc60
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc126
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc131
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc294
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc384
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc351
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc726
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc77
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc83
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc64
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc657
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc268
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc223
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc126
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc165
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc97
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc266
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc313
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc80
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc132
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc162
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc46
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc55
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc41
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc37
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc42
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc23
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc19
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc32
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc957
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_normal.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_id.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc9
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc8
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc1
-rw-r--r--source/blender/nodes/intern/node_socket.cc48
-rw-r--r--source/blender/nodes/shader/CMakeLists.txt1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.cc6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_color_ramp.cc27
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.cc77
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.cc203
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.cc52
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc35
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc33
-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.cc7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.cc3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_sky.cc21
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.cc3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_value.cc4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_math.cc73
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc39
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c23
-rw-r--r--source/blender/python/generic/blf_py_api.c24
-rw-r--r--source/blender/python/gpu/gpu_py_state.c2
-rw-r--r--source/blender/python/intern/CMakeLists.txt4
-rw-r--r--source/blender/python/intern/bpy_props.c25
-rw-r--r--source/blender/render/RE_engine.h5
-rw-r--r--source/blender/render/RE_pipeline.h57
-rw-r--r--source/blender/render/RE_texture_margin.h2
-rw-r--r--source/blender/render/intern/engine.c5
-rw-r--r--source/blender/render/intern/multires_bake.c28
-rw-r--r--source/blender/render/intern/pipeline.c253
-rw-r--r--source/blender/render/intern/render_result.c292
-rw-r--r--source/blender/render/intern/render_result.h1
-rw-r--r--source/blender/render/intern/render_types.h2
-rw-r--r--source/blender/render/intern/texture_margin.cc4
-rw-r--r--source/blender/sequencer/intern/disk_cache.c7
-rw-r--r--source/blender/sequencer/intern/effects.c4
-rw-r--r--source/blender/sequencer/intern/render.c2
-rw-r--r--source/blender/sequencer/intern/strip_transform.c2
-rw-r--r--source/blender/windowmanager/WM_types.h19
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c5
-rw-r--r--source/blender/windowmanager/intern/wm_event_query.c66
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c46
-rw-r--r--source/blender/windowmanager/intern/wm_files.c16
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c10
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c8
-rw-r--r--source/blender/windowmanager/intern/wm_operator_utils.c12
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c3
-rw-r--r--source/blender/windowmanager/intern/wm_window.c2
-rw-r--r--source/blender/windowmanager/message_bus/wm_message_bus.h10
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c2
-rw-r--r--source/creator/creator.c3
-rw-r--r--source/creator/creator_args.c40
876 files changed, 24785 insertions, 22394 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e8746d3a3f4..c7b1558fe2d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -284,6 +284,7 @@ option(WITH_IMAGE_TIFF "Enable LibTIFF Support" ON)
option(WITH_IMAGE_DDS "Enable DDS Image Support" ON)
option(WITH_IMAGE_CINEON "Enable CINEON and DPX Image Support" ON)
option(WITH_IMAGE_HDR "Enable HDR Image Support" ON)
+option(WITH_IMAGE_WEBP "Enable WebP Image Support" OFF)
# Audio/Video format support
option(WITH_CODEC_AVI "Enable Blenders own AVI file support (raw/jpeg)" ON)
@@ -408,6 +409,8 @@ option(WITH_CYCLES_DEBUG "Build Cycles with options useful for debug
option(WITH_CYCLES_STANDALONE "Build Cycles standalone application" OFF)
option(WITH_CYCLES_STANDALONE_GUI "Build Cycles standalone with GUI" OFF)
+option(WITH_CYCLES_HYDRA_RENDER_DELEGATE "Build Cycles Hydra render delegate" OFF)
+
option(WITH_CYCLES_DEBUG_NAN "Build Cycles with additional asserts for detecting NaNs and invalid values" OFF)
option(WITH_CYCLES_NATIVE_ONLY "Build Cycles with native kernel only (which fits current CPU, use for development only)" OFF)
option(WITH_CYCLES_KERNEL_ASAN "Build Cycles kernels with address sanitizer when WITH_COMPILER_ASAN is on, even if it's very slow" OFF)
@@ -443,7 +446,7 @@ if(NOT APPLE)
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")
+ set(CYCLES_HIP_BINARIES_ARCH gfx900 gfx906 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()
@@ -531,6 +534,19 @@ mark_as_advanced(
WITH_GPU_SHADER_BUILDER
)
+# Metal
+
+if (APPLE)
+ option(WITH_METAL_BACKEND "Use Metal for graphics instead of (or as well as) OpenGL on macOS." OFF)
+ mark_as_advanced(WITH_METAL_BACKEND)
+else()
+ set(WITH_METAL_BACKEND OFF)
+endif()
+
+if (WITH_METAL_BACKEND)
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version" FORCE)
+endif()
+
if(WIN32)
option(WITH_GL_ANGLE "Link with the ANGLE library, an OpenGL ES 2.0 implementation based on Direct3D, instead of the system OpenGL library." OFF)
mark_as_advanced(WITH_GL_ANGLE)
@@ -729,9 +745,10 @@ endif()
#-----------------------------------------------------------------------------
# Check for conflicting/unsupported configurations
-if(NOT WITH_BLENDER AND NOT WITH_CYCLES_STANDALONE)
+if(NOT WITH_BLENDER AND NOT WITH_CYCLES_STANDALONE AND NOT WITH_CYCLES_HYDRA_RENDER_DELEGATE)
message(FATAL_ERROR
"At least one of WITH_BLENDER or WITH_CYCLES_STANDALONE "
+ "or WITH_CYCLES_HYDRA_RENDER_DELEGATE "
"must be enabled, nothing to do!"
)
endif()
@@ -1275,6 +1292,16 @@ else()
endif()
#-----------------------------------------------------------------------------
+# Configure Metal.
+if (WITH_METAL_BACKEND)
+ add_definitions(-DWITH_METAL_BACKEND)
+
+ # No need to add frameworks here, all the ones we need for Metal and
+ # Metal-OpenGL Interop are already being added by
+ # build_files/cmake/platform/platform_apple.cmake
+endif()
+
+#-----------------------------------------------------------------------------
# Configure OpenMP.
if(WITH_OPENMP)
if(NOT OPENMP_CUSTOM)
@@ -1668,6 +1695,8 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
ADD_CHECK_C_COMPILER_FLAG(C_REMOVE_STRICT_FLAGS C_WARN_NO_DUPLICATE_ENUM -Wno-duplicate-enum)
ADD_CHECK_C_COMPILER_FLAG(C_REMOVE_STRICT_FLAGS C_WARN_NO_UNDEF -Wno-undef)
ADD_CHECK_C_COMPILER_FLAG(C_REMOVE_STRICT_FLAGS C_WARN_NO_MISSING_NORETURN -Wno-missing-noreturn)
+ ADD_CHECK_C_COMPILER_FLAG(C_REMOVE_STRICT_FLAGS C_WARN_NO_UNUSED_BUT_SET_VARIABLE -Wno-unused-but-set-variable)
+ ADD_CHECK_C_COMPILER_FLAG(C_REMOVE_STRICT_FLAGS C_WARN_NO_DEPRECATED_DECLARATIONS -Wno-deprecated-declarations)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_REMOVE_STRICT_FLAGS CXX_WARN_NO_UNUSED_PARAMETER -Wno-unused-parameter)
ADD_CHECK_CXX_COMPILER_FLAG(CXX_REMOVE_STRICT_FLAGS CXX_WARN_NO_UNUSED_PRIVATE_FIELD -Wno-unused-private-field)
@@ -1882,14 +1911,13 @@ if(WITH_BLENDER)
# source after intern and extern to gather all
# internal and external library information first, for test linking
add_subdirectory(source)
-elseif(WITH_CYCLES_STANDALONE)
+elseif(WITH_CYCLES_STANDALONE OR WITH_CYCLES_HYDRA_RENDER_DELEGATE)
add_subdirectory(intern/glew-mx)
add_subdirectory(intern/guardedalloc)
add_subdirectory(intern/libc_compat)
add_subdirectory(intern/sky)
add_subdirectory(intern/cycles)
- add_subdirectory(extern/clew)
if(WITH_CYCLES_LOGGING)
if(NOT WITH_SYSTEM_GFLAGS)
add_subdirectory(extern/gflags)
diff --git a/build_files/build_environment/cmake/download.cmake b/build_files/build_environment/cmake/download.cmake
index b92073636f5..5ca46c15d8d 100644
--- a/build_files/build_environment/cmake/download.cmake
+++ b/build_files/build_environment/cmake/download.cmake
@@ -1,11 +1,16 @@
# SPDX-License-Identifier: GPL-2.0-or-later
+## Update and uncomment this in the release branch
+# set(BLENDER_VERSION 3.1)
+
function(download_source dep)
set(TARGET_FILE ${${dep}_FILE})
set(TARGET_HASH_TYPE ${${dep}_HASH_TYPE})
set(TARGET_HASH ${${dep}_HASH})
if(PACKAGE_USE_UPSTREAM_SOURCES)
set(TARGET_URI ${${dep}_URI})
+ elseif(BLENDER_VERSION)
+ set(TARGET_URI https://svn.blender.org/svnroot/bf-blender/tags/blender-${BLENDER_VERSION}-release/lib/packages/${TARGET_FILE})
else()
set(TARGET_URI https://svn.blender.org/svnroot/bf-blender/trunk/lib/packages/${TARGET_FILE})
endif()
diff --git a/build_files/build_environment/cmake/usd.cmake b/build_files/build_environment/cmake/usd.cmake
index 26b728b5801..afa9f788b07 100644
--- a/build_files/build_environment/cmake/usd.cmake
+++ b/build_files/build_environment/cmake/usd.cmake
@@ -52,6 +52,14 @@ add_dependencies(
external_boost
)
+# Since USD 21.11 the libraries are prefixed with "usd_", i.e. "libusd_m.a" became "libusd_usd_m.a".
+# See https://github.com/PixarAnimationStudios/USD/blob/release/CHANGELOG.md#2111---2021-11-01
+if (USD_VERSION VERSION_LESS 21.11)
+ set(PXR_LIB_PREFIX "")
+else()
+ set(PXR_LIB_PREFIX "usd_")
+endif()
+
if(WIN32)
# USD currently demands python be available at build time
# and then proceeds not to use it, but still checks that the
@@ -65,14 +73,14 @@ if(WIN32)
if(BUILD_MODE STREQUAL Release)
ExternalProject_Add_Step(external_usd after_install
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/usd/ ${HARVEST_TARGET}/usd
- COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/usd/src/external_usd-build/pxr/Release/usd_m.lib ${HARVEST_TARGET}/usd/lib/libusd_m.lib
+ COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/usd/src/external_usd-build/pxr/Release/${PXR_LIB_PREFIX}usd_m.lib ${HARVEST_TARGET}/usd/lib/lib${PXR_LIB_PREFIX}usd_m.lib
DEPENDEES install
)
endif()
if(BUILD_MODE STREQUAL Debug)
ExternalProject_Add_Step(external_usd after_install
COMMAND ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/usd/lib ${HARVEST_TARGET}/usd/lib
- COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/usd/src/external_usd-build/pxr/Debug/usd_m_d.lib ${HARVEST_TARGET}/usd/lib/libusd_m_d.lib
+ COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/usd/src/external_usd-build/pxr/Debug/${PXR_LIB_PREFIX}usd_m_d.lib ${HARVEST_TARGET}/usd/lib/lib${PXR_LIB_PREFIX}usd_m_d.lib
DEPENDEES install
)
endif()
@@ -84,7 +92,7 @@ else()
# case (only the shared library). As a result, we need to grab the `libusd_m.a`
# file from the build directory instead of from the install directory.
ExternalProject_Add_Step(external_usd after_install
- COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/usd/src/external_usd-build/pxr/libusd_m.a ${HARVEST_TARGET}/usd/lib/libusd_m.a
+ COMMAND ${CMAKE_COMMAND} -E copy ${BUILD_DIR}/usd/src/external_usd-build/pxr/lib${PXR_LIB_PREFIX}usd_m.a ${HARVEST_TARGET}/usd/lib/lib${PXR_LIB_PREFIX}usd_m.a
DEPENDEES install
)
endif()
diff --git a/build_files/cmake/Modules/FindUSD.cmake b/build_files/cmake/Modules/FindUSD.cmake
index 840fa2d538f..d8f2ee22e6e 100644
--- a/build_files/cmake/Modules/FindUSD.cmake
+++ b/build_files/cmake/Modules/FindUSD.cmake
@@ -32,9 +32,12 @@ FIND_PATH(USD_INCLUDE_DIR
DOC "Universal Scene Description (USD) header files"
)
+# Since USD 21.11 the libraries are prefixed with "usd_", i.e. "libusd_m.a" became "libusd_usd_m.a".
+# See https://github.com/PixarAnimationStudios/USD/blob/release/CHANGELOG.md#2111---2021-11-01
FIND_LIBRARY(USD_LIBRARY
NAMES
- usd_m usd_ms
+ usd_usd_m usd_usd_ms usd_m usd_ms
+ ${PXR_LIB_PREFIX}usd
NAMES_PER_DIR
HINTS
${_usd_SEARCH_DIRS}
diff --git a/build_files/cmake/Modules/FindWebP.cmake b/build_files/cmake/Modules/FindWebP.cmake
new file mode 100644
index 00000000000..741c48ec447
--- /dev/null
+++ b/build_files/cmake/Modules/FindWebP.cmake
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2022 Blender Foundation.
+
+# - Find WebP library
+# Find the native WebP includes and library
+# This module defines
+# WEBP_INCLUDE_DIRS, where to find WebP headers, Set when WebP is found.
+# WEBP_LIBRARIES, libraries to link against to use WebP.
+# WEBP_ROOT_DIR, The base directory to search for WebP.
+# This can also be an environment variable.
+# WEBP_FOUND, If false, do not try to use WebP.
+#
+# also defined, but not for general use are
+# WEBP_LIBRARY, where to find the WEBP library.
+
+# If WEBP_ROOT_DIR was defined in the environment, use it.
+IF(NOT WEBP_ROOT_DIR AND NOT $ENV{WEBP_ROOT_DIR} STREQUAL "")
+ SET(WEBP_ROOT_DIR $ENV{WEBP_ROOT_DIR})
+ENDIF()
+
+SET(_webp_SEARCH_DIRS
+ ${WEBP_ROOT_DIR}
+ /opt/lib/webp
+)
+
+FIND_PATH(WEBP_INCLUDE_DIR
+ NAMES
+ webp/types.h
+ HINTS
+ ${_webp_SEARCH_DIRS}
+ PATH_SUFFIXES
+ include
+)
+
+SET(_webp_FIND_COMPONENTS
+ webp
+ webpmux
+ webpdemux
+)
+
+SET(_webp_LIBRARIES)
+FOREACH(COMPONENT ${_webp_FIND_COMPONENTS})
+ STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
+
+ FIND_LIBRARY(WEBP_${UPPERCOMPONENT}_LIBRARY
+ NAMES
+ ${COMPONENT}
+ NAMES_PER_DIR
+ HINTS
+ ${_webp_SEARCH_DIRS}
+ PATH_SUFFIXES
+ lib64 lib lib/static
+ )
+ LIST(APPEND _webp_LIBRARIES "${WEBP_${UPPERCOMPONENT}_LIBRARY}")
+ENDFOREACH()
+
+IF(${WEBP_WEBP_LIBRARY_NOTFOUND})
+ set(WEBP_FOUND FALSE)
+ELSE()
+ # handle the QUIETLY and REQUIRED arguments and set WEBP_FOUND to TRUE if
+ # all listed variables are TRUE
+ INCLUDE(FindPackageHandleStandardArgs)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(WebP DEFAULT_MSG _webp_LIBRARIES WEBP_INCLUDE_DIR)
+
+ IF(WEBP_FOUND)
+ get_filename_component(WEBP_LIBRARY_DIR ${WEBP_WEBP_LIBRARY} DIRECTORY)
+ SET(WEBP_INCLUDE_DIRS ${WEBP_INCLUDE_DIR})
+ SET(WEBP_LIBRARIES ${_webp_LIBRARIES})
+ ELSE()
+ SET(WEBPL_PUGIXML_FOUND FALSE)
+ ENDIF()
+ENDIF()
+
+MARK_AS_ADVANCED(
+ WEBP_INCLUDE_DIR
+ WEBP_LIBRARY_DIR
+)
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index bf3e56922c9..5508e8f2104 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -879,7 +879,7 @@ function(delayed_install
destination)
foreach(f ${files})
- if(IS_ABSOLUTE ${f})
+ if(IS_ABSOLUTE ${f} OR "${base}" STREQUAL "")
set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_FILES ${f})
else()
set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_FILES ${base}/${f})
diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake
index b09f2f8917b..43ce23081af 100644
--- a/build_files/cmake/platform/platform_apple.cmake
+++ b/build_files/cmake/platform/platform_apple.cmake
@@ -232,6 +232,15 @@ if(WITH_IMAGE_TIFF)
endif()
endif()
+if(WITH_IMAGE_WEBP)
+ set(WEBP_ROOT_DIR ${LIBDIR}/webp)
+ find_package(WebP)
+ if(NOT WEBP_FOUND)
+ message(WARNING "WebP not found, disabling WITH_IMAGE_WEBP")
+ set(WITH_IMAGE_WEBP OFF)
+ endif()
+endif()
+
if(WITH_BOOST)
set(Boost_NO_BOOST_CMAKE ON)
set(BOOST_ROOT ${LIBDIR}/boost)
diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake
index 0a7119802c8..cc168476d5d 100644
--- a/build_files/cmake/platform/platform_unix.cmake
+++ b/build_files/cmake/platform/platform_unix.cmake
@@ -368,6 +368,14 @@ if(WITH_PUGIXML)
endif()
endif()
+if(WITH_IMAGE_WEBP)
+ set(WEBP_ROOT_DIR ${LIBDIR}/webp)
+ find_package_wrapper(WebP)
+ if(NOT WEBP_FOUND)
+ set(WITH_IMAGE_WEBP OFF)
+ endif()
+endif()
+
if(WITH_OPENIMAGEIO)
find_package_wrapper(OpenImageIO)
set(OPENIMAGEIO_LIBRARIES
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake
index e2e49ca0bcd..9418f74994b 100644
--- a/build_files/cmake/platform/platform_win32.cmake
+++ b/build_files/cmake/platform/platform_win32.cmake
@@ -39,12 +39,12 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
set(WITH_WINDOWS_STRIPPED_PDB OFF)
endif()
else()
- if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.28.29921) # MSVC 2019 16.9.16
+ if(WITH_BLENDER AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.28.29921) # MSVC 2019 16.9.16
message(FATAL_ERROR "Compiler is unsupported, MSVC 2019 16.9.16 or newer is required for building blender.")
endif()
endif()
-if(NOT WITH_PYTHON_MODULE)
+if(WITH_BLENDER AND NOT WITH_PYTHON_MODULE)
set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT blender)
endif()
@@ -238,7 +238,6 @@ else()
endif()
if(NOT DEFINED LIBDIR)
-
# Setup 64bit and 64bit windows systems
if(CMAKE_CL_64)
message(STATUS "64 bit compiler detected.")
@@ -252,6 +251,9 @@ if(NOT DEFINED LIBDIR)
elseif(MSVC_VERSION GREATER 1919)
message(STATUS "Visual Studio 2019 detected.")
set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc15)
+ elseif(MSVC_VERSION GREATER 1909)
+ message(STATUS "Visual Studio 2017 detected.")
+ set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc15)
endif()
else()
message(STATUS "Using pre-compiled LIBDIR: ${LIBDIR}")
@@ -300,9 +302,8 @@ set(ZLIB_INCLUDE_DIR ${LIBDIR}/zlib/include)
set(ZLIB_LIBRARY ${LIBDIR}/zlib/lib/libz_st.lib)
set(ZLIB_DIR ${LIBDIR}/zlib)
-windows_find_package(zlib) # we want to find before finding things that depend on it like png
-windows_find_package(png)
-
+windows_find_package(ZLIB) # we want to find before finding things that depend on it like png
+windows_find_package(PNG)
if(NOT PNG_FOUND)
warn_hardcoded_paths(libpng)
set(PNG_PNG_INCLUDE_DIR ${LIBDIR}/png/include)
@@ -313,9 +314,9 @@ if(NOT PNG_FOUND)
endif()
set(JPEG_NAMES ${JPEG_NAMES} libjpeg)
-windows_find_package(jpeg REQUIRED)
+windows_find_package(JPEG REQUIRED)
if(NOT JPEG_FOUND)
- warn_hardcoded_paths(jpeg)
+ warn_hardcoded_paths(libjpeg)
set(JPEG_INCLUDE_DIR ${LIBDIR}/jpeg/include)
set(JPEG_LIBRARIES ${LIBDIR}/jpeg/lib/libjpeg.lib)
endif()
@@ -333,7 +334,7 @@ set(FREETYPE_LIBRARIES
${LIBDIR}/brotli/lib/brotlidec-static.lib
${LIBDIR}/brotli/lib/brotlicommon-static.lib
)
-windows_find_package(freetype REQUIRED)
+windows_find_package(Freetype REQUIRED)
if(WITH_FFTW3)
set(FFTW3 ${LIBDIR}/fftw3)
@@ -342,6 +343,14 @@ if(WITH_FFTW3)
set(FFTW3_LIBPATH ${FFTW3}/lib)
endif()
+windows_find_package(WebP)
+if(NOT WEBP_FOUND)
+ set(WEBP_INCLUDE_DIRS ${LIBDIR}/webp/include)
+ set(WEBP_ROOT_DIR ${LIBDIR}/webp)
+ set(WEBP_LIBRARIES ${LIBDIR}/webp/lib/webp.lib ${LIBDIR}/webp/lib/webpdemux.lib ${LIBDIR}/webp/lib/webpmux.lib)
+ set(WEBP_FOUND ON)
+endif()
+
if(WITH_OPENCOLLADA)
set(OPENCOLLADA ${LIBDIR}/opencollada)
@@ -389,9 +398,9 @@ if(WITH_CODEC_FFMPEG)
${LIBDIR}/ffmpeg/include
${LIBDIR}/ffmpeg/include/msvc
)
- windows_find_package(FFMPEG)
+ windows_find_package(FFmpeg)
if(NOT FFMPEG_FOUND)
- warn_hardcoded_paths(ffmpeg)
+ warn_hardcoded_paths(FFmpeg)
set(FFMPEG_LIBRARIES
${LIBDIR}/ffmpeg/lib/avcodec.lib
${LIBDIR}/ffmpeg/lib/avformat.lib
@@ -403,10 +412,10 @@ if(WITH_CODEC_FFMPEG)
endif()
if(WITH_IMAGE_OPENEXR)
- set(OPENEXR_ROOT_DIR ${LIBDIR}/openexr)
- set(OPENEXR_VERSION "2.1")
- windows_find_package(OPENEXR REQUIRED)
+ windows_find_package(OpenEXR REQUIRED)
if(NOT OPENEXR_FOUND)
+ set(OPENEXR_ROOT_DIR ${LIBDIR}/openexr)
+ set(OPENEXR_VERSION "2.1")
warn_hardcoded_paths(OpenEXR)
set(OPENEXR ${LIBDIR}/openexr)
set(OPENEXR_INCLUDE_DIR ${OPENEXR}/include)
@@ -624,21 +633,23 @@ if(WITH_IMAGE_OPENJPEG)
endif()
if(WITH_OPENSUBDIV)
- set(OPENSUBDIV_INCLUDE_DIRS ${LIBDIR}/opensubdiv/include)
- set(OPENSUBDIV_LIBPATH ${LIBDIR}/opensubdiv/lib)
- set(OPENSUBDIV_LIBRARIES
- optimized ${OPENSUBDIV_LIBPATH}/osdCPU.lib
- optimized ${OPENSUBDIV_LIBPATH}/osdGPU.lib
- debug ${OPENSUBDIV_LIBPATH}/osdCPU_d.lib
- debug ${OPENSUBDIV_LIBPATH}/osdGPU_d.lib
- )
- set(OPENSUBDIV_HAS_OPENMP TRUE)
- set(OPENSUBDIV_HAS_TBB FALSE)
- set(OPENSUBDIV_HAS_OPENCL TRUE)
- set(OPENSUBDIV_HAS_CUDA FALSE)
- set(OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK TRUE)
- set(OPENSUBDIV_HAS_GLSL_COMPUTE TRUE)
windows_find_package(OpenSubdiv)
+ if (NOT OpenSubdiv_FOUND)
+ set(OPENSUBDIV_INCLUDE_DIRS ${LIBDIR}/opensubdiv/include)
+ set(OPENSUBDIV_LIBPATH ${LIBDIR}/opensubdiv/lib)
+ set(OPENSUBDIV_LIBRARIES
+ optimized ${OPENSUBDIV_LIBPATH}/osdCPU.lib
+ optimized ${OPENSUBDIV_LIBPATH}/osdGPU.lib
+ debug ${OPENSUBDIV_LIBPATH}/osdCPU_d.lib
+ debug ${OPENSUBDIV_LIBPATH}/osdGPU_d.lib
+ )
+ set(OPENSUBDIV_HAS_OPENMP TRUE)
+ set(OPENSUBDIV_HAS_TBB FALSE)
+ set(OPENSUBDIV_HAS_OPENCL TRUE)
+ set(OPENSUBDIV_HAS_CUDA FALSE)
+ set(OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK TRUE)
+ set(OPENSUBDIV_HAS_GLSL_COMPUTE TRUE)
+ endif()
endif()
if(WITH_SDL)
@@ -659,12 +670,15 @@ if(WITH_SYSTEM_AUDASPACE)
endif()
if(WITH_TBB)
- set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib)
- set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include)
- set(TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR})
- if(WITH_TBB_MALLOC_PROXY)
- set(TBB_MALLOC_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbbmalloc.lib debug ${LIBDIR}/tbb/lib/tbbmalloc_debug.lib)
- add_definitions(-DWITH_TBB_MALLOC)
+ windows_find_package(TBB)
+ if (NOT TBB_FOUND)
+ set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib)
+ set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include)
+ set(TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR})
+ if(WITH_TBB_MALLOC_PROXY)
+ set(TBB_MALLOC_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbbmalloc.lib debug ${LIBDIR}/tbb/lib/tbbmalloc_debug.lib)
+ add_definitions(-DWITH_TBB_MALLOC)
+ endif()
endif()
endif()
diff --git a/doc/license/LGPL2.1-license.txt b/doc/license/LGPL2.1-license.txt
new file mode 100644
index 00000000000..e5ab03e1238
--- /dev/null
+++ b/doc/license/LGPL2.1-license.txt
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/doc/license/SPDX-license-identifiers.txt b/doc/license/SPDX-license-identifiers.txt
index 41736ff8ce5..705169b1af7 100644
--- a/doc/license/SPDX-license-identifiers.txt
+++ b/doc/license/SPDX-license-identifiers.txt
@@ -5,5 +5,6 @@ BSD-2-Clause BSD-2-Clause-license.txt https://spdx.org/licenses/BS
BSD-3-Clause BSD-3-Clause-license.txt https://spdx.org/licenses/BSD-3-Clause.html
GPL-2.0-or-later GPL-license.txt https://spdx.org/licenses/GPL-2.0-or-later.html
GPL-3.0-or-later GPL3-license.txt https://spdx.org/licenses/GPL-3.0-or-later.html
+LGPL-2.1-or-later LGPL2.1-license.txt https://spdx.org/licenses/LGPL-2.1-or-later.html
MIT MIT-license.txt https://spdx.org/licenses/MIT.html
Zlib Zlib-license.txt https://spdx.org/licenses/Zlib.html
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt
index ad2b5ab4d7b..1cc3dccf426 100644
--- a/intern/cycles/CMakeLists.txt
+++ b/intern/cycles/CMakeLists.txt
@@ -2,8 +2,12 @@
# Copyright 2011-2022 Blender Foundation
# Standalone or with Blender
-if(NOT WITH_BLENDER AND WITH_CYCLES_STANDALONE)
- set(CYCLES_INSTALL_PATH ${CMAKE_INSTALL_PREFIX})
+if(NOT WITH_BLENDER)
+ if(WITH_CYCLES_STANDALONE OR NOT WITH_CYCLES_HYDRA_RENDER_DELEGATE)
+ set(CYCLES_INSTALL_PATH ${CMAKE_INSTALL_PREFIX})
+ else()
+ set(CYCLES_INSTALL_PATH ${CMAKE_INSTALL_PREFIX}/hdCycles/resources)
+ endif()
else()
set(WITH_CYCLES_BLENDER ON)
# WINDOWS_PYTHON_DEBUG needs to write into the user addons folder since it will
@@ -335,6 +339,11 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_C_COMPILER_ID MATCHES "Clang")
unset(_has_no_error_unused_macros)
endif()
+if(WITH_CYCLES_HYDRA_RENDER_DELEGATE AND NOT WITH_USD)
+ message(STATUS "USD not found, disabling WITH_CYCLES_HYDRA_RENDER_DELEGATE")
+ set(WITH_CYCLES_HYDRA_RENDER_DELEGATE OFF)
+endif()
+
if(WITH_CYCLES_CUDA_BINARIES AND (NOT WITH_CYCLES_CUBIN_COMPILER))
if(MSVC)
set(MAX_MSVC 1800)
@@ -395,6 +404,10 @@ if(WITH_GTESTS)
add_subdirectory(test)
endif()
-if(NOT WITH_BLENDER AND WITH_CYCLES_STANDALONE)
+if(WITH_CYCLES_HYDRA_RENDER_DELEGATE)
+ add_subdirectory(hydra)
+endif()
+
+if(NOT WITH_BLENDER)
delayed_do_install(${CMAKE_BINARY_DIR}/bin)
endif()
diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt
index 3248ef0dcda..484d99c5ca7 100644
--- a/intern/cycles/app/CMakeLists.txt
+++ b/intern/cycles/app/CMakeLists.txt
@@ -22,6 +22,16 @@ set(LIBRARIES
cycles_util
)
+if(WITH_ALEMBIC)
+ add_definitions(-DWITH_ALEMBIC)
+ list(APPEND INC_SYS
+ ${ALEMBIC_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ ${ALEMBIC_LIBRARIES}
+ )
+endif()
+
if(WITH_CYCLES_OSL)
list(APPEND LIBRARIES cycles_kernel_osl)
endif()
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index 50a983022a3..723f4fd77b9 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -9,6 +9,7 @@
#include "graph/node_xml.h"
+#include "scene/alembic.h"
#include "scene/background.h"
#include "scene/camera.h"
#include "scene/film.h"
@@ -192,6 +193,31 @@ static void xml_read_camera(XMLReadState &state, xml_node node)
cam->update(state.scene);
}
+/* Alembic */
+
+#ifdef WITH_ALEMBIC
+static void xml_read_alembic(XMLReadState &state, xml_node graph_node)
+{
+ AlembicProcedural *proc = state.scene->create_node<AlembicProcedural>();
+ xml_read_node(state, proc, graph_node);
+
+ for (xml_node node = graph_node.first_child(); node; node = node.next_sibling()) {
+ if (string_iequals(node.name(), "object")) {
+ string path;
+ if (xml_read_string(&path, node, "path")) {
+ ustring object_path(path, 0);
+ AlembicObject *object = static_cast<AlembicObject *>(
+ proc->get_or_create_object(object_path));
+
+ array<Node *> used_shaders = object->get_used_shaders();
+ used_shaders.push_back_slow(state.shader);
+ object->set_used_shaders(used_shaders);
+ }
+ }
+ }
+}
+#endif
+
/* Shader */
static void xml_read_shader_graph(XMLReadState &state, Shader *shader, xml_node graph_node)
@@ -647,6 +673,11 @@ static void xml_read_scene(XMLReadState &state, xml_node scene_node)
if (xml_read_string(&src, node, "src"))
xml_read_include(state, src);
}
+#ifdef WITH_ALEMBIC
+ else if (string_iequals(node.name(), "alembic")) {
+ xml_read_alembic(state, node);
+ }
+#endif
else
fprintf(stderr, "Unknown node \"%s\".\n", node.name());
}
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index 5578e83b19a..74b28b8ea21 100644
--- a/intern/cycles/blender/addon/__init__.py
+++ b/intern/cycles/blender/addon/__init__.py
@@ -83,6 +83,17 @@ class CyclesRender(bpy.types.RenderEngine):
# viewport render
def view_update(self, context, depsgraph):
if not self.session:
+ # When starting a new render session in viewport (by switching
+ # viewport to Rendered shading) unpause the render. The way to think
+ # of it is: artist requests render, so we start to render.
+ # Do it for both original and evaluated scene so that Cycles
+ # immediately reacts to un-paused render.
+ cscene = context.scene.cycles
+ cscene_eval = depsgraph.scene_eval.cycles
+ if cscene.preview_pause or cscene_eval.preview_pause:
+ cscene.preview_pause = False
+ cscene_eval.preview_pause = False
+
engine.create(self, context.blend_data,
context.region, context.space_data, context.region_data)
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 8896f620b9f..24cc5735c96 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -348,8 +348,8 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
scrambling_distance: FloatProperty(
name="Scrambling Distance",
default=1.0,
- min=0.0, max=1.0,
- 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",
+ min=0.0, soft_max=1.0,
+ description="Reduce randomization between pixels to improve GPU rendering performance, at the cost of possible rendering artifacts if set too low",
)
preview_scrambling_distance: BoolProperty(
name="Scrambling Distance viewport",
@@ -360,7 +360,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
auto_scrambling_distance: BoolProperty(
name="Automatic Scrambling Distance",
default=False,
- 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",
+ description="Automatically reduce the randomization between pixels to improve GPU rendering performance, at the cost of possible rendering artifacts",
)
use_layer_samples: EnumProperty(
@@ -1480,7 +1480,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
col.label(text="and NVIDIA driver version 470 or newer", icon='BLANK1')
elif device_type == 'HIP':
import sys
- col.label(text="Requires discrete AMD GPU with RDNA architecture", icon='BLANK1')
+ col.label(text="Requires discrete AMD GPU with Vega 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':
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 2b74a1b7ccf..1f50f3da7ae 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -289,11 +289,8 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel):
layout.separator()
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, "preview_scrambling_distance", text="Viewport")
heading.prop(cscene, "scrambling_distance", text="Multiplier")
layout.separator()
@@ -1031,7 +1028,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', 'HAIR', 'POINTCLOUD'}:
+ if ob.type in {'MESH', 'CURVE', 'CURVE', 'SURFACE', 'FONT', 'META', 'CAMERA', 'CURVES', 'POINTCLOUD'}:
return True
if ob.instance_type == 'COLLECTION' and ob.instance_collection:
return True
@@ -1070,7 +1067,7 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
def has_geometry_visibility(ob):
- return ob and ((ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LIGHT', 'VOLUME', 'POINTCLOUD', 'HAIR'}) or
+ return ob and ((ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LIGHT', 'VOLUME', 'POINTCLOUD', 'CURVES'}) or
(ob.instance_type == 'COLLECTION' and ob.instance_collection))
diff --git a/intern/cycles/blender/object.cpp b/intern/cycles/blender/object.cpp
index 054142a9ca4..3a95746d149 100644
--- a/intern/cycles/blender/object.cpp
+++ b/intern/cycles/blender/object.cpp
@@ -422,7 +422,7 @@ static float4 lookup_instance_property(BL::DepsgraphObjectInstance &b_instance,
return value;
}
- return make_float4(0.0f);
+ return zero_float4();
}
bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object)
diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp
index ec50ad9db9a..224cbea85f3 100644
--- a/intern/cycles/blender/shader.cpp
+++ b/intern/cycles/blender/shader.cpp
@@ -271,6 +271,7 @@ static ShaderNode *add_node(Scene *scene,
curves->set_min_x(min_x);
curves->set_max_x(max_x);
curves->set_curves(curve_mapping_curves);
+ curves->set_extrapolate(mapping.extend() == mapping.extend_EXTRAPOLATED);
node = curves;
}
if (b_node.is_a(&RNA_ShaderNodeVectorCurve)) {
@@ -284,6 +285,7 @@ static ShaderNode *add_node(Scene *scene,
curves->set_min_x(min_x);
curves->set_max_x(max_x);
curves->set_curves(curve_mapping_curves);
+ curves->set_extrapolate(mapping.extend() == mapping.extend_EXTRAPOLATED);
node = curves;
}
else if (b_node.is_a(&RNA_ShaderNodeFloatCurve)) {
@@ -297,6 +299,7 @@ static ShaderNode *add_node(Scene *scene,
curve->set_min_x(min_x);
curve->set_max_x(max_x);
curve->set_curve(curve_mapping_curve);
+ curve->set_extrapolate(mapping.extend() == mapping.extend_EXTRAPOLATED);
node = curve;
}
else if (b_node.is_a(&RNA_ShaderNodeValToRGB)) {
diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp
index d4949a5ff30..8af2ee7a435 100644
--- a/intern/cycles/blender/sync.cpp
+++ b/intern/cycles/blender/sync.cpp
@@ -346,31 +346,48 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background)
cscene, "sampling_pattern", SAMPLING_NUM_PATTERNS, SAMPLING_PATTERN_SOBOL);
integrator->set_sampling_pattern(sampling_pattern);
+ int samples = 1;
bool use_adaptive_sampling = false;
if (preview) {
+ samples = get_int(cscene, "preview_samples");
use_adaptive_sampling = RNA_boolean_get(&cscene, "use_preview_adaptive_sampling");
integrator->set_use_adaptive_sampling(use_adaptive_sampling);
integrator->set_adaptive_threshold(get_float(cscene, "preview_adaptive_threshold"));
integrator->set_adaptive_min_samples(get_int(cscene, "preview_adaptive_min_samples"));
}
else {
+ samples = get_int(cscene, "samples");
use_adaptive_sampling = RNA_boolean_get(&cscene, "use_adaptive_sampling");
integrator->set_use_adaptive_sampling(use_adaptive_sampling);
integrator->set_adaptive_threshold(get_float(cscene, "adaptive_threshold"));
integrator->set_adaptive_min_samples(get_int(cscene, "adaptive_min_samples"));
}
- int samples = get_int(cscene, "samples");
float scrambling_distance = get_float(cscene, "scrambling_distance");
bool auto_scrambling_distance = get_boolean(cscene, "auto_scrambling_distance");
if (auto_scrambling_distance) {
+ if (samples == 0) {
+ /* If samples is 0, then viewport rendering is set to render infinitely. In that case we
+ * override the samples value with 4096 so the Automatic Scrambling Distance algorithm
+ * picks a Scrambling Distance value with a good balance of performance and correlation
+ * artifacts when rendering to high sample counts. */
+ samples = 4096;
+ }
+
+ if (use_adaptive_sampling) {
+ /* If Adaptive Sampling is enabled, use "min_samples" in the Automatic Scrambling Distance
+ * algorithm to avoid artifacts common with Adaptive Sampling + Scrambling Distance. */
+ const AdaptiveSampling adaptive_sampling = integrator->get_adaptive_sampling();
+ samples = min(samples, adaptive_sampling.min_samples);
+ }
scrambling_distance *= 4.0f / sqrtf(samples);
}
- /* only use scrambling distance in the viewport if user wants to and disable with AS */
+ /* Only use scrambling distance in the viewport if user wants to. */
bool preview_scrambling_distance = get_boolean(cscene, "preview_scrambling_distance");
- if ((preview && !preview_scrambling_distance) || use_adaptive_sampling)
+ if (preview && !preview_scrambling_distance) {
scrambling_distance = 1.0f;
+ }
if (scrambling_distance != 1.0f) {
VLOG(3) << "Using scrambling distance: " << scrambling_distance;
diff --git a/intern/cycles/bvh/binning.cpp b/intern/cycles/bvh/binning.cpp
index b04fc069c54..5ac7f9c782a 100644
--- a/intern/cycles/bvh/binning.cpp
+++ b/intern/cycles/bvh/binning.cpp
@@ -203,7 +203,7 @@ BVHObjectBinning::BVHObjectBinning(const BVHRange &job,
bestSAH = min(sah, bestSAH);
}
- int4 mask = float3_to_float4(cent_bounds_.size()) <= make_float4(0.0f);
+ int4 mask = float3_to_float4(cent_bounds_.size()) <= zero_float4();
bestSAH = insert<3>(select(mask, make_float4(FLT_MAX), bestSAH), FLT_MAX);
/* find best dimension */
diff --git a/intern/cycles/cmake/macros.cmake b/intern/cycles/cmake/macros.cmake
index 0f2e1b50434..e69e31f8e52 100644
--- a/intern/cycles/cmake/macros.cmake
+++ b/intern/cycles/cmake/macros.cmake
@@ -101,6 +101,7 @@ macro(cycles_target_link_libraries target)
${PNG_LIBRARIES}
${JPEG_LIBRARIES}
${TIFF_LIBRARY}
+ ${WEBP_LIBRARIES}
${OPENJPEG_LIBRARIES}
${OPENEXR_LIBRARIES}
${OPENEXR_LIBRARIES} # For circular dependencies between libs.
diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt
index 670285fb310..d4e128093fa 100644
--- a/intern/cycles/device/CMakeLists.txt
+++ b/intern/cycles/device/CMakeLists.txt
@@ -197,7 +197,8 @@ 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("hip" FILES ${SRC_HIP})
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})
+source_group("common" FILES ${SRC_BASE} ${SRC_HEADERS})
diff --git a/intern/cycles/device/hip/util.h b/intern/cycles/device/hip/util.h
index adb68a2d44c..4e4906171d1 100644
--- a/intern/cycles/device/hip/util.h
+++ b/intern/cycles/device/hip/util.h
@@ -51,7 +51,7 @@ static inline bool hipSupportsDevice(const int hipDevId)
hipDeviceGetAttribute(&major, hipDeviceAttributeComputeCapabilityMajor, hipDevId);
hipDeviceGetAttribute(&minor, hipDeviceAttributeComputeCapabilityMinor, hipDevId);
- return (major > 10) || (major == 10 && minor >= 1);
+ return (major >= 9);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/hydra/CMakeLists.txt b/intern/cycles/hydra/CMakeLists.txt
new file mode 100644
index 00000000000..703bd955135
--- /dev/null
+++ b/intern/cycles/hydra/CMakeLists.txt
@@ -0,0 +1,174 @@
+# SPDX-License-Identifier: Apache-2.0
+# Copyright 2022 Blender Foundation
+
+#####################################################################
+# Cycles Hydra render delegate
+#####################################################################
+
+set(INC
+ ..
+)
+set(INC_SYS
+ ${USD_INCLUDE_DIRS}
+ ${GLEW_INCLUDE_DIR}
+)
+
+set(INC_HD_CYCLES
+ attribute.h
+ camera.h
+ config.h
+ curves.h
+ display_driver.h
+ field.h
+ geometry.h
+ geometry.inl
+ instancer.h
+ light.h
+ material.h
+ mesh.h
+ node_util.h
+ output_driver.h
+ pointcloud.h
+ render_buffer.h
+ render_delegate.h
+ render_pass.h
+ session.h
+ volume.h
+)
+
+set(SRC_HD_CYCLES
+ attribute.cpp
+ curves.cpp
+ camera.cpp
+ display_driver.cpp
+ field.cpp
+ instancer.cpp
+ light.cpp
+ material.cpp
+ mesh.cpp
+ node_util.cpp
+ output_driver.cpp
+ pointcloud.cpp
+ render_buffer.cpp
+ render_delegate.cpp
+ render_pass.cpp
+ session.cpp
+ volume.cpp
+)
+
+add_definitions(${GL_DEFINITIONS})
+
+if(WITH_OPENVDB)
+ add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
+ list(APPEND INC_SYS
+ ${OPENVDB_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ ${OPENVDB_LIBRARIES}
+ )
+endif()
+
+include_directories(${INC})
+include_directories(SYSTEM ${INC_SYS})
+
+add_library(hdCyclesStatic STATIC
+ ${SRC_HD_CYCLES}
+ ${INC_HD_CYCLES}
+)
+
+target_compile_options(hdCyclesStatic
+ PRIVATE
+ $<$<CXX_COMPILER_ID:MSVC>:/wd4003 /wd4244 /wd4506>
+ $<$<CXX_COMPILER_ID:GNU>:-Wno-float-conversion -Wno-double-promotion -Wno-deprecated>
+)
+
+target_compile_definitions(hdCyclesStatic
+ PRIVATE
+ GLOG_NO_ABBREVIATED_SEVERITIES=1
+ OSL_DEBUG=$<CONFIG:DEBUG>
+ TBB_USE_DEBUG=$<CONFIG:DEBUG>
+ $<$<CXX_COMPILER_ID:MSVC>:NOMINMAX=1>
+)
+
+target_link_libraries(hdCyclesStatic
+ PRIVATE
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}hd${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}plug${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}tf${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}trace${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}vt${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}work${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}sdf${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}cameraUtil${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}hf${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}pxOsd${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}gf${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}arch${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}hgi${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}glf${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}hdx${CMAKE_LINK_LIBRARY_SUFFIX}
+ ${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}usdGeom${CMAKE_LINK_LIBRARY_SUFFIX}
+ cycles_scene
+ cycles_session
+ cycles_graph
+)
+
+if(USD_PYTHON_LIBRARIES)
+ target_link_libraries(hdCyclesStatic
+ PRIVATE
+ ${USD_PYTHON_LIBRARIES}
+ )
+endif()
+
+set(HdCyclesPluginName hdCycles)
+add_library(${HdCyclesPluginName} SHARED
+ plugin.h
+ plugin.cpp
+)
+
+set_target_properties(${HdCyclesPluginName}
+ PROPERTIES PREFIX ""
+)
+
+target_compile_definitions(${HdCyclesPluginName}
+ PRIVATE
+ MFB_PACKAGE_NAME=${HdCyclesPluginName}
+ MFB_ALT_PACKAGE_NAME=${HdCyclesPluginName}
+ GLOG_NO_ABBREVIATED_SEVERITIES=1
+ OSL_DEBUG=$<CONFIG:DEBUG>
+ TBB_USE_DEBUG=$<CONFIG:DEBUG>
+ $<$<CXX_COMPILER_ID:MSVC>:NOMINMAX=1>
+)
+
+target_link_libraries(${HdCyclesPluginName}
+ hdCyclesStatic
+)
+
+target_link_directories(${HdCyclesPluginName}
+ BEFORE
+ PRIVATE
+ ${USD_LIBRARY_DIR}
+)
+
+cycles_target_link_libraries(${HdCyclesPluginName})
+
+if(WITH_CYCLES_BLENDER)
+ set(CYCLES_HYDRA_INSTALL_PATH "../")
+else()
+ set(CYCLES_HYDRA_INSTALL_PATH ${CMAKE_INSTALL_PREFIX})
+ # Put the root plugInfo.json one level up
+ delayed_install("${CMAKE_CURRENT_SOURCE_DIR}" "plugInfo.json" ${CMAKE_INSTALL_PREFIX})
+endif()
+
+delayed_install("" $<TARGET_FILE:${HdCyclesPluginName}> ${CYCLES_HYDRA_INSTALL_PATH})
+
+set(PLUG_INFO_ROOT "..")
+set(PLUG_INFO_LIBRARY_PATH "../${HdCyclesPluginName}${CMAKE_SHARED_LIBRARY_SUFFIX}")
+set(PLUG_INFO_RESOURCE_PATH "resources")
+
+configure_file(resources/plugInfo.json
+ ${CMAKE_CURRENT_BINARY_DIR}/resources/plugInfo.json
+ @ONLY
+)
+
+delayed_install("${CMAKE_CURRENT_BINARY_DIR}/resources" "plugInfo.json" "${CYCLES_HYDRA_INSTALL_PATH}/${HdCyclesPluginName}/resources")
diff --git a/intern/cycles/hydra/attribute.cpp b/intern/cycles/hydra/attribute.cpp
new file mode 100644
index 00000000000..f22665345e6
--- /dev/null
+++ b/intern/cycles/hydra/attribute.cpp
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/attribute.h"
+#include "scene/attribute.h"
+#include "scene/geometry.h"
+#include "scene/scene.h"
+
+#include <pxr/base/gf/vec2f.h>
+#include <pxr/base/gf/vec3f.h>
+#include <pxr/base/gf/vec4f.h>
+#include <pxr/base/vt/array.h>
+#include <pxr/imaging/hd/tokens.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+void ApplyPrimvars(AttributeSet &attributes,
+ const ustring &name,
+ VtValue value,
+ AttributeElement elem,
+ AttributeStandard std)
+{
+ const void *data = HdGetValueData(value);
+ size_t size = value.GetArraySize();
+
+ const HdType valueType = HdGetValueTupleType(value).type;
+
+ TypeDesc attrType = CCL_NS::TypeUnknown;
+ switch (valueType) {
+ case HdTypeFloat:
+ attrType = CCL_NS::TypeFloat;
+ size *= sizeof(float);
+ break;
+ case HdTypeFloatVec2:
+ attrType = CCL_NS::TypeFloat2;
+ size *= sizeof(float2);
+ static_assert(sizeof(GfVec2f) == sizeof(float2));
+ break;
+ case HdTypeFloatVec3: {
+ attrType = CCL_NS::TypeVector;
+ size *= sizeof(float3);
+ // The Cycles "float3" data type is padded to "float4", so need to convert the array
+ const auto &valueData = value.Get<VtVec3fArray>();
+ VtArray<float3> valueConverted;
+ valueConverted.reserve(valueData.size());
+ for (const GfVec3f &vec : valueData) {
+ valueConverted.push_back(make_float3(vec[0], vec[1], vec[2]));
+ }
+ data = valueConverted.data();
+ value = std::move(valueConverted);
+ break;
+ }
+ case HdTypeFloatVec4:
+ attrType = CCL_NS::TypeFloat4;
+ size *= sizeof(float4);
+ static_assert(sizeof(GfVec4f) == sizeof(float4));
+ break;
+ default:
+ TF_WARN("Unsupported attribute type %d", static_cast<int>(valueType));
+ return;
+ }
+
+ Attribute *const attr = attributes.add(name, attrType, elem);
+ attr->std = std;
+
+ assert(size == attr->buffer.size());
+ std::memcpy(attr->data(), data, size);
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/attribute.h b/intern/cycles/hydra/attribute.h
new file mode 100644
index 00000000000..3277f97f44d
--- /dev/null
+++ b/intern/cycles/hydra/attribute.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+#include "scene/attribute.h"
+
+#include <pxr/base/vt/value.h>
+#include <pxr/imaging/hd/types.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+void ApplyPrimvars(CCL_NS::AttributeSet &attributes,
+ const CCL_NS::ustring &name,
+ PXR_NS::VtValue value,
+ CCL_NS::AttributeElement elem,
+ CCL_NS::AttributeStandard std);
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/camera.cpp b/intern/cycles/hydra/camera.cpp
new file mode 100644
index 00000000000..05f1c32d3c4
--- /dev/null
+++ b/intern/cycles/hydra/camera.cpp
@@ -0,0 +1,297 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/camera.h"
+#include "scene/camera.h"
+
+#include <pxr/base/gf/frustum.h>
+#include <pxr/imaging/hd/sceneDelegate.h>
+#include <pxr/usd/usdGeom/tokens.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+extern Transform convert_transform(const GfMatrix4d &matrix);
+
+HdCyclesCamera::HdCyclesCamera(const SdfPath &sprimId) : HdCamera(sprimId)
+{
+#if PXR_VERSION >= 2102
+ // Synchronize default values
+ _horizontalAperture = _data.GetHorizontalAperture() * GfCamera::APERTURE_UNIT;
+ _verticalAperture = _data.GetVerticalAperture() * GfCamera::APERTURE_UNIT;
+ _horizontalApertureOffset = _data.GetHorizontalApertureOffset() * GfCamera::APERTURE_UNIT;
+ _verticalApertureOffset = _data.GetVerticalApertureOffset() * GfCamera::APERTURE_UNIT;
+ _focalLength = _data.GetFocalLength() * GfCamera::FOCAL_LENGTH_UNIT;
+ _clippingRange = _data.GetClippingRange();
+ _fStop = _data.GetFStop();
+ _focusDistance = _data.GetFocusDistance();
+#endif
+}
+
+HdCyclesCamera::~HdCyclesCamera()
+{
+}
+
+HdDirtyBits HdCyclesCamera::GetInitialDirtyBitsMask() const
+{
+ return DirtyBits::AllDirty;
+}
+
+void HdCyclesCamera::Sync(HdSceneDelegate *sceneDelegate,
+ HdRenderParam *renderParam,
+ HdDirtyBits *dirtyBits)
+{
+ if (*dirtyBits == DirtyBits::Clean) {
+ return;
+ }
+
+ VtValue value;
+ const SdfPath &id = GetId();
+
+#if PXR_VERSION >= 2102
+ if (*dirtyBits & DirtyBits::DirtyTransform) {
+ sceneDelegate->SampleTransform(id, &_transformSamples);
+
+ for (size_t i = 0; i < _transformSamples.count; ++i) {
+ if (_transformSamples.times[i] == 0.0f) {
+ _transform = _transformSamples.values[i];
+ _data.SetTransform(_transform);
+ break;
+ }
+ }
+ }
+#else
+ if (*dirtyBits & DirtyBits::DirtyViewMatrix) {
+ sceneDelegate->SampleTransform(id, &_transformSamples);
+
+ value = sceneDelegate->GetCameraParamValue(id, HdCameraTokens->worldToViewMatrix);
+ if (!value.IsEmpty()) {
+ _worldToViewMatrix = value.Get<GfMatrix4d>();
+ _worldToViewInverseMatrix = _worldToViewMatrix.GetInverse();
+ _data.SetTransform(_worldToViewInverseMatrix);
+ }
+ }
+#endif
+
+ if (*dirtyBits & DirtyBits::DirtyProjMatrix) {
+ value = sceneDelegate->GetCameraParamValue(id, HdCameraTokens->projectionMatrix);
+ if (!value.IsEmpty()) {
+ _projectionMatrix = value.Get<GfMatrix4d>();
+ const float focalLength = _data.GetFocalLength(); // Get default focal length
+#if PXR_VERSION >= 2102
+ _data.SetFromViewAndProjectionMatrix(GetViewMatrix(), _projectionMatrix, focalLength);
+#else
+ if (_projectionMatrix[2][3] < -0.5) {
+ _data.SetProjection(GfCamera::Perspective);
+
+ const float horizontalAperture = (2.0 * focalLength) / _projectionMatrix[0][0];
+ _data.SetHorizontalAperture(horizontalAperture);
+ _data.SetHorizontalApertureOffset(0.5 * horizontalAperture * _projectionMatrix[2][0]);
+ const float verticalAperture = (2.0 * focalLength) / _projectionMatrix[1][1];
+ _data.SetVerticalAperture(verticalAperture);
+ _data.SetVerticalApertureOffset(0.5 * verticalAperture * _projectionMatrix[2][1]);
+
+ _data.SetClippingRange(
+ GfRange1f(_projectionMatrix[3][2] / (_projectionMatrix[2][2] - 1.0),
+ _projectionMatrix[3][2] / (_projectionMatrix[2][2] + 1.0)));
+ }
+ else {
+ _data.SetProjection(GfCamera::Orthographic);
+
+ const float horizontalAperture = (2.0 / GfCamera::APERTURE_UNIT) / _projectionMatrix[0][0];
+ _data.SetHorizontalAperture(horizontalAperture);
+ _data.SetHorizontalApertureOffset(-0.5 * horizontalAperture * _projectionMatrix[3][0]);
+ const float verticalAperture = (2.0 / GfCamera::APERTURE_UNIT) / _projectionMatrix[1][1];
+ _data.SetVerticalAperture(verticalAperture);
+ _data.SetVerticalApertureOffset(-0.5 * verticalAperture * _projectionMatrix[3][1]);
+
+ const double nearMinusFarHalf = 1.0 / _projectionMatrix[2][2];
+ const double nearPlusFarHalf = nearMinusFarHalf * _projectionMatrix[3][2];
+ _data.SetClippingRange(
+ GfRange1f(nearPlusFarHalf + nearMinusFarHalf, nearPlusFarHalf - nearMinusFarHalf));
+ }
+#endif
+ }
+ }
+
+ if (*dirtyBits & DirtyBits::DirtyWindowPolicy) {
+ value = sceneDelegate->GetCameraParamValue(id, HdCameraTokens->windowPolicy);
+ if (!value.IsEmpty()) {
+ _windowPolicy = value.Get<CameraUtilConformWindowPolicy>();
+ }
+ }
+
+ if (*dirtyBits & DirtyBits::DirtyClipPlanes) {
+ value = sceneDelegate->GetCameraParamValue(id, HdCameraTokens->clipPlanes);
+ if (!value.IsEmpty()) {
+ _clipPlanes = value.Get<std::vector<GfVec4d>>();
+ }
+ }
+
+ if (*dirtyBits & DirtyBits::DirtyParams) {
+#if PXR_VERSION >= 2102
+ value = sceneDelegate->GetCameraParamValue(id, HdCameraTokens->projection);
+ if (!value.IsEmpty()) {
+ _projection = value.Get<Projection>();
+ _data.SetProjection(_projection != Orthographic ? GfCamera::Perspective :
+ GfCamera::Orthographic);
+ }
+#else
+ value = sceneDelegate->GetCameraParamValue(id, UsdGeomTokens->projection);
+ if (!value.IsEmpty()) {
+ _data.SetProjection(value.Get<TfToken>() != UsdGeomTokens->orthographic ?
+ GfCamera::Perspective :
+ GfCamera::Orthographic);
+ }
+#endif
+
+ value = sceneDelegate->GetCameraParamValue(id, HdCameraTokens->horizontalAperture);
+ if (!value.IsEmpty()) {
+ const auto horizontalAperture = value.Get<float>();
+#if PXR_VERSION >= 2102
+ _horizontalAperture = horizontalAperture;
+#endif
+ _data.SetHorizontalAperture(horizontalAperture / GfCamera::APERTURE_UNIT);
+ }
+
+ value = sceneDelegate->GetCameraParamValue(id, HdCameraTokens->verticalAperture);
+ if (!value.IsEmpty()) {
+ const auto verticalAperture = value.Get<float>();
+#if PXR_VERSION >= 2102
+ _verticalAperture = verticalAperture;
+#endif
+ _data.SetVerticalAperture(verticalAperture / GfCamera::APERTURE_UNIT);
+ }
+
+ value = sceneDelegate->GetCameraParamValue(id, HdCameraTokens->horizontalApertureOffset);
+ if (!value.IsEmpty()) {
+ const auto horizontalApertureOffset = value.Get<float>();
+#if PXR_VERSION >= 2102
+ _horizontalApertureOffset = horizontalApertureOffset;
+#endif
+ _data.SetHorizontalApertureOffset(horizontalApertureOffset / GfCamera::APERTURE_UNIT);
+ }
+
+ value = sceneDelegate->GetCameraParamValue(id, HdCameraTokens->verticalApertureOffset);
+ if (!value.IsEmpty()) {
+ const auto verticalApertureOffset = value.Get<float>();
+#if PXR_VERSION >= 2102
+ _verticalApertureOffset = verticalApertureOffset;
+#endif
+ _data.SetVerticalApertureOffset(verticalApertureOffset / GfCamera::APERTURE_UNIT);
+ }
+
+ value = sceneDelegate->GetCameraParamValue(id, HdCameraTokens->focalLength);
+ if (!value.IsEmpty()) {
+ const auto focalLength = value.Get<float>();
+#if PXR_VERSION >= 2102
+ _focalLength = focalLength;
+#endif
+ _data.SetFocalLength(focalLength / GfCamera::FOCAL_LENGTH_UNIT);
+ }
+
+ value = sceneDelegate->GetCameraParamValue(id, HdCameraTokens->clippingRange);
+ if (!value.IsEmpty()) {
+ const auto clippingRange = value.Get<GfRange1f>();
+#if PXR_VERSION >= 2102
+ _clippingRange = clippingRange;
+#endif
+ _data.SetClippingRange(clippingRange);
+ }
+
+ value = sceneDelegate->GetCameraParamValue(id, HdCameraTokens->fStop);
+ if (!value.IsEmpty()) {
+ const auto fStop = value.Get<float>();
+#if PXR_VERSION >= 2102
+ _fStop = fStop;
+#endif
+ _data.SetFStop(fStop);
+ }
+
+ value = sceneDelegate->GetCameraParamValue(id, HdCameraTokens->focusDistance);
+ if (!value.IsEmpty()) {
+ const auto focusDistance = value.Get<float>();
+#if PXR_VERSION >= 2102
+ _focusDistance = focusDistance;
+#endif
+ _data.SetFocusDistance(focusDistance);
+ }
+ }
+
+ *dirtyBits = DirtyBits::Clean;
+}
+
+void HdCyclesCamera::Finalize(HdRenderParam *renderParam)
+{
+ HdCamera::Finalize(renderParam);
+}
+
+void HdCyclesCamera::ApplyCameraSettings(Camera *cam) const
+{
+ ApplyCameraSettings(_data, _windowPolicy, cam);
+
+ array<Transform> motion(_transformSamples.count);
+ for (size_t i = 0; i < _transformSamples.count; ++i)
+ motion[i] = convert_transform(_transformSamples.values[i]) *
+ transform_scale(1.0f, 1.0f, -1.0f);
+ cam->set_motion(motion);
+}
+
+void HdCyclesCamera::ApplyCameraSettings(const GfCamera &dataUnconformedWindow,
+ CameraUtilConformWindowPolicy windowPolicy,
+ Camera *cam)
+{
+ const float width = cam->get_full_width();
+ const float height = cam->get_full_height();
+
+ auto data = dataUnconformedWindow;
+ CameraUtilConformWindow(&data, windowPolicy, width / height);
+
+ static_assert(GfCamera::Perspective == CAMERA_PERSPECTIVE &&
+ GfCamera::Orthographic == CAMERA_ORTHOGRAPHIC);
+ cam->set_camera_type(static_cast<CameraType>(data.GetProjection()));
+
+ auto viewplane = data.GetFrustum().GetWindow();
+ auto focalLength = 1.0f;
+ if (data.GetProjection() == GfCamera::Perspective) {
+ viewplane *= 2.0 / viewplane.GetSize()[1]; // Normalize viewplane
+ focalLength = data.GetFocalLength() * 1e-3f;
+
+ cam->set_fov(GfDegreesToRadians(data.GetFieldOfView(GfCamera::FOVVertical)));
+ }
+
+ cam->set_sensorwidth(data.GetHorizontalAperture() * GfCamera::APERTURE_UNIT);
+ cam->set_sensorheight(data.GetVerticalAperture() * GfCamera::APERTURE_UNIT);
+
+ cam->set_nearclip(data.GetClippingRange().GetMin());
+ cam->set_farclip(data.GetClippingRange().GetMax());
+
+ cam->set_viewplane_left(viewplane.GetMin()[0]);
+ cam->set_viewplane_right(viewplane.GetMax()[0]);
+ cam->set_viewplane_bottom(viewplane.GetMin()[1]);
+ cam->set_viewplane_top(viewplane.GetMax()[1]);
+
+ if (data.GetFStop() != 0.0f) {
+ cam->set_focaldistance(data.GetFocusDistance());
+ cam->set_aperturesize(focalLength / (2.0f * data.GetFStop()));
+ }
+
+ cam->set_matrix(convert_transform(data.GetTransform()) * transform_scale(1.0f, 1.0f, -1.0f));
+}
+
+void HdCyclesCamera::ApplyCameraSettings(const GfMatrix4d &worldToViewMatrix,
+ const GfMatrix4d &projectionMatrix,
+ const std::vector<GfVec4d> &clipPlanes,
+ Camera *cam)
+{
+#if PXR_VERSION >= 2102
+ GfCamera data;
+ data.SetFromViewAndProjectionMatrix(worldToViewMatrix, projectionMatrix);
+
+ ApplyCameraSettings(data, CameraUtilFit, cam);
+#else
+ TF_CODING_ERROR("Not implemented");
+#endif
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/camera.h b/intern/cycles/hydra/camera.h
new file mode 100644
index 00000000000..8b7fed5a6bb
--- /dev/null
+++ b/intern/cycles/hydra/camera.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+
+#include <pxr/base/gf/camera.h>
+#include <pxr/imaging/hd/camera.h>
+#include <pxr/imaging/hd/timeSampleArray.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesCamera final : public PXR_NS::HdCamera {
+ public:
+ HdCyclesCamera(const PXR_NS::SdfPath &sprimId);
+ ~HdCyclesCamera() override;
+
+ void ApplyCameraSettings(CCL_NS::Camera *targetCamera) const;
+
+ static void ApplyCameraSettings(const PXR_NS::GfCamera &cameraData,
+ PXR_NS::CameraUtilConformWindowPolicy windowPolicy,
+ CCL_NS::Camera *targetCamera);
+ static void ApplyCameraSettings(const PXR_NS::GfMatrix4d &worldToViewMatrix,
+ const PXR_NS::GfMatrix4d &projectionMatrix,
+ const std::vector<PXR_NS::GfVec4d> &clipPlanes,
+ CCL_NS::Camera *targetCamera);
+
+ PXR_NS::HdDirtyBits GetInitialDirtyBitsMask() const override;
+
+ void Sync(PXR_NS::HdSceneDelegate *sceneDelegate,
+ PXR_NS::HdRenderParam *renderParam,
+ PXR_NS::HdDirtyBits *dirtyBits) override;
+
+ void Finalize(PXR_NS::HdRenderParam *renderParam) override;
+
+ private:
+ PXR_NS::GfCamera _data;
+ PXR_NS::HdTimeSampleArray<PXR_NS::GfMatrix4d, 2> _transformSamples;
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/config.h b/intern/cycles/hydra/config.h
new file mode 100644
index 00000000000..034be302d9f
--- /dev/null
+++ b/intern/cycles/hydra/config.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include <pxr/pxr.h>
+
+#define CCL_NS ccl
+#define CCL_NAMESPACE_USING_DIRECTIVE using namespace CCL_NS;
+
+#define HD_CYCLES_NS HdCycles
+#define HDCYCLES_NAMESPACE_OPEN_SCOPE \
+ namespace HD_CYCLES_NS { \
+ CCL_NAMESPACE_USING_DIRECTIVE; \
+ PXR_NAMESPACE_USING_DIRECTIVE;
+#define HDCYCLES_NAMESPACE_CLOSE_SCOPE }
+
+namespace HD_CYCLES_NS {
+class HdCyclesCamera;
+class HdCyclesDelegate;
+class HdCyclesSession;
+class HdCyclesRenderBuffer;
+} // namespace HD_CYCLES_NS
+
+namespace CCL_NS {
+class AttributeSet;
+class BufferParams;
+class Camera;
+class Geometry;
+class Hair;
+class Light;
+class Mesh;
+class Object;
+class ParticleSystem;
+class Pass;
+class PointCloud;
+class Scene;
+class Session;
+class SessionParams;
+class Shader;
+class ShaderGraph;
+class Volume;
+} // namespace CCL_NS
diff --git a/intern/cycles/hydra/curves.cpp b/intern/cycles/hydra/curves.cpp
new file mode 100644
index 00000000000..2007a5d09ca
--- /dev/null
+++ b/intern/cycles/hydra/curves.cpp
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/curves.h"
+#include "hydra/geometry.inl"
+#include "scene/hair.h"
+
+#include <pxr/imaging/hd/extComputationUtils.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+HdCyclesCurves::HdCyclesCurves(const SdfPath &rprimId
+#if PXR_VERSION < 2102
+ ,
+ const SdfPath &instancerId
+#endif
+ )
+ : HdCyclesGeometry(rprimId
+#if PXR_VERSION < 2102
+ ,
+ instancerId
+#endif
+ )
+{
+}
+
+HdCyclesCurves::~HdCyclesCurves()
+{
+}
+
+HdDirtyBits HdCyclesCurves::GetInitialDirtyBitsMask() const
+{
+ HdDirtyBits bits = HdCyclesGeometry::GetInitialDirtyBitsMask();
+ bits |= HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyWidths |
+ HdChangeTracker::DirtyPrimvar | HdChangeTracker::DirtyTopology;
+ return bits;
+}
+
+HdDirtyBits HdCyclesCurves::_PropagateDirtyBits(HdDirtyBits bits) const
+{
+ if (bits & (HdChangeTracker::DirtyTopology)) {
+ // Changing topology clears the geometry, so need to populate everything again
+ bits |= HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyWidths |
+ HdChangeTracker::DirtyPrimvar;
+ }
+
+ return bits;
+}
+
+void HdCyclesCurves::Populate(HdSceneDelegate *sceneDelegate, HdDirtyBits dirtyBits, bool &rebuild)
+{
+ if (HdChangeTracker::IsTopologyDirty(dirtyBits, GetId())) {
+ PopulateTopology(sceneDelegate);
+ }
+
+ if (dirtyBits & HdChangeTracker::DirtyPoints) {
+ PopulatePoints(sceneDelegate);
+ }
+
+ if (dirtyBits & HdChangeTracker::DirtyWidths) {
+ PopulateWidths(sceneDelegate);
+ }
+
+ if (dirtyBits & HdChangeTracker::DirtyPrimvar) {
+ PopulatePrimvars(sceneDelegate);
+ }
+
+ rebuild = (_geom->curve_keys_is_modified()) || (_geom->curve_radius_is_modified());
+}
+
+void HdCyclesCurves::PopulatePoints(HdSceneDelegate *sceneDelegate)
+{
+ VtValue value;
+
+ for (const HdExtComputationPrimvarDescriptor &desc :
+ sceneDelegate->GetExtComputationPrimvarDescriptors(GetId(), HdInterpolationVertex)) {
+ if (desc.name == HdTokens->points) {
+ auto valueStore = HdExtComputationUtils::GetComputedPrimvarValues({desc}, sceneDelegate);
+ const auto valueStoreIt = valueStore.find(desc.name);
+ if (valueStoreIt != valueStore.end()) {
+ value = std::move(valueStoreIt->second);
+ }
+ break;
+ }
+ }
+
+ if (value.IsEmpty()) {
+ value = GetPrimvar(sceneDelegate, HdTokens->points);
+ }
+
+ if (!value.IsHolding<VtVec3fArray>()) {
+ TF_WARN("Invalid points data for %s", GetId().GetText());
+ return;
+ }
+
+ const auto &points = value.UncheckedGet<VtVec3fArray>();
+
+ array<float3> pointsDataCycles;
+ pointsDataCycles.reserve(points.size());
+
+ for (const GfVec3f &point : points) {
+ pointsDataCycles.push_back_reserved(make_float3(point[0], point[1], point[2]));
+ }
+
+ _geom->set_curve_keys(pointsDataCycles);
+}
+
+void HdCyclesCurves::PopulateWidths(HdSceneDelegate *sceneDelegate)
+{
+ VtValue value = GetPrimvar(sceneDelegate, HdTokens->widths);
+ const HdInterpolation interpolation = GetPrimvarInterpolation(sceneDelegate, HdTokens->widths);
+
+ if (!value.IsHolding<VtFloatArray>()) {
+ TF_WARN("Invalid widths data for %s", GetId().GetText());
+ return;
+ }
+
+ const auto &widths = value.UncheckedGet<VtFloatArray>();
+
+ array<float> radiusDataCycles;
+ radiusDataCycles.reserve(widths.size());
+
+ if (interpolation == HdInterpolationConstant) {
+ TF_VERIFY(widths.size() == 1);
+
+ const float constantRadius = widths[0] * 0.5f;
+
+ for (size_t i = 0; i < _geom->num_keys(); ++i) {
+ radiusDataCycles.push_back_reserved(constantRadius);
+ }
+ }
+ else if (interpolation == HdInterpolationVertex) {
+ TF_VERIFY(widths.size() == _geom->num_keys());
+
+ for (size_t i = 0; i < _geom->num_keys(); ++i) {
+ radiusDataCycles.push_back_reserved(widths[i] * 0.5f);
+ }
+ }
+
+ _geom->set_curve_radius(radiusDataCycles);
+}
+
+void HdCyclesCurves::PopulatePrimvars(HdSceneDelegate *sceneDelegate)
+{
+ Scene *const scene = (Scene *)_geom->get_owner();
+
+ const std::pair<HdInterpolation, AttributeElement> interpolations[] = {
+ std::make_pair(HdInterpolationVertex, ATTR_ELEMENT_CURVE_KEY),
+ std::make_pair(HdInterpolationVarying, ATTR_ELEMENT_CURVE_KEY),
+ std::make_pair(HdInterpolationUniform, ATTR_ELEMENT_CURVE),
+ std::make_pair(HdInterpolationConstant, ATTR_ELEMENT_OBJECT),
+ };
+
+ for (const auto &interpolation : interpolations) {
+ for (const HdPrimvarDescriptor &desc :
+ GetPrimvarDescriptors(sceneDelegate, interpolation.first)) {
+ // Skip special primvars that are handled separately
+ if (desc.name == HdTokens->points || desc.name == HdTokens->widths) {
+ continue;
+ }
+
+ VtValue value = GetPrimvar(sceneDelegate, desc.name);
+ if (value.IsEmpty()) {
+ continue;
+ }
+
+ const ustring name(desc.name.GetString());
+
+ AttributeStandard std = ATTR_STD_NONE;
+ if (desc.role == HdPrimvarRoleTokens->textureCoordinate) {
+ std = ATTR_STD_UV;
+ }
+ else if (desc.name == HdTokens->displayColor &&
+ interpolation.first == HdInterpolationConstant) {
+ if (value.IsHolding<VtVec3fArray>() && value.GetArraySize() == 1) {
+ const GfVec3f color = value.UncheckedGet<VtVec3fArray>()[0];
+ _instances[0]->set_color(make_float3(color[0], color[1], color[2]));
+ }
+ }
+
+ // Skip attributes that are not needed
+ if ((std != ATTR_STD_NONE && _geom->need_attribute(scene, std)) ||
+ _geom->need_attribute(scene, name)) {
+ ApplyPrimvars(_geom->attributes, name, value, interpolation.second, std);
+ }
+ }
+ }
+}
+
+void HdCyclesCurves::PopulateTopology(HdSceneDelegate *sceneDelegate)
+{
+ // Clear geometry before populating it again with updated topology
+ _geom->clear(true);
+
+ HdBasisCurvesTopology topology = GetBasisCurvesTopology(sceneDelegate);
+
+ _geom->reserve_curves(topology.GetNumCurves(), topology.CalculateNeededNumberOfControlPoints());
+
+ const VtIntArray vertCounts = topology.GetCurveVertexCounts();
+
+ for (int curve = 0, key = 0; curve < topology.GetNumCurves(); ++curve) {
+ // Always reference shader at index zero, which is the primitive material
+ _geom->add_curve(key, 0);
+
+ key += vertCounts[curve];
+ }
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/curves.h b/intern/cycles/hydra/curves.h
new file mode 100644
index 00000000000..1eb4a51c0db
--- /dev/null
+++ b/intern/cycles/hydra/curves.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+#include "hydra/geometry.h"
+
+#include <pxr/imaging/hd/basisCurves.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesCurves final : public HdCyclesGeometry<PXR_NS::HdBasisCurves, CCL_NS::Hair> {
+ public:
+ HdCyclesCurves(
+ const PXR_NS::SdfPath &rprimId
+#if PXR_VERSION < 2102
+ ,
+ const PXR_NS::SdfPath &instancerId = {}
+#endif
+ );
+ ~HdCyclesCurves() override;
+
+ PXR_NS::HdDirtyBits GetInitialDirtyBitsMask() const override;
+
+ private:
+ PXR_NS::HdDirtyBits _PropagateDirtyBits(PXR_NS::HdDirtyBits bits) const override;
+
+ void Populate(PXR_NS::HdSceneDelegate *sceneDelegate,
+ PXR_NS::HdDirtyBits dirtyBits,
+ bool &rebuild) override;
+
+ void PopulatePoints(PXR_NS::HdSceneDelegate *sceneDelegate);
+ void PopulateWidths(PXR_NS::HdSceneDelegate *sceneDelegate);
+
+ void PopulatePrimvars(PXR_NS::HdSceneDelegate *sceneDelegate);
+
+ void PopulateTopology(PXR_NS::HdSceneDelegate *sceneDelegate);
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/display_driver.cpp b/intern/cycles/hydra/display_driver.cpp
new file mode 100644
index 00000000000..6f6ca35cd31
--- /dev/null
+++ b/intern/cycles/hydra/display_driver.cpp
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#ifdef _WIN32
+// Include first to avoid "NOGDI" definition set in Cycles headers
+# include <Windows.h>
+#endif
+
+#include "hydra/display_driver.h"
+#include "hydra/render_buffer.h"
+#include "hydra/session.h"
+
+#include <GL/glew.h>
+#include <pxr/imaging/hgiGL/texture.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+HdCyclesDisplayDriver::HdCyclesDisplayDriver(HdCyclesSession *renderParam, Hgi *hgi)
+ : _renderParam(renderParam), _hgi(hgi)
+{
+#ifdef _WIN32
+ hdc_ = GetDC(CreateWindowA("STATIC",
+ "HdCycles",
+ WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
+ 0,
+ 0,
+ 64,
+ 64,
+ NULL,
+ NULL,
+ GetModuleHandle(NULL),
+ NULL));
+
+ int pixelFormat = GetPixelFormat(wglGetCurrentDC());
+ PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd)};
+ DescribePixelFormat((HDC)hdc_, pixelFormat, sizeof(pfd), &pfd);
+ SetPixelFormat((HDC)hdc_, pixelFormat, &pfd);
+
+ TF_VERIFY(gl_context_ = wglCreateContext((HDC)hdc_));
+ TF_VERIFY(wglShareLists(wglGetCurrentContext(), (HGLRC)gl_context_));
+#endif
+
+ glewInit();
+
+ glGenBuffers(1, &gl_pbo_id_);
+}
+
+HdCyclesDisplayDriver::~HdCyclesDisplayDriver()
+{
+ if (texture_) {
+ _hgi->DestroyTexture(&texture_);
+ }
+
+ glDeleteBuffers(1, &gl_pbo_id_);
+
+#ifdef _WIN32
+ TF_VERIFY(wglDeleteContext((HGLRC)gl_context_));
+ DestroyWindow(WindowFromDC((HDC)hdc_));
+#endif
+}
+
+void HdCyclesDisplayDriver::next_tile_begin()
+{
+}
+
+bool HdCyclesDisplayDriver::update_begin(const Params &params,
+ int texture_width,
+ int texture_height)
+{
+#ifdef _WIN32
+ if (!hdc_ || !gl_context_) {
+ return false;
+ }
+#endif
+
+ graphics_interop_activate();
+
+ if (gl_render_sync_) {
+ glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
+ }
+
+ if (pbo_size_.x != params.full_size.x || pbo_size_.y != params.full_size.y) {
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_pbo_id_);
+ glBufferData(GL_PIXEL_UNPACK_BUFFER,
+ sizeof(half4) * params.full_size.x * params.full_size.y,
+ 0,
+ GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ pbo_size_ = params.full_size;
+ }
+
+ need_update_ = true;
+
+ return true;
+}
+
+void HdCyclesDisplayDriver::update_end()
+{
+ gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+
+ glFlush();
+
+ graphics_interop_deactivate();
+}
+
+void HdCyclesDisplayDriver::flush()
+{
+ graphics_interop_activate();
+
+ if (gl_upload_sync_) {
+ glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
+ }
+
+ if (gl_render_sync_) {
+ glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
+ }
+
+ graphics_interop_deactivate();
+}
+
+half4 *HdCyclesDisplayDriver::map_texture_buffer()
+{
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_pbo_id_);
+
+ const auto mapped_rgba_pixels = static_cast<half4 *>(
+ glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));
+
+ if (need_clear_ && mapped_rgba_pixels) {
+ memset(mapped_rgba_pixels, 0, sizeof(half4) * pbo_size_.x * pbo_size_.y);
+ need_clear_ = false;
+ }
+
+ return mapped_rgba_pixels;
+}
+
+void HdCyclesDisplayDriver::unmap_texture_buffer()
+{
+ glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
+
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+}
+
+DisplayDriver::GraphicsInterop HdCyclesDisplayDriver::graphics_interop_get()
+{
+ GraphicsInterop interop_dst;
+ interop_dst.buffer_width = pbo_size_.x;
+ interop_dst.buffer_height = pbo_size_.y;
+ interop_dst.opengl_pbo_id = gl_pbo_id_;
+
+ interop_dst.need_clear = need_clear_;
+ need_clear_ = false;
+
+ return interop_dst;
+}
+
+void HdCyclesDisplayDriver::graphics_interop_activate()
+{
+ mutex_.lock();
+
+#ifdef _WIN32
+ // Do not change context if this is called in the main thread
+ if (wglGetCurrentContext() == nullptr) {
+ TF_VERIFY(wglMakeCurrent((HDC)hdc_, (HGLRC)gl_context_));
+ }
+#endif
+}
+
+void HdCyclesDisplayDriver::graphics_interop_deactivate()
+{
+#ifdef _WIN32
+ if (wglGetCurrentContext() == gl_context_) {
+ TF_VERIFY(wglMakeCurrent(nullptr, nullptr));
+ }
+#endif
+
+ mutex_.unlock();
+}
+
+void HdCyclesDisplayDriver::clear()
+{
+ need_clear_ = true;
+}
+
+void HdCyclesDisplayDriver::draw(const Params &params)
+{
+ const auto renderBuffer = static_cast<HdCyclesRenderBuffer *>(
+ _renderParam->GetDisplayAovBinding().renderBuffer);
+ if (!renderBuffer || // Ensure this render buffer matches the texture dimensions
+ (renderBuffer->GetWidth() != params.size.x || renderBuffer->GetHeight() != params.size.y)) {
+ return;
+ }
+
+ // Cycles 'DisplayDriver' only supports 'half4' format
+ TF_VERIFY(renderBuffer->GetFormat() == HdFormatFloat16Vec4);
+
+ const thread_scoped_lock lock(mutex_);
+
+ const GfVec3i dimensions(params.size.x, params.size.y, 1);
+ if (!texture_ || texture_->GetDescriptor().dimensions != dimensions) {
+ if (texture_) {
+ _hgi->DestroyTexture(&texture_);
+ }
+
+ HgiTextureDesc texDesc;
+ texDesc.usage = 0;
+ texDesc.format = HgiFormatFloat16Vec4;
+ texDesc.type = HgiTextureType2D;
+ texDesc.dimensions = dimensions;
+ texDesc.sampleCount = HgiSampleCount1;
+
+ texture_ = _hgi->CreateTexture(texDesc);
+
+ renderBuffer->SetResource(VtValue(texture_));
+ }
+
+ HgiGLTexture *const texture = dynamic_cast<HgiGLTexture *>(texture_.Get());
+ if (!texture || !need_update_ || pbo_size_.x != params.size.x || pbo_size_.y != params.size.y) {
+ return;
+ }
+
+ if (gl_upload_sync_) {
+ glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, texture->GetTextureId());
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_pbo_id_);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, pbo_size_.x, pbo_size_.y, GL_RGBA, GL_HALF_FLOAT, 0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+
+ glFlush();
+
+ need_update_ = false;
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/display_driver.h b/intern/cycles/hydra/display_driver.h
new file mode 100644
index 00000000000..668f7d76eed
--- /dev/null
+++ b/intern/cycles/hydra/display_driver.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+#include "session/display_driver.h"
+#include "util/thread.h"
+
+#include <pxr/imaging/hgi/hgi.h>
+#include <pxr/imaging/hgi/texture.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesDisplayDriver final : public CCL_NS::DisplayDriver {
+ public:
+ HdCyclesDisplayDriver(HdCyclesSession *renderParam, Hgi *hgi);
+ ~HdCyclesDisplayDriver();
+
+ private:
+ void next_tile_begin() override;
+
+ bool update_begin(const Params &params, int texture_width, int texture_height) override;
+ void update_end() override;
+
+ void flush() override;
+
+ CCL_NS::half4 *map_texture_buffer() override;
+ void unmap_texture_buffer() override;
+
+ GraphicsInterop graphics_interop_get() override;
+
+ void graphics_interop_activate() override;
+ void graphics_interop_deactivate() override;
+
+ void clear() override;
+
+ void draw(const Params &params) override;
+
+ HdCyclesSession *const _renderParam;
+ Hgi *const _hgi;
+
+#ifdef _WIN32
+ void *hdc_ = nullptr;
+ void *gl_context_ = nullptr;
+#endif
+
+ CCL_NS::thread_mutex mutex_;
+
+ PXR_NS::HgiTextureHandle texture_;
+ unsigned int gl_pbo_id_ = 0;
+ CCL_NS::int2 pbo_size_ = CCL_NS::make_int2(0, 0);
+ bool need_update_ = false;
+ std::atomic_bool need_clear_ = false;
+
+ void *gl_render_sync_ = nullptr;
+ void *gl_upload_sync_ = nullptr;
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/field.cpp b/intern/cycles/hydra/field.cpp
new file mode 100644
index 00000000000..8b92ddb6f1f
--- /dev/null
+++ b/intern/cycles/hydra/field.cpp
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/field.h"
+#include "hydra/session.h"
+#include "scene/image_vdb.h"
+#include "scene/scene.h"
+
+#include <pxr/imaging/hd/sceneDelegate.h>
+#include <pxr/usd/sdf/assetPath.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+// clang-format off
+TF_DEFINE_PRIVATE_TOKENS(_tokens,
+ (fieldName)
+);
+// clang-format on
+
+#ifdef WITH_OPENVDB
+class HdCyclesVolumeLoader : public VDBImageLoader {
+ public:
+ HdCyclesVolumeLoader(const std::string &filePath, const std::string &gridName)
+ : VDBImageLoader(gridName)
+ {
+ openvdb::io::File file(filePath);
+ file.setCopyMaxBytes(0);
+ if (file.open()) {
+ grid = file.readGrid(gridName);
+ }
+ }
+};
+#endif
+
+HdCyclesField::HdCyclesField(const SdfPath &bprimId, const TfToken &typeId) : HdField(bprimId)
+{
+}
+
+HdCyclesField::~HdCyclesField()
+{
+}
+
+HdDirtyBits HdCyclesField::GetInitialDirtyBitsMask() const
+{
+ return DirtyBits::DirtyParams;
+}
+
+void HdCyclesField::Sync(HdSceneDelegate *sceneDelegate,
+ HdRenderParam *renderParam,
+ HdDirtyBits *dirtyBits)
+{
+#ifdef WITH_OPENVDB
+ VtValue value;
+ const SdfPath &id = GetId();
+
+ if (*dirtyBits & DirtyBits::DirtyParams) {
+ value = sceneDelegate->Get(id, HdFieldTokens->filePath);
+ if (value.IsHolding<SdfAssetPath>()) {
+ std::string filename = value.UncheckedGet<SdfAssetPath>().GetResolvedPath();
+ if (filename.empty()) {
+ filename = value.UncheckedGet<SdfAssetPath>().GetAssetPath();
+ }
+
+# if PXR_VERSION >= 2108
+ value = sceneDelegate->Get(id, HdFieldTokens->fieldName);
+# else
+ value = sceneDelegate->Get(id, _tokens->fieldName);
+# endif
+ if (value.IsHolding<TfToken>()) {
+ ImageLoader *const loader = new HdCyclesVolumeLoader(
+ filename, value.UncheckedGet<TfToken>().GetString());
+
+ const SceneLock lock(renderParam);
+
+ ImageParams params;
+ params.frame = 0.0f;
+
+ _handle = lock.scene->image_manager->add_image(loader, params, false);
+ }
+ }
+ }
+#endif
+
+ *dirtyBits = DirtyBits::Clean;
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/field.h b/intern/cycles/hydra/field.h
new file mode 100644
index 00000000000..14cd9468761
--- /dev/null
+++ b/intern/cycles/hydra/field.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+#include "scene/image.h"
+
+#include <pxr/imaging/hd/field.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesField final : public PXR_NS::HdField {
+ public:
+ HdCyclesField(const PXR_NS::SdfPath &bprimId, const PXR_NS::TfToken &typeId);
+ ~HdCyclesField() override;
+
+ PXR_NS::HdDirtyBits GetInitialDirtyBitsMask() const override;
+
+ void Sync(PXR_NS::HdSceneDelegate *sceneDelegate,
+ PXR_NS::HdRenderParam *renderParam,
+ PXR_NS::HdDirtyBits *dirtyBits) override;
+
+ CCL_NS::ImageHandle GetImageHandle() const
+ {
+ return _handle;
+ }
+
+ private:
+ CCL_NS::ImageHandle _handle;
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/geometry.h b/intern/cycles/hydra/geometry.h
new file mode 100644
index 00000000000..1a516ed691d
--- /dev/null
+++ b/intern/cycles/hydra/geometry.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+
+#include <pxr/imaging/hd/rprim.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+template<typename Base, typename CyclesBase> class HdCyclesGeometry : public Base {
+ public:
+ HdCyclesGeometry(const PXR_NS::SdfPath &rprimId
+#if PXR_VERSION < 2102
+ ,
+ const PXR_NS::SdfPath &instancerId
+#endif
+ );
+
+ void Sync(PXR_NS::HdSceneDelegate *sceneDelegate,
+ PXR_NS::HdRenderParam *renderParam,
+ PXR_NS::HdDirtyBits *dirtyBits,
+ const PXR_NS::TfToken &reprToken) override;
+
+ PXR_NS::HdDirtyBits GetInitialDirtyBitsMask() const override;
+
+ virtual void Finalize(PXR_NS::HdRenderParam *renderParam) override;
+
+ protected:
+ void _InitRepr(const PXR_NS::TfToken &reprToken, PXR_NS::HdDirtyBits *dirtyBits) override;
+
+ PXR_NS::HdDirtyBits _PropagateDirtyBits(PXR_NS::HdDirtyBits bits) const override;
+
+ virtual void Populate(PXR_NS::HdSceneDelegate *sceneDelegate,
+ PXR_NS::HdDirtyBits dirtyBits,
+ bool &rebuild) = 0;
+
+ PXR_NS::HdInterpolation GetPrimvarInterpolation(PXR_NS::HdSceneDelegate *sceneDelegate,
+ const PXR_NS::TfToken &name) const;
+
+ CyclesBase *_geom = nullptr;
+ std::vector<CCL_NS::Object *> _instances;
+
+ private:
+ void Initialize(PXR_NS::HdRenderParam *renderParam);
+
+ void InitializeInstance(int index);
+
+ PXR_NS::GfMatrix4d _geomTransform;
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/geometry.inl b/intern/cycles/hydra/geometry.inl
new file mode 100644
index 00000000000..007fc6f2667
--- /dev/null
+++ b/intern/cycles/hydra/geometry.inl
@@ -0,0 +1,247 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/attribute.h"
+#include "hydra/geometry.h"
+#include "hydra/instancer.h"
+#include "hydra/material.h"
+#include "hydra/session.h"
+#include "scene/geometry.h"
+#include "scene/object.h"
+#include "scene/scene.h"
+#include "util/hash.h"
+
+#include <pxr/imaging/hd/sceneDelegate.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+extern Transform convert_transform(const GfMatrix4d &matrix);
+
+template<typename Base, typename CyclesBase>
+HdCyclesGeometry<Base, CyclesBase>::HdCyclesGeometry(const SdfPath &rprimId
+#if PXR_VERSION < 2102
+ ,
+ const SdfPath &instancerId
+#endif
+ )
+ : Base(rprimId
+#if PXR_VERSION < 2102
+
+ ,
+ instancerId
+#endif
+ ),
+ _geomTransform(1.0)
+{
+}
+
+template<typename Base, typename CyclesBase>
+void HdCyclesGeometry<Base, CyclesBase>::_InitRepr(const TfToken &reprToken,
+ HdDirtyBits *dirtyBits)
+{
+ TF_UNUSED(reprToken);
+ TF_UNUSED(dirtyBits);
+}
+
+template<typename Base, typename CyclesBase>
+HdDirtyBits HdCyclesGeometry<Base, CyclesBase>::GetInitialDirtyBitsMask() const
+{
+ return HdChangeTracker::DirtyPrimID | HdChangeTracker::DirtyTransform |
+ HdChangeTracker::DirtyMaterialId | HdChangeTracker::DirtyVisibility |
+ HdChangeTracker::DirtyInstancer;
+}
+
+template<typename Base, typename CyclesBase>
+HdDirtyBits HdCyclesGeometry<Base, CyclesBase>::_PropagateDirtyBits(HdDirtyBits bits) const
+{
+ return bits;
+}
+
+template<typename Base, typename CyclesBase>
+void HdCyclesGeometry<Base, CyclesBase>::Sync(HdSceneDelegate *sceneDelegate,
+ HdRenderParam *renderParam,
+ HdDirtyBits *dirtyBits,
+ const TfToken &reprToken)
+{
+ TF_UNUSED(reprToken);
+
+ if (*dirtyBits == HdChangeTracker::Clean) {
+ return;
+ }
+
+ Initialize(renderParam);
+
+#if PXR_VERSION >= 2102
+ Base::_UpdateInstancer(sceneDelegate, dirtyBits);
+ HdInstancer::_SyncInstancerAndParents(sceneDelegate->GetRenderIndex(), Base::GetInstancerId());
+#endif
+ Base::_UpdateVisibility(sceneDelegate, dirtyBits);
+
+ const SceneLock lock(renderParam);
+
+ if (*dirtyBits & HdChangeTracker::DirtyMaterialId) {
+#if HD_API_VERSION >= 37 && PXR_VERSION >= 2105
+ Base::SetMaterialId(sceneDelegate->GetMaterialId(Base::GetId()));
+#else
+ Base::_SetMaterialId(sceneDelegate->GetRenderIndex().GetChangeTracker(),
+ sceneDelegate->GetMaterialId(Base::GetId()));
+#endif
+
+ const auto material = static_cast<const HdCyclesMaterial *>(
+ sceneDelegate->GetRenderIndex().GetSprim(HdPrimTypeTokens->material,
+ Base::GetMaterialId()));
+
+ array<Node *> usedShaders(1);
+ if (material && material->GetCyclesShader()) {
+ usedShaders[0] = material->GetCyclesShader();
+ }
+ else {
+ usedShaders[0] = lock.scene->default_surface;
+ }
+
+ for (Node *shader : usedShaders) {
+ static_cast<Shader *>(shader)->tag_used(lock.scene);
+ }
+
+ _geom->set_used_shaders(usedShaders);
+ }
+
+ const SdfPath &id = Base::GetId();
+
+ if (HdChangeTracker::IsPrimIdDirty(*dirtyBits, id)) {
+ // This needs to be corrected in the AOV
+ _instances[0]->set_pass_id(Base::GetPrimId() + 1);
+ }
+
+ if (HdChangeTracker::IsTransformDirty(*dirtyBits, id)) {
+ _geomTransform = sceneDelegate->GetTransform(id);
+ }
+
+ if (HdChangeTracker::IsTransformDirty(*dirtyBits, id) ||
+ HdChangeTracker::IsInstancerDirty(*dirtyBits, id)) {
+ const auto instancer = static_cast<HdCyclesInstancer *>(
+ sceneDelegate->GetRenderIndex().GetInstancer(Base::GetInstancerId()));
+
+ // Make sure the first object attribute is the instanceId
+ assert(_instances[0]->attributes.size() >= 1 &&
+ _instances[0]->attributes.front().name() == HdAovTokens->instanceId.GetString());
+
+ VtMatrix4dArray transforms;
+ if (instancer) {
+ transforms = instancer->ComputeInstanceTransforms(id);
+ _instances[0]->attributes.front() = ParamValue(HdAovTokens->instanceId.GetString(), +0.0f);
+ }
+ else {
+ // Default to a single instance with an identity transform
+ transforms.push_back(GfMatrix4d(1.0));
+ _instances[0]->attributes.front() = ParamValue(HdAovTokens->instanceId.GetString(), -1.0f);
+ }
+
+ const size_t oldSize = _instances.size();
+ const size_t newSize = transforms.size();
+
+ // Resize instance list
+ for (size_t i = newSize; i < oldSize; ++i) {
+ lock.scene->delete_node(_instances[i]);
+ }
+ _instances.resize(newSize);
+ for (size_t i = oldSize; i < newSize; ++i) {
+ _instances[i] = lock.scene->create_node<Object>();
+ InitializeInstance(static_cast<int>(i));
+ }
+
+ // Update transforms of all instances
+ for (size_t i = 0; i < transforms.size(); ++i) {
+ const Transform tfm = convert_transform(_geomTransform * transforms[i]);
+ _instances[i]->set_tfm(tfm);
+ }
+ }
+
+ if (HdChangeTracker::IsVisibilityDirty(*dirtyBits, id)) {
+ for (Object *instance : _instances) {
+ instance->set_visibility(Base::IsVisible() ? ~0 : 0);
+ }
+ }
+
+ // Must happen after material ID update, so that attribute decisions can be made
+ // based on it (e.g. check whether an attribute is actually needed)
+ bool rebuild = false;
+ Populate(sceneDelegate, *dirtyBits, rebuild);
+
+ if (_geom->is_modified() || rebuild) {
+ _geom->tag_update(lock.scene, rebuild);
+ }
+
+ for (Object *instance : _instances) {
+ instance->tag_update(lock.scene);
+ }
+
+ *dirtyBits = HdChangeTracker::Clean;
+}
+
+template<typename Base, typename CyclesBase>
+void HdCyclesGeometry<Base, CyclesBase>::Finalize(HdRenderParam *renderParam)
+{
+ if (!_geom && _instances.empty()) {
+ return;
+ }
+
+ const SceneLock lock(renderParam);
+
+ lock.scene->delete_node(_geom);
+ _geom = nullptr;
+
+ lock.scene->delete_nodes(set<Object *>(_instances.begin(), _instances.end()));
+ _instances.clear();
+ _instances.shrink_to_fit();
+}
+
+template<typename Base, typename CyclesBase>
+void HdCyclesGeometry<Base, CyclesBase>::Initialize(HdRenderParam *renderParam)
+{
+ if (_geom) {
+ return;
+ }
+
+ const SceneLock lock(renderParam);
+
+ // Create geometry
+ _geom = lock.scene->create_node<CyclesBase>();
+ _geom->name = Base::GetId().GetString();
+
+ // Create default instance
+ _instances.push_back(lock.scene->create_node<Object>());
+ InitializeInstance(0);
+}
+
+template<typename Base, typename CyclesBase>
+void HdCyclesGeometry<Base, CyclesBase>::InitializeInstance(int index)
+{
+ Object *instance = _instances[index];
+ instance->set_geometry(_geom);
+
+ instance->attributes.emplace_back(HdAovTokens->instanceId.GetString(),
+ _instances.size() == 1 ? -1.0f : static_cast<float>(index));
+
+ instance->set_color(make_float3(0.8f, 0.8f, 0.8f));
+ instance->set_random_id(hash_uint2(hash_string(_geom->name.c_str()), index));
+}
+
+template<typename Base, typename CyclesBase>
+HdInterpolation HdCyclesGeometry<Base, CyclesBase>::GetPrimvarInterpolation(
+ HdSceneDelegate *sceneDelegate, const TfToken &name) const
+{
+ for (int i = 0; i < HdInterpolationCount; ++i) {
+ for (const HdPrimvarDescriptor &desc :
+ Base::GetPrimvarDescriptors(sceneDelegate, static_cast<HdInterpolation>(i))) {
+ if (desc.name == name) {
+ return static_cast<HdInterpolation>(i);
+ }
+ }
+ }
+
+ return HdInterpolationCount;
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/instancer.cpp b/intern/cycles/hydra/instancer.cpp
new file mode 100644
index 00000000000..ade5141cd19
--- /dev/null
+++ b/intern/cycles/hydra/instancer.cpp
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/instancer.h"
+
+#include <pxr/base/gf/quatd.h>
+#include <pxr/imaging/hd/sceneDelegate.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+HdCyclesInstancer::HdCyclesInstancer(HdSceneDelegate *delegate,
+ const SdfPath &instancerId
+#if PXR_VERSION <= 2011
+ ,
+ const SdfPath &parentId
+#endif
+ )
+ : HdInstancer(delegate,
+ instancerId
+#if PXR_VERSION <= 2011
+ ,
+ parentId
+#endif
+ )
+{
+}
+
+HdCyclesInstancer::~HdCyclesInstancer()
+{
+}
+
+#if PXR_VERSION > 2011
+void HdCyclesInstancer::Sync(HdSceneDelegate *sceneDelegate,
+ HdRenderParam *renderParam,
+ HdDirtyBits *dirtyBits)
+{
+ _UpdateInstancer(sceneDelegate, dirtyBits);
+
+ if (HdChangeTracker::IsAnyPrimvarDirty(*dirtyBits, GetId())) {
+ SyncPrimvars();
+ }
+}
+#endif
+
+void HdCyclesInstancer::SyncPrimvars()
+{
+ HdSceneDelegate *const sceneDelegate = GetDelegate();
+ const HdDirtyBits dirtyBits =
+ sceneDelegate->GetRenderIndex().GetChangeTracker().GetInstancerDirtyBits(GetId());
+
+ for (const HdPrimvarDescriptor &desc :
+ sceneDelegate->GetPrimvarDescriptors(GetId(), HdInterpolationInstance)) {
+ if (!HdChangeTracker::IsPrimvarDirty(dirtyBits, GetId(), desc.name)) {
+ continue;
+ }
+
+ const VtValue value = sceneDelegate->Get(GetId(), desc.name);
+ if (value.IsEmpty()) {
+ continue;
+ }
+
+ if (desc.name == HdInstancerTokens->translate) {
+ _translate = value.Get<VtVec3fArray>();
+ }
+ else if (desc.name == HdInstancerTokens->rotate) {
+ _rotate = value.Get<VtVec4fArray>();
+ }
+ else if (desc.name == HdInstancerTokens->scale) {
+ _scale = value.Get<VtVec3fArray>();
+ }
+ else if (desc.name == HdInstancerTokens->instanceTransform) {
+ _instanceTransform = value.Get<VtMatrix4dArray>();
+ }
+ }
+
+ sceneDelegate->GetRenderIndex().GetChangeTracker().MarkInstancerClean(GetId());
+}
+
+VtMatrix4dArray HdCyclesInstancer::ComputeInstanceTransforms(const SdfPath &prototypeId)
+{
+#if PXR_VERSION <= 2011
+ SyncPrimvars();
+#endif
+
+ const VtIntArray instanceIndices = GetDelegate()->GetInstanceIndices(GetId(), prototypeId);
+ const GfMatrix4d instanceTransform = GetDelegate()->GetInstancerTransform(GetId());
+
+ VtMatrix4dArray transforms;
+ transforms.reserve(instanceIndices.size());
+
+ for (int index : instanceIndices) {
+ GfMatrix4d transform = instanceTransform;
+
+ if (index < _translate.size()) {
+ GfMatrix4d translateMat(1);
+ translateMat.SetTranslate(_translate[index]);
+ transform *= translateMat;
+ }
+
+ if (index < _rotate.size()) {
+ GfMatrix4d rotateMat(1);
+ const GfVec4f &quat = _rotate[index];
+ rotateMat.SetRotate(GfQuatd(quat[0], quat[1], quat[2], quat[3]));
+ transform *= rotateMat;
+ }
+
+ if (index < _scale.size()) {
+ GfMatrix4d scaleMat(1);
+ scaleMat.SetScale(_scale[index]);
+ transform *= scaleMat;
+ }
+
+ if (index < _instanceTransform.size()) {
+ transform *= _instanceTransform[index];
+ }
+
+ transforms.push_back(transform);
+ }
+
+ VtMatrix4dArray resultTransforms;
+
+ if (const auto instancer = static_cast<HdCyclesInstancer *>(
+ GetDelegate()->GetRenderIndex().GetInstancer(GetParentId()))) {
+ for (const GfMatrix4d &parentTransform : instancer->ComputeInstanceTransforms(GetId())) {
+ for (const GfMatrix4d &localTransform : transforms) {
+ resultTransforms.push_back(parentTransform * localTransform);
+ }
+ }
+ }
+ else {
+ resultTransforms = std::move(transforms);
+ }
+
+ return resultTransforms;
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/instancer.h b/intern/cycles/hydra/instancer.h
new file mode 100644
index 00000000000..ade1dfba8ee
--- /dev/null
+++ b/intern/cycles/hydra/instancer.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+
+#include <pxr/base/gf/matrix4d.h>
+#include <pxr/base/gf/vec3f.h>
+#include <pxr/base/gf/vec4f.h>
+#include <pxr/base/vt/array.h>
+#include <pxr/imaging/hd/instancer.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesInstancer final : public PXR_NS::HdInstancer {
+ public:
+ HdCyclesInstancer(PXR_NS::HdSceneDelegate *delegate,
+ const PXR_NS::SdfPath &instancerId
+#if PXR_VERSION <= 2011
+ ,
+ const PXR_NS::SdfPath &parentId
+#endif
+ );
+ ~HdCyclesInstancer() override;
+
+#if PXR_VERSION > 2011
+ void Sync(PXR_NS::HdSceneDelegate *sceneDelegate,
+ PXR_NS::HdRenderParam *renderParam,
+ PXR_NS::HdDirtyBits *dirtyBits) override;
+#endif
+
+ PXR_NS::VtMatrix4dArray ComputeInstanceTransforms(const PXR_NS::SdfPath &prototypeId);
+
+ private:
+ void SyncPrimvars();
+
+ PXR_NS::VtVec3fArray _translate;
+ PXR_NS::VtVec4fArray _rotate;
+ PXR_NS::VtVec3fArray _scale;
+ PXR_NS::VtMatrix4dArray _instanceTransform;
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/light.cpp b/intern/cycles/hydra/light.cpp
new file mode 100644
index 00000000000..b691da0d6a6
--- /dev/null
+++ b/intern/cycles/hydra/light.cpp
@@ -0,0 +1,399 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/light.h"
+#include "hydra/session.h"
+#include "scene/light.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+#include "util/hash.h"
+
+#include <pxr/imaging/hd/sceneDelegate.h>
+#include <pxr/usd/sdf/assetPath.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+extern Transform convert_transform(const GfMatrix4d &matrix);
+
+// clang-format off
+TF_DEFINE_PRIVATE_TOKENS(_tokens,
+ (visibleInPrimaryRay)
+);
+// clang-format on
+
+HdCyclesLight::HdCyclesLight(const SdfPath &sprimId, const TfToken &lightType)
+ : HdLight(sprimId), _lightType(lightType)
+{
+}
+
+HdCyclesLight::~HdCyclesLight()
+{
+}
+
+HdDirtyBits HdCyclesLight::GetInitialDirtyBitsMask() const
+{
+ return DirtyBits::DirtyTransform | DirtyBits::DirtyParams;
+}
+
+void HdCyclesLight::Sync(HdSceneDelegate *sceneDelegate,
+ HdRenderParam *renderParam,
+ HdDirtyBits *dirtyBits)
+{
+ if (*dirtyBits == DirtyBits::Clean) {
+ return;
+ }
+
+ Initialize(renderParam);
+
+ const SceneLock lock(renderParam);
+
+ VtValue value;
+ const SdfPath &id = GetId();
+
+ if (*dirtyBits & DirtyBits::DirtyTransform) {
+#if PXR_VERSION >= 2011
+ const Transform tfm = convert_transform(sceneDelegate->GetTransform(id));
+#else
+ const Transform tfm = convert_transform(
+ sceneDelegate->GetLightParamValue(id, HdTokens->transform).Get<GfMatrix4d>());
+#endif
+ _light->set_tfm(tfm);
+
+ _light->set_co(transform_get_column(&tfm, 3));
+ _light->set_dir(-transform_get_column(&tfm, 2));
+
+ if (_lightType == HdPrimTypeTokens->diskLight || _lightType == HdPrimTypeTokens->rectLight) {
+ _light->set_axisu(transform_get_column(&tfm, 0));
+ _light->set_axisv(transform_get_column(&tfm, 1));
+ }
+ }
+
+ if (*dirtyBits & DirtyBits::DirtyParams) {
+ float3 strength = make_float3(1.0f, 1.0f, 1.0f);
+
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->color);
+ if (!value.IsEmpty()) {
+ const auto color = value.Get<GfVec3f>();
+ strength = make_float3(color[0], color[1], color[2]);
+ }
+
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->exposure);
+ if (!value.IsEmpty()) {
+ strength *= exp2(value.Get<float>());
+ }
+
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->intensity);
+ if (!value.IsEmpty()) {
+ strength *= value.Get<float>();
+ }
+
+ // Cycles lights are normalized by default, so need to scale intensity if Hydra light is not
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->normalize);
+ const bool normalize = value.IsHolding<bool>() && value.UncheckedGet<bool>();
+
+ value = sceneDelegate->GetLightParamValue(id, _tokens->visibleInPrimaryRay);
+ if (!value.IsEmpty()) {
+ _light->set_use_camera(value.Get<bool>());
+ }
+
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->shadowEnable);
+ if (!value.IsEmpty()) {
+ _light->set_cast_shadow(value.Get<bool>());
+ }
+
+ if (_lightType == HdPrimTypeTokens->distantLight) {
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->angle);
+ if (!value.IsEmpty()) {
+ _light->set_angle(GfDegreesToRadians(value.Get<float>()));
+ }
+ }
+ else if (_lightType == HdPrimTypeTokens->diskLight) {
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->radius);
+ if (!value.IsEmpty()) {
+ const float size = value.Get<float>() * 2.0f;
+ _light->set_sizeu(size);
+ _light->set_sizev(size);
+ }
+
+ if (!normalize) {
+ const float radius = _light->get_sizeu() * 0.5f;
+ strength *= M_PI * radius * radius;
+ }
+ }
+ else if (_lightType == HdPrimTypeTokens->rectLight) {
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->width);
+ if (!value.IsEmpty()) {
+ _light->set_sizeu(value.Get<float>());
+ }
+
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->height);
+ if (!value.IsEmpty()) {
+ _light->set_sizev(value.Get<float>());
+ }
+
+ if (!normalize) {
+ strength *= _light->get_sizeu() * _light->get_sizeu();
+ }
+ }
+ else if (_lightType == HdPrimTypeTokens->sphereLight) {
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->radius);
+ if (!value.IsEmpty()) {
+ _light->set_size(value.Get<float>());
+ }
+
+ bool shaping = false;
+
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->shapingConeAngle);
+ if (!value.IsEmpty()) {
+ _light->set_spot_angle(GfDegreesToRadians(value.Get<float>()) * 2.0f);
+ shaping = true;
+ }
+
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->shapingConeSoftness);
+ if (!value.IsEmpty()) {
+ _light->set_spot_smooth(value.Get<float>());
+ shaping = true;
+ }
+
+ _light->set_light_type(shaping ? LIGHT_SPOT : LIGHT_POINT);
+
+ if (!normalize) {
+ const float radius = _light->get_size();
+ strength *= M_PI * radius * radius * 4.0f;
+ }
+ }
+
+ const bool visible = sceneDelegate->GetVisible(id);
+ // Disable invisible lights by zeroing the strength
+ // So 'LightManager::test_enabled_lights' updates the enabled flag correctly
+ if (!visible) {
+ strength = zero_float3();
+ }
+
+ _light->set_strength(strength);
+ _light->set_is_enabled(visible);
+
+ PopulateShaderGraph(sceneDelegate);
+ }
+ // Need to update shader graph when transform changes in case transform was baked into it
+ else if (_light->tfm_is_modified() && (_lightType == HdPrimTypeTokens->domeLight ||
+ _light->get_shader()->has_surface_spatial_varying)) {
+ PopulateShaderGraph(sceneDelegate);
+ }
+
+ if (_light->is_modified()) {
+ _light->tag_update(lock.scene);
+ }
+
+ *dirtyBits = DirtyBits::Clean;
+}
+
+void HdCyclesLight::PopulateShaderGraph(HdSceneDelegate *sceneDelegate)
+{
+ auto graph = new ShaderGraph();
+ ShaderNode *outputNode = nullptr;
+
+ if (_lightType == HdPrimTypeTokens->domeLight) {
+ BackgroundNode *bgNode = graph->create_node<BackgroundNode>();
+ // Bake strength into shader graph, since only the shader is used for background lights
+ bgNode->set_color(_light->get_strength());
+ graph->add(bgNode);
+
+ graph->connect(bgNode->output("Background"), graph->output()->input("Surface"));
+
+ outputNode = bgNode;
+ }
+ else {
+ EmissionNode *emissionNode = graph->create_node<EmissionNode>();
+ emissionNode->set_color(one_float3());
+ emissionNode->set_strength(1.0f);
+ graph->add(emissionNode);
+
+ graph->connect(emissionNode->output("Emission"), graph->output()->input("Surface"));
+
+ outputNode = emissionNode;
+ }
+
+ VtValue value;
+ const SdfPath &id = GetId();
+ bool hasSpatialVarying = false;
+ bool hasColorTemperature = false;
+
+ if (sceneDelegate != nullptr) {
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->enableColorTemperature);
+ const bool enableColorTemperature = value.IsHolding<bool>() && value.UncheckedGet<bool>();
+
+ if (enableColorTemperature) {
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->colorTemperature);
+ if (value.IsHolding<float>()) {
+ BlackbodyNode *blackbodyNode = graph->create_node<BlackbodyNode>();
+ blackbodyNode->set_temperature(value.UncheckedGet<float>());
+ graph->add(blackbodyNode);
+
+ if (_lightType == HdPrimTypeTokens->domeLight) {
+ VectorMathNode *mathNode = graph->create_node<VectorMathNode>();
+ mathNode->set_math_type(NODE_VECTOR_MATH_MULTIPLY);
+ mathNode->set_vector2(_light->get_strength());
+ graph->add(mathNode);
+
+ graph->connect(blackbodyNode->output("Color"), mathNode->input("Vector1"));
+ graph->connect(mathNode->output("Vector"), outputNode->input("Color"));
+ }
+ else {
+ graph->connect(blackbodyNode->output("Color"), outputNode->input("Color"));
+ }
+
+ hasColorTemperature = true;
+ }
+ }
+
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->shapingIesFile);
+ if (value.IsHolding<SdfAssetPath>()) {
+ std::string filename = value.UncheckedGet<SdfAssetPath>().GetResolvedPath();
+ if (filename.empty()) {
+ filename = value.UncheckedGet<SdfAssetPath>().GetAssetPath();
+ }
+
+ TextureCoordinateNode *coordNode = graph->create_node<TextureCoordinateNode>();
+ coordNode->set_ob_tfm(_light->get_tfm());
+ coordNode->set_use_transform(true);
+ graph->add(coordNode);
+
+ IESLightNode *iesNode = graph->create_node<IESLightNode>();
+ iesNode->set_filename(ustring(filename));
+
+ graph->connect(coordNode->output("Normal"), iesNode->input("Vector"));
+ graph->connect(iesNode->output("Fac"), outputNode->input("Strength"));
+
+ hasSpatialVarying = true;
+ }
+
+ value = sceneDelegate->GetLightParamValue(id, HdLightTokens->textureFile);
+ if (value.IsHolding<SdfAssetPath>()) {
+ std::string filename = value.UncheckedGet<SdfAssetPath>().GetResolvedPath();
+ if (filename.empty()) {
+ filename = value.UncheckedGet<SdfAssetPath>().GetAssetPath();
+ }
+
+ ImageSlotTextureNode *textureNode = nullptr;
+ if (_lightType == HdPrimTypeTokens->domeLight) {
+ Transform tfm = _light->get_tfm();
+ transform_set_column(&tfm, 3, zero_float3()); // Remove translation
+
+ TextureCoordinateNode *coordNode = graph->create_node<TextureCoordinateNode>();
+ coordNode->set_ob_tfm(tfm);
+ coordNode->set_use_transform(true);
+ graph->add(coordNode);
+
+ textureNode = graph->create_node<EnvironmentTextureNode>();
+ static_cast<EnvironmentTextureNode *>(textureNode)->set_filename(ustring(filename));
+ graph->add(textureNode);
+
+ graph->connect(coordNode->output("Object"), textureNode->input("Vector"));
+
+ hasSpatialVarying = true;
+ }
+ else {
+ GeometryNode *coordNode = graph->create_node<GeometryNode>();
+ graph->add(coordNode);
+
+ textureNode = graph->create_node<ImageTextureNode>();
+ static_cast<ImageTextureNode *>(textureNode)->set_filename(ustring(filename));
+ graph->add(textureNode);
+
+ graph->connect(coordNode->output("Parametric"), textureNode->input("Vector"));
+ }
+
+ if (hasColorTemperature) {
+ VectorMathNode *mathNode = graph->create_node<VectorMathNode>();
+ mathNode->set_math_type(NODE_VECTOR_MATH_MULTIPLY);
+ graph->add(mathNode);
+
+ graph->connect(textureNode->output("Color"), mathNode->input("Vector1"));
+ ShaderInput *const outputNodeInput = outputNode->input("Color");
+ graph->connect(outputNodeInput->link, mathNode->input("Vector2"));
+ graph->disconnect(outputNodeInput);
+ graph->connect(mathNode->output("Vector"), outputNodeInput);
+ }
+ else if (_lightType == HdPrimTypeTokens->domeLight) {
+ VectorMathNode *mathNode = graph->create_node<VectorMathNode>();
+ mathNode->set_math_type(NODE_VECTOR_MATH_MULTIPLY);
+ mathNode->set_vector2(_light->get_strength());
+ graph->add(mathNode);
+
+ graph->connect(textureNode->output("Color"), mathNode->input("Vector1"));
+ graph->connect(mathNode->output("Vector"), outputNode->input("Color"));
+ }
+ else {
+ graph->connect(textureNode->output("Color"), outputNode->input("Color"));
+ }
+ }
+ }
+
+ Shader *const shader = _light->get_shader();
+ shader->set_graph(graph);
+ shader->tag_update((Scene *)_light->get_owner());
+
+ shader->has_surface_spatial_varying = hasSpatialVarying;
+}
+
+void HdCyclesLight::Finalize(HdRenderParam *renderParam)
+{
+ if (!_light) {
+ return;
+ }
+
+ const SceneLock lock(renderParam);
+
+ lock.scene->delete_node(_light);
+ _light = nullptr;
+}
+
+void HdCyclesLight::Initialize(HdRenderParam *renderParam)
+{
+ if (_light) {
+ return;
+ }
+
+ const SceneLock lock(renderParam);
+
+ _light = lock.scene->create_node<Light>();
+ _light->name = GetId().GetString();
+
+ _light->set_random_id(hash_uint2(hash_string(_light->name.c_str()), 0));
+
+ if (_lightType == HdPrimTypeTokens->domeLight) {
+ _light->set_light_type(LIGHT_BACKGROUND);
+ }
+ else if (_lightType == HdPrimTypeTokens->distantLight) {
+ _light->set_light_type(LIGHT_DISTANT);
+ }
+ else if (_lightType == HdPrimTypeTokens->diskLight) {
+ _light->set_light_type(LIGHT_AREA);
+ _light->set_round(true);
+ _light->set_size(1.0f);
+ }
+ else if (_lightType == HdPrimTypeTokens->rectLight) {
+ _light->set_light_type(LIGHT_AREA);
+ _light->set_round(false);
+ _light->set_size(1.0f);
+ }
+ else if (_lightType == HdPrimTypeTokens->sphereLight) {
+ _light->set_light_type(LIGHT_POINT);
+ _light->set_size(1.0f);
+ }
+
+ _light->set_use_mis(true);
+ _light->set_use_camera(false);
+
+ Shader *const shader = lock.scene->create_node<Shader>();
+ _light->set_shader(shader);
+
+ // Create default shader graph
+ PopulateShaderGraph(nullptr);
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/light.h b/intern/cycles/hydra/light.h
new file mode 100644
index 00000000000..9230bc5730e
--- /dev/null
+++ b/intern/cycles/hydra/light.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+
+#include <pxr/imaging/hd/light.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesLight final : public PXR_NS::HdLight {
+ public:
+ HdCyclesLight(const PXR_NS::SdfPath &sprimId, const PXR_NS::TfToken &lightType);
+ ~HdCyclesLight() override;
+
+ PXR_NS::HdDirtyBits GetInitialDirtyBitsMask() const override;
+
+ void Sync(PXR_NS::HdSceneDelegate *sceneDelegate,
+ PXR_NS::HdRenderParam *renderParam,
+ PXR_NS::HdDirtyBits *dirtyBits) override;
+
+ void Finalize(PXR_NS::HdRenderParam *renderParam) override;
+
+ private:
+ void Initialize(PXR_NS::HdRenderParam *renderParam);
+
+ void PopulateShaderGraph(PXR_NS::HdSceneDelegate *sceneDelegate);
+
+ CCL_NS::Light *_light = nullptr;
+ PXR_NS::TfToken _lightType;
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/material.cpp b/intern/cycles/hydra/material.cpp
new file mode 100644
index 00000000000..a595102a605
--- /dev/null
+++ b/intern/cycles/hydra/material.cpp
@@ -0,0 +1,589 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/material.h"
+#include "hydra/node_util.h"
+#include "hydra/session.h"
+#include "scene/scene.h"
+#include "scene/shader.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+
+#include <pxr/imaging/hd/sceneDelegate.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+// clang-format off
+TF_DEFINE_PRIVATE_TOKENS(CyclesMaterialTokens,
+ ((cyclesSurface, "cycles:surface"))
+ ((cyclesDisplacement, "cycles:displacement"))
+ ((cyclesVolume, "cycles:volume"))
+ (UsdPreviewSurface)
+ (UsdUVTexture)
+ (UsdPrimvarReader_float)
+ (UsdPrimvarReader_float2)
+ (UsdPrimvarReader_float3)
+ (UsdPrimvarReader_float4)
+ (UsdPrimvarReader_int)
+ (UsdTransform2d)
+ (a)
+ (rgb)
+ (r)
+ (g)
+ (b)
+ (result)
+ (st)
+ (wrapS)
+ (wrapT)
+ (periodic)
+);
+// clang-format on
+
+namespace {
+
+// Simple class to handle remapping of USDPreviewSurface nodes and parameters to Cycles equivalents
+class UsdToCyclesMapping {
+ using ParamMap = std::unordered_map<TfToken, ustring, TfToken::HashFunctor>;
+
+ public:
+ UsdToCyclesMapping(const char *nodeType, ParamMap paramMap)
+ : _nodeType(nodeType), _paramMap(std::move(paramMap))
+ {
+ }
+
+ ustring nodeType() const
+ {
+ return _nodeType;
+ }
+
+ virtual std::string parameterName(const TfToken &name,
+ const ShaderInput *inputConnection,
+ VtValue *value = nullptr) const
+ {
+ // UsdNode.name -> Node.input
+ // These all follow a simple pattern that we can just remap
+ // based on the name or 'Node.input' type
+ if (inputConnection) {
+ if (name == CyclesMaterialTokens->a) {
+ return "alpha";
+ }
+ if (name == CyclesMaterialTokens->rgb) {
+ return "color";
+ }
+ // TODO: Is there a better mapping than 'color'?
+ if (name == CyclesMaterialTokens->r || name == CyclesMaterialTokens->g ||
+ name == CyclesMaterialTokens->b) {
+ return "color";
+ }
+
+ if (name == CyclesMaterialTokens->result) {
+ switch (inputConnection->socket_type.type) {
+ case SocketType::BOOLEAN:
+ case SocketType::FLOAT:
+ case SocketType::INT:
+ case SocketType::UINT:
+ return "alpha";
+ case SocketType::COLOR:
+ case SocketType::VECTOR:
+ case SocketType::POINT:
+ case SocketType::NORMAL:
+ default:
+ return "color";
+ }
+ }
+ }
+
+ // Simple mapping case
+ const auto it = _paramMap.find(name);
+ return it != _paramMap.end() ? it->second.string() : name.GetString();
+ }
+
+ private:
+ const ustring _nodeType;
+ ParamMap _paramMap;
+};
+
+class UsdToCyclesTexture : public UsdToCyclesMapping {
+ public:
+ using UsdToCyclesMapping::UsdToCyclesMapping;
+
+ std::string parameterName(const TfToken &name,
+ const ShaderInput *inputConnection,
+ VtValue *value) const override
+ {
+ if (value) {
+ // Remap UsdUVTexture.wrapS and UsdUVTexture.wrapT to cycles_image_texture.extension
+ if (name == CyclesMaterialTokens->wrapS || name == CyclesMaterialTokens->wrapT) {
+ std::string valueString = VtValue::Cast<std::string>(*value).Get<std::string>();
+
+ // A value of 'repeat' in USD is equivalent to 'periodic' in Cycles
+ if (valueString == "repeat") {
+ *value = VtValue(CyclesMaterialTokens->periodic);
+ }
+
+ return "extension";
+ }
+ }
+
+ return UsdToCyclesMapping::parameterName(name, inputConnection, value);
+ }
+};
+
+class UsdToCycles {
+ const UsdToCyclesMapping UsdPreviewSurface = {
+ "principled_bsdf",
+ {
+ {TfToken("diffuseColor"), ustring("base_color")},
+ {TfToken("emissiveColor"), ustring("emission")},
+ {TfToken("specularColor"), ustring("specular")},
+ {TfToken("clearcoatRoughness"), ustring("clearcoat_roughness")},
+ {TfToken("opacity"), ustring("alpha")},
+ // opacityThreshold
+ // occlusion
+ // displacement
+ }};
+ const UsdToCyclesTexture UsdUVTexture = {
+ "image_texture",
+ {
+ {CyclesMaterialTokens->st, ustring("vector")},
+ {CyclesMaterialTokens->wrapS, ustring("extension")},
+ {CyclesMaterialTokens->wrapT, ustring("extension")},
+ {TfToken("file"), ustring("filename")},
+ {TfToken("sourceColorSpace"), ustring("colorspace")},
+ }};
+ const UsdToCyclesMapping UsdPrimvarReader = {"attribute",
+ {{TfToken("varname"), ustring("attribute")}}};
+
+ public:
+ const UsdToCyclesMapping *findUsd(const TfToken &usdNodeType)
+ {
+ if (usdNodeType == CyclesMaterialTokens->UsdPreviewSurface) {
+ return &UsdPreviewSurface;
+ }
+ if (usdNodeType == CyclesMaterialTokens->UsdUVTexture) {
+ return &UsdUVTexture;
+ }
+ if (usdNodeType == CyclesMaterialTokens->UsdPrimvarReader_float ||
+ usdNodeType == CyclesMaterialTokens->UsdPrimvarReader_float2 ||
+ usdNodeType == CyclesMaterialTokens->UsdPrimvarReader_float3 ||
+ usdNodeType == CyclesMaterialTokens->UsdPrimvarReader_float4 ||
+ usdNodeType == CyclesMaterialTokens->UsdPrimvarReader_int) {
+ return &UsdPrimvarReader;
+ }
+
+ return nullptr;
+ }
+ const UsdToCyclesMapping *findCycles(const ustring &cyclesNodeType)
+ {
+ return nullptr;
+ }
+};
+TfStaticData<UsdToCycles> sUsdToCyles;
+
+} // namespace
+
+struct HdCyclesMaterial::NodeDesc {
+ ShaderNode *node;
+ const UsdToCyclesMapping *mapping;
+};
+
+HdCyclesMaterial::HdCyclesMaterial(const SdfPath &sprimId) : HdMaterial(sprimId)
+{
+}
+
+HdCyclesMaterial::~HdCyclesMaterial()
+{
+}
+
+HdDirtyBits HdCyclesMaterial::GetInitialDirtyBitsMask() const
+{
+ return DirtyBits::DirtyResource | DirtyBits::DirtyParams;
+}
+
+void HdCyclesMaterial::Sync(HdSceneDelegate *sceneDelegate,
+ HdRenderParam *renderParam,
+ HdDirtyBits *dirtyBits)
+{
+ if (*dirtyBits == DirtyBits::Clean) {
+ return;
+ }
+
+ Initialize(renderParam);
+
+ const SceneLock lock(renderParam);
+
+ const bool dirtyParams = (*dirtyBits & DirtyBits::DirtyParams);
+ const bool dirtyResource = (*dirtyBits & DirtyBits::DirtyResource);
+
+ VtValue value;
+ const SdfPath &id = GetId();
+
+ if (dirtyResource || dirtyParams) {
+ value = sceneDelegate->GetMaterialResource(id);
+
+#if 1
+ const HdMaterialNetwork2 *network = nullptr;
+ std::unique_ptr<HdMaterialNetwork2> networkConverted;
+ if (value.IsHolding<HdMaterialNetwork2>()) {
+ network = &value.UncheckedGet<HdMaterialNetwork2>();
+ }
+ else if (value.IsHolding<HdMaterialNetworkMap>()) {
+ const auto &networkOld = value.UncheckedGet<HdMaterialNetworkMap>();
+ // In the case of only parameter updates, there is no need to waste time converting to a
+ // HdMaterialNetwork2, as supporting HdMaterialNetworkMap for parameters only is trivial.
+ if (!_nodes.empty() && !dirtyResource) {
+ for (const auto &networkEntry : networkOld.map) {
+ UpdateParameters(networkEntry.second);
+ }
+ _shader->tag_modified();
+ }
+ else {
+ networkConverted = std::make_unique<HdMaterialNetwork2>();
+ HdMaterialNetwork2ConvertFromHdMaterialNetworkMap(networkOld, networkConverted.get());
+ network = networkConverted.get();
+ }
+ }
+ else {
+ TF_RUNTIME_ERROR("Could not get a HdMaterialNetwork2.");
+ }
+
+ if (network) {
+ if (!_nodes.empty() && !dirtyResource) {
+ UpdateParameters(*network);
+ _shader->tag_modified();
+ }
+ else {
+ PopulateShaderGraph(*network);
+ }
+ }
+#endif
+ }
+
+ if (_shader->is_modified()) {
+ _shader->tag_update(lock.scene);
+ }
+
+ *dirtyBits = DirtyBits::Clean;
+}
+
+void HdCyclesMaterial::UpdateParameters(NodeDesc &nodeDesc,
+ const std::map<TfToken, VtValue> &parameters,
+ const SdfPath &nodePath)
+{
+ for (const std::pair<TfToken, VtValue> &param : parameters) {
+ VtValue value = param.second;
+
+ // See if the parameter name is in USDPreviewSurface terms, and needs to be converted
+ const UsdToCyclesMapping *inputMapping = nodeDesc.mapping;
+ const std::string inputName = inputMapping ?
+ inputMapping->parameterName(param.first, nullptr, &value) :
+ param.first.GetString();
+
+ // Find the input to write the parameter value to
+ const SocketType *input = nullptr;
+ for (const SocketType &socket : nodeDesc.node->type->inputs) {
+ if (string_iequals(socket.name.string(), inputName) || socket.ui_name == inputName) {
+ input = &socket;
+ break;
+ }
+ }
+
+ if (!input) {
+ TF_WARN("Could not find parameter '%s' on node '%s' ('%s')",
+ param.first.GetText(),
+ nodePath.GetText(),
+ nodeDesc.node->name.c_str());
+ continue;
+ }
+
+ SetNodeValue(nodeDesc.node, *input, value);
+ }
+}
+
+void HdCyclesMaterial::UpdateParameters(const HdMaterialNetwork &network)
+{
+ for (const HdMaterialNode &nodeEntry : network.nodes) {
+ const SdfPath &nodePath = nodeEntry.path;
+
+ const auto nodeIt = _nodes.find(nodePath);
+ if (nodeIt == _nodes.end()) {
+ TF_RUNTIME_ERROR("Could not update parameters on missing node '%s'", nodePath.GetText());
+ continue;
+ }
+
+ UpdateParameters(nodeIt->second, nodeEntry.parameters, nodePath);
+ }
+}
+
+void HdCyclesMaterial::UpdateParameters(const HdMaterialNetwork2 &network)
+{
+ for (const std::pair<SdfPath, HdMaterialNode2> &nodeEntry : network.nodes) {
+ const SdfPath &nodePath = nodeEntry.first;
+
+ const auto nodeIt = _nodes.find(nodePath);
+ if (nodeIt == _nodes.end()) {
+ TF_RUNTIME_ERROR("Could not update parameters on missing node '%s'", nodePath.GetText());
+ continue;
+ }
+
+ UpdateParameters(nodeIt->second, nodeEntry.second.parameters, nodePath);
+ }
+}
+
+void HdCyclesMaterial::UpdateConnections(NodeDesc &nodeDesc,
+ const HdMaterialNode2 &matNode,
+ const SdfPath &nodePath,
+ ShaderGraph *shaderGraph)
+{
+ for (const std::pair<TfToken, std::vector<HdMaterialConnection2>> &connection :
+ matNode.inputConnections) {
+ const TfToken &dstSocketName = connection.first;
+
+ const UsdToCyclesMapping *inputMapping = nodeDesc.mapping;
+ const std::string inputName = inputMapping ?
+ inputMapping->parameterName(dstSocketName, nullptr) :
+ dstSocketName.GetString();
+
+ // Find the input to connect to on the passed in node
+ ShaderInput *input = nullptr;
+ for (ShaderInput *in : nodeDesc.node->inputs) {
+ if (string_iequals(in->socket_type.name.string(), inputName)) {
+ input = in;
+ break;
+ }
+ }
+
+ if (!input) {
+ TF_WARN("Ignoring connection on '%s.%s', input '%s' was not found",
+ nodePath.GetText(),
+ dstSocketName.GetText(),
+ dstSocketName.GetText());
+ continue;
+ }
+
+ // Now find the output to connect from
+ const auto &connectedNodes = connection.second;
+ if (connectedNodes.empty()) {
+ continue;
+ }
+
+ // TODO: Hydra allows multiple connections of the same input
+ // Unsure how to handle this in Cycles, so just use the first
+ if (connectedNodes.size() > 1) {
+ TF_WARN(
+ "Ignoring multiple connections to '%s.%s'", nodePath.GetText(), dstSocketName.GetText());
+ }
+
+ const SdfPath &upstreamNodePath = connectedNodes.front().upstreamNode;
+ const TfToken &upstreamOutputName = connectedNodes.front().upstreamOutputName;
+
+ const auto srcNodeIt = _nodes.find(upstreamNodePath);
+ if (srcNodeIt == _nodes.end()) {
+ TF_WARN("Ignoring connection from '%s.%s' to '%s.%s', node '%s' was not found",
+ upstreamNodePath.GetText(),
+ upstreamOutputName.GetText(),
+ nodePath.GetText(),
+ dstSocketName.GetText(),
+ upstreamNodePath.GetText());
+ continue;
+ }
+
+ const UsdToCyclesMapping *outputMapping = srcNodeIt->second.mapping;
+ const std::string outputName = outputMapping ?
+ outputMapping->parameterName(upstreamOutputName, input) :
+ upstreamOutputName.GetString();
+
+ ShaderOutput *output = nullptr;
+ for (ShaderOutput *out : srcNodeIt->second.node->outputs) {
+ if (string_iequals(out->socket_type.name.string(), outputName)) {
+ output = out;
+ break;
+ }
+ }
+
+ if (!output) {
+ TF_WARN("Ignoring connection from '%s.%s' to '%s.%s', output '%s' was not found",
+ upstreamNodePath.GetText(),
+ upstreamOutputName.GetText(),
+ nodePath.GetText(),
+ dstSocketName.GetText(),
+ upstreamOutputName.GetText());
+ continue;
+ }
+
+ shaderGraph->connect(output, input);
+ }
+}
+
+void HdCyclesMaterial::PopulateShaderGraph(const HdMaterialNetwork2 &networkMap)
+{
+ _nodes.clear();
+
+ auto graph = new ShaderGraph();
+
+ // Iterate all the nodes first and build a complete but unconnected graph with parameters set
+ for (const std::pair<SdfPath, HdMaterialNode2> &nodeEntry : networkMap.nodes) {
+ NodeDesc nodeDesc = {};
+ const SdfPath &nodePath = nodeEntry.first;
+
+ const auto nodeIt = _nodes.find(nodePath);
+ // Create new node only if it does not exist yet
+ if (nodeIt != _nodes.end()) {
+ nodeDesc = nodeIt->second;
+ }
+ else {
+ // E.g. cycles_principled_bsdf or UsdPreviewSurface
+ const std::string &nodeTypeId = nodeEntry.second.nodeTypeId.GetString();
+
+ ustring cyclesType(nodeTypeId);
+ // Interpret a node type ID prefixed with cycles_<type> or cycles:<type> as a node of <type>
+ if (nodeTypeId.rfind("cycles", 0) == 0) {
+ cyclesType = nodeTypeId.substr(7);
+ nodeDesc.mapping = sUsdToCyles->findCycles(cyclesType);
+ }
+ else {
+ // Check if any remapping is needed (e.g. for USDPreviewSurface to Cycles nodes)
+ nodeDesc.mapping = sUsdToCyles->findUsd(nodeEntry.second.nodeTypeId);
+ if (nodeDesc.mapping) {
+ cyclesType = nodeDesc.mapping->nodeType();
+ }
+ }
+
+ // If it's a native Cycles' node-type, just do the lookup now.
+ if (const NodeType *nodeType = NodeType::find(cyclesType)) {
+ nodeDesc.node = static_cast<ShaderNode *>(nodeType->create(nodeType));
+ nodeDesc.node->set_owner(graph);
+
+ graph->add(nodeDesc.node);
+
+ _nodes.emplace(nodePath, nodeDesc);
+ }
+ else {
+ TF_RUNTIME_ERROR("Could not create node '%s'", nodePath.GetText());
+ continue;
+ }
+ }
+
+ UpdateParameters(nodeDesc, nodeEntry.second.parameters, nodePath);
+ }
+
+ // Now that all nodes have been constructed, iterate the network again and build up any
+ // connections between nodes
+ for (const std::pair<SdfPath, HdMaterialNode2> &nodeEntry : networkMap.nodes) {
+ const SdfPath &nodePath = nodeEntry.first;
+
+ const auto nodeIt = _nodes.find(nodePath);
+ if (nodeIt == _nodes.end()) {
+ TF_RUNTIME_ERROR("Could not find node '%s' to connect", nodePath.GetText());
+ continue;
+ }
+
+ UpdateConnections(nodeIt->second, nodeEntry.second, nodePath, graph);
+ }
+
+ // Finally connect the terminals to the graph output (Surface, Volume, Displacement)
+ for (const std::pair<TfToken, HdMaterialConnection2> &terminalEntry : networkMap.terminals) {
+ const TfToken &terminalName = terminalEntry.first;
+ const HdMaterialConnection2 &connection = terminalEntry.second;
+
+ const auto nodeIt = _nodes.find(connection.upstreamNode);
+ if (nodeIt == _nodes.end()) {
+ TF_RUNTIME_ERROR("Could not find terminal node '%s'", connection.upstreamNode.GetText());
+ continue;
+ }
+
+ ShaderNode *const node = nodeIt->second.node;
+
+ const char *inputName = nullptr;
+ const char *outputName = nullptr;
+ if (terminalName == HdMaterialTerminalTokens->surface ||
+ terminalName == CyclesMaterialTokens->cyclesSurface) {
+ inputName = "Surface";
+ // Find default output name based on the node if none is provided
+ if (node->type->name == "add_closure" || node->type->name == "mix_closure") {
+ outputName = "Closure";
+ }
+ else if (node->type->name == "emission") {
+ outputName = "Emission";
+ }
+ else {
+ outputName = "BSDF";
+ }
+ }
+ else if (terminalName == HdMaterialTerminalTokens->displacement ||
+ terminalName == CyclesMaterialTokens->cyclesDisplacement) {
+ inputName = outputName = "Displacement";
+ }
+ else if (terminalName == HdMaterialTerminalTokens->volume ||
+ terminalName == CyclesMaterialTokens->cyclesVolume) {
+ inputName = outputName = "Volume";
+ }
+
+ if (!connection.upstreamOutputName.IsEmpty()) {
+ outputName = connection.upstreamOutputName.GetText();
+ }
+
+ ShaderInput *const input = inputName ? graph->output()->input(inputName) : nullptr;
+ if (!input) {
+ TF_RUNTIME_ERROR("Could not find terminal input '%s.%s'",
+ connection.upstreamNode.GetText(),
+ inputName ? inputName : "<null>");
+ continue;
+ }
+
+ ShaderOutput *const output = outputName ? node->output(outputName) : nullptr;
+ if (!output) {
+ TF_RUNTIME_ERROR("Could not find terminal output '%s.%s'",
+ connection.upstreamNode.GetText(),
+ outputName ? outputName : "<null>");
+ continue;
+ }
+
+ graph->connect(output, input);
+ }
+
+ // Create the instanceId AOV output
+ {
+ const ustring instanceId(HdAovTokens->instanceId.GetString());
+
+ OutputAOVNode *aovNode = graph->create_node<OutputAOVNode>();
+ aovNode->set_name(instanceId);
+ graph->add(aovNode);
+
+ AttributeNode *instanceIdNode = graph->create_node<AttributeNode>();
+ instanceIdNode->set_attribute(instanceId);
+ graph->add(instanceIdNode);
+
+ graph->connect(instanceIdNode->output("Fac"), aovNode->input("Value"));
+ }
+
+ _shader->set_graph(graph);
+}
+
+void HdCyclesMaterial::Finalize(HdRenderParam *renderParam)
+{
+ if (!_shader) {
+ return;
+ }
+
+ const SceneLock lock(renderParam);
+
+ _nodes.clear();
+
+ lock.scene->delete_node(_shader);
+ _shader = nullptr;
+}
+
+void HdCyclesMaterial::Initialize(HdRenderParam *renderParam)
+{
+ if (_shader) {
+ return;
+ }
+
+ const SceneLock lock(renderParam);
+
+ _shader = lock.scene->create_node<Shader>();
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/material.h b/intern/cycles/hydra/material.h
new file mode 100644
index 00000000000..15925671bb8
--- /dev/null
+++ b/intern/cycles/hydra/material.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+
+#include <pxr/imaging/hd/material.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesMaterial final : public PXR_NS::HdMaterial {
+ public:
+ HdCyclesMaterial(const PXR_NS::SdfPath &sprimId);
+ ~HdCyclesMaterial() override;
+
+ PXR_NS::HdDirtyBits GetInitialDirtyBitsMask() const override;
+
+ void Sync(PXR_NS::HdSceneDelegate *sceneDelegate,
+ PXR_NS::HdRenderParam *renderParam,
+ PXR_NS::HdDirtyBits *dirtyBits) override;
+
+#if PXR_VERSION < 2011
+ void Reload() override
+ {
+ }
+#endif
+
+ void Finalize(PXR_NS::HdRenderParam *renderParam) override;
+
+ CCL_NS::Shader *GetCyclesShader() const
+ {
+ return _shader;
+ }
+
+ struct NodeDesc;
+
+ private:
+ void Initialize(PXR_NS::HdRenderParam *renderParam);
+
+ void UpdateParameters(NodeDesc &nodeDesc,
+ const std::map<PXR_NS::TfToken, PXR_NS::VtValue> &parameters,
+ const PXR_NS::SdfPath &nodePath);
+
+ void UpdateParameters(const PXR_NS::HdMaterialNetwork &network);
+ void UpdateParameters(const PXR_NS::HdMaterialNetwork2 &network);
+
+ void UpdateConnections(NodeDesc &nodeDesc,
+ const PXR_NS::HdMaterialNode2 &matNode,
+ const PXR_NS::SdfPath &nodePath,
+ CCL_NS::ShaderGraph *shaderGraph);
+
+ void PopulateShaderGraph(const PXR_NS::HdMaterialNetwork2 &network);
+
+ CCL_NS::Shader *_shader = nullptr;
+ std::unordered_map<PXR_NS::SdfPath, NodeDesc, PXR_NS::SdfPath::Hash> _nodes;
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/mesh.cpp b/intern/cycles/hydra/mesh.cpp
new file mode 100644
index 00000000000..155843458ef
--- /dev/null
+++ b/intern/cycles/hydra/mesh.cpp
@@ -0,0 +1,524 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/mesh.h"
+#include "hydra/geometry.inl"
+#include "scene/mesh.h"
+
+#include <pxr/base/gf/vec2f.h>
+#include <pxr/imaging/hd/extComputationUtils.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+namespace {
+
+template<typename T>
+VtValue ComputeTriangulatedUniformPrimvar(VtValue value, const VtIntArray &primitiveParams)
+{
+ T output;
+ output.reserve(primitiveParams.size());
+ const T &input = value.Get<T>();
+
+ for (size_t i = 0; i < primitiveParams.size(); ++i) {
+ const int faceIndex = HdMeshUtil::DecodeFaceIndexFromCoarseFaceParam(primitiveParams[i]);
+
+ output.push_back(input[faceIndex]);
+ }
+
+ return VtValue(output);
+}
+
+VtValue ComputeTriangulatedUniformPrimvar(VtValue value,
+ const HdType valueType,
+ const VtIntArray &primitiveParams)
+{
+ switch (valueType) {
+ case HdTypeFloat:
+ return ComputeTriangulatedUniformPrimvar<VtFloatArray>(value, primitiveParams);
+ case HdTypeFloatVec2:
+ return ComputeTriangulatedUniformPrimvar<VtVec2fArray>(value, primitiveParams);
+ case HdTypeFloatVec3:
+ return ComputeTriangulatedUniformPrimvar<VtVec3fArray>(value, primitiveParams);
+ case HdTypeFloatVec4:
+ return ComputeTriangulatedUniformPrimvar<VtVec4fArray>(value, primitiveParams);
+ default:
+ TF_RUNTIME_ERROR("Unsupported attribute type %d", static_cast<int>(valueType));
+ return VtValue();
+ }
+}
+
+VtValue ComputeTriangulatedFaceVaryingPrimvar(VtValue value,
+ const HdType valueType,
+ HdMeshUtil &meshUtil)
+{
+ if (meshUtil.ComputeTriangulatedFaceVaryingPrimvar(
+ HdGetValueData(value), value.GetArraySize(), valueType, &value)) {
+ return value;
+ }
+
+ return VtValue();
+}
+
+} // namespace
+
+Transform convert_transform(const GfMatrix4d &matrix)
+{
+ return make_transform(matrix[0][0],
+ matrix[1][0],
+ matrix[2][0],
+ matrix[3][0],
+ matrix[0][1],
+ matrix[1][1],
+ matrix[2][1],
+ matrix[3][1],
+ matrix[0][2],
+ matrix[1][2],
+ matrix[2][2],
+ matrix[3][2]);
+}
+
+HdCyclesMesh::HdCyclesMesh(const SdfPath &rprimId
+#if PXR_VERSION < 2102
+ ,
+ const SdfPath &instancerId
+#endif
+ )
+ : HdCyclesGeometry(rprimId
+#if PXR_VERSION < 2102
+ ,
+ instancerId
+#endif
+ ),
+ _util(&_topology, rprimId)
+{
+}
+
+HdCyclesMesh::~HdCyclesMesh()
+{
+}
+
+HdDirtyBits HdCyclesMesh::GetInitialDirtyBitsMask() const
+{
+ HdDirtyBits bits = HdCyclesGeometry::GetInitialDirtyBitsMask();
+ bits |= HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyNormals |
+ HdChangeTracker::DirtyPrimvar | HdChangeTracker::DirtyTopology |
+ HdChangeTracker::DirtyDisplayStyle | HdChangeTracker::DirtySubdivTags;
+ return bits;
+}
+
+HdDirtyBits HdCyclesMesh::_PropagateDirtyBits(HdDirtyBits bits) const
+{
+ if (bits & (HdChangeTracker::DirtyMaterialId)) {
+ // Update used shaders from geometry subsets if any exist in the topology
+ bits |= HdChangeTracker::DirtyTopology;
+ }
+
+ if (bits & (HdChangeTracker::DirtyTopology | HdChangeTracker::DirtyDisplayStyle |
+ HdChangeTracker::DirtySubdivTags)) {
+ // Do full topology update when display style or subdivision changes
+ bits |= HdChangeTracker::DirtyTopology | HdChangeTracker::DirtyDisplayStyle |
+ HdChangeTracker::DirtySubdivTags;
+ }
+
+ if (bits & (HdChangeTracker::DirtyTopology)) {
+ // Changing topology clears the geometry, so need to populate everything again
+ bits |= HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyNormals |
+ HdChangeTracker::DirtyPrimvar;
+ }
+
+ return bits;
+}
+
+void HdCyclesMesh::Populate(HdSceneDelegate *sceneDelegate, HdDirtyBits dirtyBits, bool &rebuild)
+{
+ if (HdChangeTracker::IsTopologyDirty(dirtyBits, GetId())) {
+ PopulateTopology(sceneDelegate);
+ }
+
+ if (dirtyBits & HdChangeTracker::DirtyPoints) {
+ PopulatePoints(sceneDelegate);
+ }
+
+ // Must happen after topology update, so that normals attribute size can be calculated
+ if (dirtyBits & HdChangeTracker::DirtyNormals) {
+ PopulateNormals(sceneDelegate);
+ }
+
+ // Must happen after topology update, so that appropriate attribute set can be selected
+ if (dirtyBits & HdChangeTracker::DirtyPrimvar) {
+ PopulatePrimvars(sceneDelegate);
+ }
+
+ rebuild = (_geom->triangles_is_modified()) || (_geom->subd_start_corner_is_modified()) ||
+ (_geom->subd_num_corners_is_modified()) || (_geom->subd_shader_is_modified()) ||
+ (_geom->subd_smooth_is_modified()) || (_geom->subd_ptex_offset_is_modified()) ||
+ (_geom->subd_face_corners_is_modified());
+}
+
+void HdCyclesMesh::PopulatePoints(HdSceneDelegate *sceneDelegate)
+{
+ VtValue value;
+
+ for (const HdExtComputationPrimvarDescriptor &desc :
+ sceneDelegate->GetExtComputationPrimvarDescriptors(GetId(), HdInterpolationVertex)) {
+ if (desc.name == HdTokens->points) {
+ auto valueStore = HdExtComputationUtils::GetComputedPrimvarValues({desc}, sceneDelegate);
+ const auto valueStoreIt = valueStore.find(desc.name);
+ if (valueStoreIt != valueStore.end()) {
+ value = std::move(valueStoreIt->second);
+ }
+ break;
+ }
+ }
+
+ if (value.IsEmpty()) {
+ value = GetPoints(sceneDelegate);
+ }
+
+ if (!value.IsHolding<VtVec3fArray>()) {
+ TF_WARN("Invalid points data for %s", GetId().GetText());
+ return;
+ }
+
+ const auto &points = value.UncheckedGet<VtVec3fArray>();
+
+ TF_VERIFY(points.size() >= static_cast<size_t>(_topology.GetNumPoints()));
+
+ array<float3> pointsDataCycles;
+ pointsDataCycles.reserve(points.size());
+ for (const GfVec3f &point : points) {
+ pointsDataCycles.push_back_reserved(make_float3(point[0], point[1], point[2]));
+ }
+
+ _geom->set_verts(pointsDataCycles);
+}
+
+void HdCyclesMesh::PopulateNormals(HdSceneDelegate *sceneDelegate)
+{
+ _geom->attributes.remove(ATTR_STD_FACE_NORMAL);
+ _geom->attributes.remove(ATTR_STD_VERTEX_NORMAL);
+
+ // Authored normals should only exist on triangle meshes
+ if (_geom->get_subdivision_type() != Mesh::SUBDIVISION_NONE) {
+ return;
+ }
+
+ VtValue value;
+ HdInterpolation interpolation = HdInterpolationCount;
+
+ for (int i = 0; i < HdInterpolationCount && interpolation == HdInterpolationCount; ++i) {
+ for (const HdExtComputationPrimvarDescriptor &desc :
+ sceneDelegate->GetExtComputationPrimvarDescriptors(GetId(),
+ static_cast<HdInterpolation>(i))) {
+ if (desc.name == HdTokens->normals) {
+ auto valueStore = HdExtComputationUtils::GetComputedPrimvarValues({desc}, sceneDelegate);
+ const auto valueStoreIt = valueStore.find(desc.name);
+ if (valueStoreIt != valueStore.end()) {
+ value = std::move(valueStoreIt->second);
+ interpolation = static_cast<HdInterpolation>(i);
+ }
+ break;
+ }
+ }
+ }
+
+ if (value.IsEmpty()) {
+ interpolation = GetPrimvarInterpolation(sceneDelegate, HdTokens->normals);
+ if (interpolation == HdInterpolationCount) {
+ return; // Ignore missing normals
+ }
+
+ value = GetNormals(sceneDelegate);
+ }
+
+ if (!value.IsHolding<VtVec3fArray>()) {
+ TF_WARN("Invalid normals data for %s", GetId().GetText());
+ return;
+ }
+
+ const auto &normals = value.UncheckedGet<VtVec3fArray>();
+
+ if (interpolation == HdInterpolationConstant) {
+ TF_VERIFY(normals.size() == 1);
+
+ const GfVec3f constantNormal = normals[0];
+
+ float3 *const N = _geom->attributes.add(ATTR_STD_VERTEX_NORMAL)->data_float3();
+ for (size_t i = 0; i < _geom->get_verts().size(); ++i) {
+ N[i] = make_float3(constantNormal[0], constantNormal[1], constantNormal[2]);
+ }
+ }
+ else if (interpolation == HdInterpolationUniform) {
+ TF_VERIFY(normals.size() == static_cast<size_t>(_topology.GetNumFaces()));
+
+ float3 *const N = _geom->attributes.add(ATTR_STD_FACE_NORMAL)->data_float3();
+ for (size_t i = 0; i < _geom->num_triangles(); ++i) {
+ const int faceIndex = HdMeshUtil::DecodeFaceIndexFromCoarseFaceParam(_primitiveParams[i]);
+
+ N[i] = make_float3(normals[faceIndex][0], normals[faceIndex][1], normals[faceIndex][2]);
+ }
+ }
+ else if (interpolation == HdInterpolationVertex || interpolation == HdInterpolationVarying) {
+ TF_VERIFY(normals.size() == static_cast<size_t>(_topology.GetNumPoints()) &&
+ static_cast<size_t>(_topology.GetNumPoints()) == _geom->get_verts().size());
+
+ float3 *const N = _geom->attributes.add(ATTR_STD_VERTEX_NORMAL)->data_float3();
+ for (size_t i = 0; i < _geom->get_verts().size(); ++i) {
+ N[i] = make_float3(normals[i][0], normals[i][1], normals[i][2]);
+ }
+ }
+ else if (interpolation == HdInterpolationFaceVarying) {
+ TF_VERIFY(normals.size() == static_cast<size_t>(_topology.GetNumFaceVaryings()));
+
+ if (!_util.ComputeTriangulatedFaceVaryingPrimvar(
+ normals.data(), normals.size(), HdTypeFloatVec3, &value)) {
+ return;
+ }
+
+ const auto &normalsTriangulated = value.UncheckedGet<VtVec3fArray>();
+
+ // Cycles has no standard attribute for face-varying normals, so this is a lossy transformation
+ float3 *const N = _geom->attributes.add(ATTR_STD_FACE_NORMAL)->data_float3();
+ for (size_t i = 0; i < _geom->num_triangles(); ++i) {
+ GfVec3f averageNormal = normalsTriangulated[i * 3] + normalsTriangulated[i * 3 + 1] +
+ normalsTriangulated[i * 3 + 2];
+ GfNormalize(&averageNormal);
+
+ N[i] = make_float3(averageNormal[0], averageNormal[1], averageNormal[2]);
+ }
+ }
+}
+
+void HdCyclesMesh::PopulatePrimvars(HdSceneDelegate *sceneDelegate)
+{
+ Scene *const scene = (Scene *)_geom->get_owner();
+
+ const bool subdivision = _geom->get_subdivision_type() != Mesh::SUBDIVISION_NONE;
+ AttributeSet &attributes = subdivision ? _geom->subd_attributes : _geom->attributes;
+
+ const std::pair<HdInterpolation, AttributeElement> interpolations[] = {
+ std::make_pair(HdInterpolationFaceVarying, ATTR_ELEMENT_CORNER),
+ std::make_pair(HdInterpolationUniform, ATTR_ELEMENT_FACE),
+ std::make_pair(HdInterpolationVertex, ATTR_ELEMENT_VERTEX),
+ std::make_pair(HdInterpolationVarying, ATTR_ELEMENT_VERTEX),
+ std::make_pair(HdInterpolationConstant, ATTR_ELEMENT_OBJECT),
+ };
+
+ for (const auto &interpolation : interpolations) {
+ for (const HdPrimvarDescriptor &desc :
+ GetPrimvarDescriptors(sceneDelegate, interpolation.first)) {
+ // Skip special primvars that are handled separately
+ if (desc.name == HdTokens->points || desc.name == HdTokens->normals) {
+ continue;
+ }
+
+ VtValue value = GetPrimvar(sceneDelegate, desc.name);
+ if (value.IsEmpty()) {
+ continue;
+ }
+
+ const ustring name(desc.name.GetString());
+
+ AttributeStandard std = ATTR_STD_NONE;
+ if (desc.role == HdPrimvarRoleTokens->textureCoordinate) {
+ std = ATTR_STD_UV;
+ }
+ else if (interpolation.first == HdInterpolationVertex) {
+ if (desc.name == HdTokens->displayColor || desc.role == HdPrimvarRoleTokens->color) {
+ std = ATTR_STD_VERTEX_COLOR;
+ }
+ else if (desc.name == HdTokens->normals) {
+ std = ATTR_STD_VERTEX_NORMAL;
+ }
+ }
+ else if (desc.name == HdTokens->displayColor &&
+ interpolation.first == HdInterpolationConstant) {
+ if (value.IsHolding<VtVec3fArray>() && value.GetArraySize() == 1) {
+ const GfVec3f color = value.UncheckedGet<VtVec3fArray>()[0];
+ _instances[0]->set_color(make_float3(color[0], color[1], color[2]));
+ }
+ }
+
+ // Skip attributes that are not needed
+ if ((std != ATTR_STD_NONE && _geom->need_attribute(scene, std)) ||
+ _geom->need_attribute(scene, name)) {
+ const HdType valueType = HdGetValueTupleType(value).type;
+
+ if (!subdivision) {
+ // Adjust attributes for polygons that were triangulated
+ if (interpolation.first == HdInterpolationUniform) {
+ value = ComputeTriangulatedUniformPrimvar(value, valueType, _primitiveParams);
+ if (value.IsEmpty()) {
+ continue;
+ }
+ }
+ else if (interpolation.first == HdInterpolationFaceVarying) {
+ value = ComputeTriangulatedFaceVaryingPrimvar(value, valueType, _util);
+ if (value.IsEmpty()) {
+ continue;
+ }
+ }
+ }
+
+ ApplyPrimvars(attributes, name, value, interpolation.second, std);
+ }
+ }
+ }
+}
+
+void HdCyclesMesh::PopulateTopology(HdSceneDelegate *sceneDelegate)
+{
+ // Clear geometry before populating it again with updated topology
+ _geom->clear(true);
+
+ const HdDisplayStyle displayStyle = GetDisplayStyle(sceneDelegate);
+ _topology = HdMeshTopology(GetMeshTopology(sceneDelegate), displayStyle.refineLevel);
+
+ const TfToken subdivScheme = _topology.GetScheme();
+ if (subdivScheme == PxOsdOpenSubdivTokens->bilinear && _topology.GetRefineLevel() > 0) {
+ _geom->set_subdivision_type(Mesh::SUBDIVISION_LINEAR);
+ }
+ else if (subdivScheme == PxOsdOpenSubdivTokens->catmullClark && _topology.GetRefineLevel() > 0) {
+ _geom->set_subdivision_type(Mesh::SUBDIVISION_CATMULL_CLARK);
+ }
+ else {
+ _geom->set_subdivision_type(Mesh::SUBDIVISION_NONE);
+ }
+
+ const bool smooth = !displayStyle.flatShadingEnabled;
+ const bool subdivision = _geom->get_subdivision_type() != Mesh::SUBDIVISION_NONE;
+
+ // Initialize lookup table from polygon face to material shader index
+ VtIntArray faceShaders(_topology.GetNumFaces(), 0);
+
+ HdGeomSubsets const &geomSubsets = _topology.GetGeomSubsets();
+ if (!geomSubsets.empty()) {
+ array<Node *> usedShaders = std::move(_geom->get_used_shaders());
+ // Remove any previous materials except for the material assigned to the prim
+ usedShaders.resize(1);
+
+ std::unordered_map<SdfPath, int, SdfPath::Hash> materials;
+
+ for (const HdGeomSubset &geomSubset : geomSubsets) {
+ TF_VERIFY(geomSubset.type == HdGeomSubset::TypeFaceSet);
+
+ int shader = 0;
+ const auto it = materials.find(geomSubset.materialId);
+ if (it != materials.end()) {
+ shader = it->second;
+ }
+ else {
+ const auto material = static_cast<const HdCyclesMaterial *>(
+ sceneDelegate->GetRenderIndex().GetSprim(HdPrimTypeTokens->material,
+ geomSubset.materialId));
+
+ if (material && material->GetCyclesShader()) {
+ shader = static_cast<int>(usedShaders.size());
+ usedShaders.push_back_slow(material->GetCyclesShader());
+
+ materials.emplace(geomSubset.materialId, shader);
+ }
+ }
+
+ for (int face : geomSubset.indices) {
+ faceShaders[face] = shader;
+ }
+ }
+
+ _geom->set_used_shaders(usedShaders);
+ }
+
+ const VtIntArray vertIndx = _topology.GetFaceVertexIndices();
+ const VtIntArray vertCounts = _topology.GetFaceVertexCounts();
+
+ if (!subdivision) {
+ VtVec3iArray triangles;
+ _util.ComputeTriangleIndices(&triangles, &_primitiveParams);
+
+ _geom->reserve_mesh(_topology.GetNumPoints(), triangles.size());
+
+ for (size_t i = 0; i < _primitiveParams.size(); ++i) {
+ const int faceIndex = HdMeshUtil::DecodeFaceIndexFromCoarseFaceParam(_primitiveParams[i]);
+
+ const GfVec3i triangle = triangles[i];
+ _geom->add_triangle(triangle[0], triangle[1], triangle[2], faceShaders[faceIndex], smooth);
+ }
+ }
+ else {
+ PxOsdSubdivTags subdivTags = GetSubdivTags(sceneDelegate);
+ _topology.SetSubdivTags(subdivTags);
+
+ size_t numNgons = 0;
+ size_t numCorners = 0;
+ for (int vertCount : vertCounts) {
+ numNgons += (vertCount == 4) ? 0 : 1;
+ numCorners += vertCount;
+ }
+
+ _geom->reserve_subd_faces(_topology.GetNumFaces(), numNgons, numCorners);
+
+ // TODO: Handle hole indices
+ size_t faceIndex = 0;
+ size_t indexOffset = 0;
+ for (int vertCount : vertCounts) {
+ _geom->add_subd_face(&vertIndx[indexOffset], vertCount, faceShaders[faceIndex], smooth);
+
+ faceIndex++;
+ indexOffset += vertCount;
+ }
+
+ const VtIntArray creaseLengths = subdivTags.GetCreaseLengths();
+ if (!creaseLengths.empty()) {
+ size_t numCreases = 0;
+ for (int creaseLength : creaseLengths) {
+ numCreases += creaseLength - 1;
+ }
+
+ _geom->reserve_subd_creases(numCreases);
+
+ const VtIntArray creaseIndices = subdivTags.GetCreaseIndices();
+ const VtFloatArray creaseWeights = subdivTags.GetCreaseWeights();
+
+ indexOffset = 0;
+ size_t creaseLengthOffset = 0;
+ size_t createWeightOffset = 0;
+ for (int creaseLength : creaseLengths) {
+ for (int j = 0; j < creaseLength - 1; ++j, ++createWeightOffset) {
+ const int v0 = creaseIndices[indexOffset + j];
+ const int v1 = creaseIndices[indexOffset + j + 1];
+
+ float weight = creaseWeights.size() == creaseLengths.size() ?
+ creaseWeights[creaseLengthOffset] :
+ creaseWeights[createWeightOffset];
+
+ _geom->add_edge_crease(v0, v1, weight);
+ }
+
+ indexOffset += creaseLength;
+ creaseLengthOffset++;
+ }
+
+ const VtIntArray cornerIndices = subdivTags.GetCornerIndices();
+ const VtFloatArray cornerWeights = subdivTags.GetCornerWeights();
+
+ for (size_t i = 0; i < cornerIndices.size(); ++i) {
+ _geom->add_vertex_crease(cornerIndices[i], cornerWeights[i]);
+ }
+ }
+
+ _geom->set_subd_dicing_rate(1.0f);
+ _geom->set_subd_max_level(_topology.GetRefineLevel());
+ _geom->set_subd_objecttoworld(_instances[0]->get_tfm());
+ }
+}
+
+void HdCyclesMesh::Finalize(PXR_NS::HdRenderParam *renderParam)
+{
+ _topology = HdMeshTopology();
+ _primitiveParams.clear();
+
+ HdCyclesGeometry<PXR_NS::HdMesh, Mesh>::Finalize(renderParam);
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/mesh.h b/intern/cycles/hydra/mesh.h
new file mode 100644
index 00000000000..8ec108534a1
--- /dev/null
+++ b/intern/cycles/hydra/mesh.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+#include "hydra/geometry.h"
+
+#include <pxr/imaging/hd/mesh.h>
+#include <pxr/imaging/hd/meshUtil.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesMesh final : public HdCyclesGeometry<PXR_NS::HdMesh, CCL_NS::Mesh> {
+ public:
+ HdCyclesMesh(
+ const PXR_NS::SdfPath &rprimId
+#if PXR_VERSION < 2102
+ ,
+ const PXR_NS::SdfPath &instancerId = {}
+#endif
+ );
+ ~HdCyclesMesh() override;
+
+ PXR_NS::HdDirtyBits GetInitialDirtyBitsMask() const override;
+
+ void Finalize(PXR_NS::HdRenderParam *renderParam) override;
+
+ private:
+ PXR_NS::HdDirtyBits _PropagateDirtyBits(PXR_NS::HdDirtyBits bits) const override;
+
+ void Populate(PXR_NS::HdSceneDelegate *sceneDelegate,
+ PXR_NS::HdDirtyBits dirtyBits,
+ bool &rebuild) override;
+
+ void PopulatePoints(PXR_NS::HdSceneDelegate *sceneDelegate);
+ void PopulateNormals(PXR_NS::HdSceneDelegate *sceneDelegate);
+
+ void PopulatePrimvars(PXR_NS::HdSceneDelegate *sceneDelegate);
+
+ void PopulateTopology(PXR_NS::HdSceneDelegate *sceneDelegate);
+
+ PXR_NS::HdMeshUtil _util;
+ PXR_NS::HdMeshTopology _topology;
+ PXR_NS::VtIntArray _primitiveParams;
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/node_util.cpp b/intern/cycles/hydra/node_util.cpp
new file mode 100644
index 00000000000..c7e49688f5c
--- /dev/null
+++ b/intern/cycles/hydra/node_util.cpp
@@ -0,0 +1,561 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/node_util.h"
+#include "util/transform.h"
+
+#include <pxr/base/gf/matrix3d.h>
+#include <pxr/base/gf/matrix3f.h>
+#include <pxr/base/gf/matrix4d.h>
+#include <pxr/base/gf/matrix4f.h>
+#include <pxr/base/gf/vec2f.h>
+#include <pxr/base/gf/vec3f.h>
+#include <pxr/base/vt/array.h>
+#include <pxr/usd/sdf/assetPath.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+namespace {
+
+template<typename DstType> DstType convertToCycles(const VtValue &value)
+{
+ if (value.IsHolding<DstType>()) {
+ return value.UncheckedGet<DstType>();
+ }
+
+ VtValue castedValue = VtValue::Cast<DstType>(value);
+ if (castedValue.IsHolding<DstType>()) {
+ return castedValue.UncheckedGet<DstType>();
+ }
+
+ TF_WARN("Could not convert VtValue to Cycles type");
+ return DstType(0);
+}
+
+template<> float2 convertToCycles<float2>(const VtValue &value)
+{
+ const GfVec2f convertedValue = convertToCycles<GfVec2f>(value);
+ return make_float2(convertedValue[0], convertedValue[1]);
+}
+
+template<> float3 convertToCycles<float3>(const VtValue &value)
+{
+ if (value.IsHolding<GfVec3f>()) {
+ const GfVec3f convertedValue = value.UncheckedGet<GfVec3f>();
+ return make_float3(convertedValue[0], convertedValue[1], convertedValue[2]);
+ }
+ if (value.IsHolding<GfVec4f>()) {
+ const GfVec4f convertedValue = value.UncheckedGet<GfVec4f>();
+ return make_float3(convertedValue[0], convertedValue[1], convertedValue[2]);
+ }
+
+ if (value.CanCast<GfVec3f>()) {
+ const GfVec3f convertedValue = VtValue::Cast<GfVec3f>(value).UncheckedGet<GfVec3f>();
+ return make_float3(convertedValue[0], convertedValue[1], convertedValue[2]);
+ }
+ if (value.CanCast<GfVec4f>()) {
+ const GfVec4f convertedValue = VtValue::Cast<GfVec4f>(value).UncheckedGet<GfVec4f>();
+ return make_float3(convertedValue[0], convertedValue[1], convertedValue[2]);
+ }
+
+ TF_WARN("Could not convert VtValue to float3");
+ return zero_float3();
+}
+
+template<> ustring convertToCycles<ustring>(const VtValue &value)
+{
+ if (value.IsHolding<TfToken>()) {
+ return ustring(value.UncheckedGet<TfToken>().GetString());
+ }
+ if (value.IsHolding<std::string>()) {
+ return ustring(value.UncheckedGet<std::string>());
+ }
+ if (value.IsHolding<SdfAssetPath>()) {
+ const SdfAssetPath &path = value.UncheckedGet<SdfAssetPath>();
+ return ustring(path.GetResolvedPath());
+ }
+
+ if (value.CanCast<TfToken>()) {
+ return convertToCycles<ustring>(VtValue::Cast<TfToken>(value));
+ }
+ if (value.CanCast<std::string>()) {
+ return convertToCycles<ustring>(VtValue::Cast<std::string>(value));
+ }
+ if (value.CanCast<SdfAssetPath>()) {
+ return convertToCycles<ustring>(VtValue::Cast<SdfAssetPath>(value));
+ }
+
+ TF_WARN("Could not convert VtValue to ustring");
+ return ustring();
+}
+
+template<typename Matrix>
+Transform convertMatrixToCycles(
+ const typename std::enable_if<Matrix::numRows == 3 && Matrix::numColumns == 3, Matrix>::type
+ &matrix)
+{
+ return make_transform(matrix[0][0],
+ matrix[1][0],
+ matrix[2][0],
+ 0,
+ matrix[0][1],
+ matrix[1][1],
+ matrix[2][1],
+ 0,
+ matrix[0][2],
+ matrix[1][2],
+ matrix[2][2],
+ 0);
+}
+
+template<typename Matrix>
+Transform convertMatrixToCycles(
+ const typename std::enable_if<Matrix::numRows == 4 && Matrix::numColumns == 4, Matrix>::type
+ &matrix)
+{
+ return make_transform(matrix[0][0],
+ matrix[1][0],
+ matrix[2][0],
+ matrix[3][0],
+ matrix[0][1],
+ matrix[1][1],
+ matrix[2][1],
+ matrix[3][1],
+ matrix[0][2],
+ matrix[1][2],
+ matrix[2][2],
+ matrix[3][2]);
+}
+
+template<> Transform convertToCycles<Transform>(const VtValue &value)
+{
+ if (value.IsHolding<GfMatrix4f>()) {
+ return convertMatrixToCycles<GfMatrix4f>(value.UncheckedGet<GfMatrix4f>());
+ }
+ if (value.IsHolding<GfMatrix3f>()) {
+ return convertMatrixToCycles<GfMatrix3f>(value.UncheckedGet<GfMatrix3f>());
+ }
+ if (value.IsHolding<GfMatrix4d>()) {
+ return convertMatrixToCycles<GfMatrix4d>(value.UncheckedGet<GfMatrix4d>());
+ }
+ if (value.IsHolding<GfMatrix3d>()) {
+ return convertMatrixToCycles<GfMatrix3d>(value.UncheckedGet<GfMatrix3d>());
+ }
+
+ if (value.CanCast<GfMatrix4f>()) {
+ return convertToCycles<Transform>(VtValue::Cast<GfMatrix4f>(value));
+ }
+ if (value.CanCast<GfMatrix3f>()) {
+ return convertToCycles<Transform>(VtValue::Cast<GfMatrix3f>(value));
+ }
+ if (value.CanCast<GfMatrix4d>()) {
+ return convertToCycles<Transform>(VtValue::Cast<GfMatrix4d>(value));
+ }
+ if (value.CanCast<GfMatrix3d>()) {
+ return convertToCycles<Transform>(VtValue::Cast<GfMatrix3d>(value));
+ }
+
+ TF_WARN("Could not convert VtValue to Transform");
+ return transform_identity();
+}
+
+template<typename DstType, typename SrcType = DstType>
+array<DstType> convertToCyclesArray(const VtValue &value)
+{
+ static_assert(sizeof(DstType) == sizeof(SrcType),
+ "Size mismatch between VtArray and array base type");
+
+ using SrcArray = VtArray<SrcType>;
+
+ if (value.IsHolding<SrcArray>()) {
+ const auto &valueData = value.UncheckedGet<SrcArray>();
+ array<DstType> cyclesArray;
+ cyclesArray.resize(valueData.size());
+ std::memcpy(cyclesArray.data(), valueData.data(), valueData.size() * sizeof(DstType));
+ return cyclesArray;
+ }
+
+ if (value.CanCast<SrcArray>()) {
+ VtValue castedValue = VtValue::Cast<SrcArray>(value);
+ const auto &valueData = castedValue.UncheckedGet<SrcArray>();
+ array<DstType> cyclesArray;
+ cyclesArray.resize(valueData.size());
+ std::memcpy(cyclesArray.data(), valueData.data(), valueData.size() * sizeof(DstType));
+ return cyclesArray;
+ }
+
+ return array<DstType>();
+}
+
+template<> array<float3> convertToCyclesArray<float3, GfVec3f>(const VtValue &value)
+{
+ if (value.IsHolding<VtVec3fArray>()) {
+ const auto &valueData = value.UncheckedGet<VtVec3fArray>();
+ array<float3> cyclesArray;
+ cyclesArray.reserve(valueData.size());
+ for (const GfVec3f &vec : valueData) {
+ cyclesArray.push_back_reserved(make_float3(vec[0], vec[1], vec[2]));
+ }
+ return cyclesArray;
+ }
+ if (value.IsHolding<VtVec4fArray>()) {
+ const auto &valueData = value.UncheckedGet<VtVec4fArray>();
+ array<float3> cyclesArray;
+ cyclesArray.reserve(valueData.size());
+ for (const GfVec4f &vec : valueData) {
+ cyclesArray.push_back_reserved(make_float3(vec[0], vec[1], vec[2]));
+ }
+ return cyclesArray;
+ }
+
+ if (value.CanCast<VtVec3fArray>()) {
+ return convertToCyclesArray<float3, GfVec3f>(VtValue::Cast<VtVec3fArray>(value));
+ }
+ if (value.CanCast<VtVec4fArray>()) {
+ return convertToCyclesArray<float3, GfVec3f>(VtValue::Cast<VtVec4fArray>(value));
+ }
+
+ return array<float3>();
+}
+
+template<> array<ustring> convertToCyclesArray<ustring, void>(const VtValue &value)
+{
+ using SdfPathArray = VtArray<SdfAssetPath>;
+
+ if (value.IsHolding<VtStringArray>()) {
+ const auto &valueData = value.UncheckedGet<VtStringArray>();
+ array<ustring> cyclesArray;
+ cyclesArray.reserve(valueData.size());
+ for (const auto &element : valueData) {
+ cyclesArray.push_back_reserved(ustring(element));
+ }
+ return cyclesArray;
+ }
+ if (value.IsHolding<VtTokenArray>()) {
+ const auto &valueData = value.UncheckedGet<VtTokenArray>();
+ array<ustring> cyclesArray;
+ cyclesArray.reserve(valueData.size());
+ for (const auto &element : valueData) {
+ cyclesArray.push_back_reserved(ustring(element.GetString()));
+ }
+ return cyclesArray;
+ }
+ if (value.IsHolding<SdfPathArray>()) {
+ const auto &valueData = value.UncheckedGet<SdfPathArray>();
+ array<ustring> cyclesArray;
+ cyclesArray.reserve(valueData.size());
+ for (const auto &element : valueData) {
+ cyclesArray.push_back_reserved(ustring(element.GetResolvedPath()));
+ }
+ return cyclesArray;
+ }
+
+ if (value.CanCast<VtStringArray>()) {
+ return convertToCyclesArray<ustring, void>(VtValue::Cast<VtStringArray>(value));
+ }
+ if (value.CanCast<VtTokenArray>()) {
+ return convertToCyclesArray<ustring, void>(VtValue::Cast<VtTokenArray>(value));
+ }
+ if (value.CanCast<SdfPathArray>()) {
+ return convertToCyclesArray<ustring, void>(VtValue::Cast<SdfPathArray>(value));
+ }
+
+ TF_WARN("Could not convert VtValue to array<ustring>");
+ return array<ustring>();
+}
+
+template<typename MatrixArray> array<Transform> convertToCyclesTransformArray(const VtValue &value)
+{
+ assert(value.IsHolding<MatrixArray>());
+
+ const auto &valueData = value.UncheckedGet<MatrixArray>();
+ array<Transform> cyclesArray;
+ cyclesArray.reserve(valueData.size());
+ for (const auto &element : valueData) {
+ cyclesArray.push_back_reserved(convertMatrixToCycles<MatrixArray::value_type>(element));
+ }
+ return cyclesArray;
+}
+
+template<> array<Transform> convertToCyclesArray<Transform, void>(const VtValue &value)
+{
+ if (value.IsHolding<VtMatrix4fArray>()) {
+ return convertToCyclesTransformArray<VtMatrix4fArray>(value);
+ }
+ if (value.IsHolding<VtMatrix3fArray>()) {
+ return convertToCyclesTransformArray<VtMatrix3fArray>(value);
+ }
+ if (value.IsHolding<VtMatrix4dArray>()) {
+ return convertToCyclesTransformArray<VtMatrix4dArray>(value);
+ }
+ if (value.IsHolding<VtMatrix3dArray>()) {
+ return convertToCyclesTransformArray<VtMatrix3dArray>(value);
+ }
+
+ if (value.CanCast<VtMatrix4fArray>()) {
+ return convertToCyclesTransformArray<VtMatrix4fArray>(VtValue::Cast<VtMatrix4fArray>(value));
+ }
+ if (value.CanCast<VtMatrix3fArray>()) {
+ return convertToCyclesTransformArray<VtMatrix3fArray>(VtValue::Cast<VtMatrix3fArray>(value));
+ }
+ if (value.CanCast<VtMatrix4dArray>()) {
+ return convertToCyclesTransformArray<VtMatrix4dArray>(VtValue::Cast<VtMatrix4dArray>(value));
+ }
+ if (value.CanCast<VtMatrix3dArray>()) {
+ return convertToCyclesTransformArray<VtMatrix3dArray>(VtValue::Cast<VtMatrix3dArray>(value));
+ }
+
+ TF_WARN("Could not convert VtValue to array<Transform>");
+ return array<Transform>();
+}
+
+template<typename SrcType> VtValue convertFromCycles(const SrcType &value)
+{
+ return VtValue(value);
+}
+
+template<> VtValue convertFromCycles<float2>(const float2 &value)
+{
+ const GfVec2f convertedValue(value.x, value.y);
+ return VtValue(convertedValue);
+}
+
+template<> VtValue convertFromCycles<float3>(const float3 &value)
+{
+ const GfVec3f convertedValue(value.x, value.y, value.z);
+ return VtValue(convertedValue);
+}
+
+template<> VtValue convertFromCycles<ustring>(const ustring &value)
+{
+ return VtValue(value.string());
+}
+
+GfMatrix4f convertMatrixFromCycles(const Transform &matrix)
+{
+ return GfMatrix4f(matrix[0][0],
+ matrix[1][0],
+ matrix[2][0],
+ 0.0f,
+ matrix[0][1],
+ matrix[1][1],
+ matrix[2][1],
+ 0.0f,
+ matrix[0][2],
+ matrix[1][2],
+ matrix[2][2],
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f);
+}
+
+template<> VtValue convertFromCycles<Transform>(const Transform &value)
+{
+ return VtValue(convertMatrixFromCycles(value));
+}
+
+template<typename SrcType, typename DstType = SrcType>
+VtValue convertFromCyclesArray(const array<SrcType> &value)
+{
+ static_assert(sizeof(DstType) == sizeof(SrcType),
+ "Size mismatch between VtArray and array base type");
+
+ VtArray<DstType> convertedValue;
+ convertedValue.resize(value.size());
+ std::memcpy(convertedValue.data(), value.data(), value.size() * sizeof(SrcType));
+ return VtValue(convertedValue);
+}
+
+template<> VtValue convertFromCyclesArray<float3, GfVec3f>(const array<float3> &value)
+{
+ VtVec3fArray convertedValue;
+ convertedValue.reserve(value.size());
+ for (const auto &element : value) {
+ convertedValue.push_back(GfVec3f(element.x, element.y, element.z));
+ }
+ return VtValue(convertedValue);
+}
+
+template<> VtValue convertFromCyclesArray<ustring, void>(const array<ustring> &value)
+{
+ VtStringArray convertedValue;
+ convertedValue.reserve(value.size());
+ for (const auto &element : value) {
+ convertedValue.push_back(element.string());
+ }
+ return VtValue(convertedValue);
+}
+
+template<> VtValue convertFromCyclesArray<Transform, void>(const array<Transform> &value)
+{
+ VtMatrix4fArray convertedValue;
+ convertedValue.reserve(value.size());
+ for (const auto &element : value) {
+ convertedValue.push_back(convertMatrixFromCycles(element));
+ }
+ return VtValue(convertedValue);
+}
+
+} // namespace
+
+void SetNodeValue(Node *node, const SocketType &socket, const VtValue &value)
+{
+ switch (socket.type) {
+ default:
+ case SocketType::UNDEFINED:
+ TF_RUNTIME_ERROR("Unexpected conversion: SocketType::UNDEFINED");
+ break;
+
+ case SocketType::BOOLEAN:
+ node->set(socket, convertToCycles<bool>(value));
+ break;
+ case SocketType::FLOAT:
+ node->set(socket, convertToCycles<float>(value));
+ break;
+ case SocketType::INT:
+ node->set(socket, convertToCycles<int>(value));
+ break;
+ case SocketType::UINT:
+ node->set(socket, convertToCycles<unsigned int>(value));
+ break;
+ case SocketType::COLOR:
+ case SocketType::VECTOR:
+ case SocketType::POINT:
+ case SocketType::NORMAL:
+ node->set(socket, convertToCycles<float3>(value));
+ break;
+ case SocketType::POINT2:
+ node->set(socket, convertToCycles<float2>(value));
+ break;
+ case SocketType::CLOSURE:
+ // Handled by node connections
+ break;
+ case SocketType::STRING:
+ node->set(socket, convertToCycles<ustring>(value));
+ break;
+ case SocketType::ENUM:
+ // Enum's can accept a string or an int
+ if (value.IsHolding<TfToken>() || value.IsHolding<std::string>()) {
+ node->set(socket, convertToCycles<ustring>(value));
+ }
+ else {
+ node->set(socket, convertToCycles<int>(value));
+ }
+ break;
+ case SocketType::TRANSFORM:
+ node->set(socket, convertToCycles<Transform>(value));
+ break;
+ case SocketType::NODE:
+ // TODO: renderIndex->GetRprim()->cycles_node ?
+ TF_WARN("Unimplemented conversion: SocketType::NODE");
+ break;
+
+ case SocketType::BOOLEAN_ARRAY: {
+ auto cyclesArray = convertToCyclesArray<bool>(value);
+ node->set(socket, cyclesArray);
+ break;
+ }
+ case SocketType::FLOAT_ARRAY: {
+ auto cyclesArray = convertToCyclesArray<float>(value);
+ node->set(socket, cyclesArray);
+ break;
+ }
+ case SocketType::INT_ARRAY: {
+ auto cyclesArray = convertToCyclesArray<int>(value);
+ node->set(socket, cyclesArray);
+ break;
+ }
+ case SocketType::COLOR_ARRAY:
+ case SocketType::VECTOR_ARRAY:
+ case SocketType::POINT_ARRAY:
+ case SocketType::NORMAL_ARRAY: {
+ auto cyclesArray = convertToCyclesArray<float3, GfVec3f>(value);
+ node->set(socket, cyclesArray);
+ break;
+ }
+ case SocketType::POINT2_ARRAY: {
+ auto cyclesArray = convertToCyclesArray<float2, GfVec2f>(value);
+ node->set(socket, cyclesArray);
+ break;
+ }
+ case SocketType::STRING_ARRAY: {
+ auto cyclesArray = convertToCyclesArray<ustring, void>(value);
+ node->set(socket, cyclesArray);
+ break;
+ }
+ case SocketType::TRANSFORM_ARRAY: {
+ auto cyclesArray = convertToCyclesArray<Transform, void>(value);
+ node->set(socket, cyclesArray);
+ break;
+ }
+ case SocketType::NODE_ARRAY: {
+ // TODO: renderIndex->GetRprim()->cycles_node ?
+ TF_WARN("Unimplemented conversion: SocketType::NODE_ARRAY");
+ break;
+ }
+ }
+}
+
+VtValue GetNodeValue(const Node *node, const SocketType &socket)
+{
+ switch (socket.type) {
+ default:
+ case SocketType::UNDEFINED:
+ TF_RUNTIME_ERROR("Unexpected conversion: SocketType::UNDEFINED");
+ return VtValue();
+
+ case SocketType::BOOLEAN:
+ return convertFromCycles(node->get_bool(socket));
+ case SocketType::FLOAT:
+ return convertFromCycles(node->get_float(socket));
+ case SocketType::INT:
+ return convertFromCycles(node->get_int(socket));
+ case SocketType::UINT:
+ return convertFromCycles(node->get_uint(socket));
+ case SocketType::COLOR:
+ case SocketType::VECTOR:
+ case SocketType::POINT:
+ case SocketType::NORMAL:
+ return convertFromCycles(node->get_float3(socket));
+ case SocketType::POINT2:
+ return convertFromCycles(node->get_float2(socket));
+ case SocketType::CLOSURE:
+ return VtValue();
+ case SocketType::STRING:
+ return convertFromCycles(node->get_string(socket));
+ case SocketType::ENUM:
+ return convertFromCycles(node->get_int(socket));
+ case SocketType::TRANSFORM:
+ return convertFromCycles(node->get_transform(socket));
+ case SocketType::NODE:
+ TF_WARN("Unimplemented conversion: SocketType::NODE");
+ return VtValue();
+
+ case SocketType::BOOLEAN_ARRAY:
+ return convertFromCyclesArray(node->get_bool_array(socket));
+ case SocketType::FLOAT_ARRAY:
+ return convertFromCyclesArray(node->get_float_array(socket));
+ case SocketType::INT_ARRAY:
+ return convertFromCyclesArray(node->get_int_array(socket));
+ case SocketType::COLOR_ARRAY:
+ case SocketType::VECTOR_ARRAY:
+ case SocketType::POINT_ARRAY:
+ case SocketType::NORMAL_ARRAY:
+ return convertFromCyclesArray<float3, GfVec3f>(node->get_float3_array(socket));
+ case SocketType::POINT2_ARRAY:
+ return convertFromCyclesArray<float2, GfVec2f>(node->get_float2_array(socket));
+ case SocketType::STRING_ARRAY:
+ return convertFromCyclesArray<ustring, void>(node->get_string_array(socket));
+ case SocketType::TRANSFORM_ARRAY:
+ return convertFromCyclesArray<Transform, void>(node->get_transform_array(socket));
+ case SocketType::NODE_ARRAY: {
+ TF_WARN("Unimplemented conversion: SocketType::NODE_ARRAY");
+ return VtValue();
+ }
+ }
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/node_util.h b/intern/cycles/hydra/node_util.h
new file mode 100644
index 00000000000..009a4a9eb38
--- /dev/null
+++ b/intern/cycles/hydra/node_util.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "graph/node.h"
+#include "hydra/config.h"
+
+#include <pxr/base/vt/value.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+void SetNodeValue(CCL_NS::Node *node, const CCL_NS::SocketType &socket, const VtValue &value);
+
+VtValue GetNodeValue(const CCL_NS::Node *node, const CCL_NS::SocketType &socket);
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/output_driver.cpp b/intern/cycles/hydra/output_driver.cpp
new file mode 100644
index 00000000000..c5f64ac1c18
--- /dev/null
+++ b/intern/cycles/hydra/output_driver.cpp
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/output_driver.h"
+#include "hydra/render_buffer.h"
+#include "hydra/session.h"
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+HdCyclesOutputDriver::HdCyclesOutputDriver(HdCyclesSession *renderParam)
+ : _renderParam(renderParam)
+{
+}
+
+void HdCyclesOutputDriver::write_render_tile(const Tile &tile)
+{
+ update_render_tile(tile);
+
+ // Update convergence state of all render buffers
+ for (const HdRenderPassAovBinding &aovBinding : _renderParam->GetAovBindings()) {
+ if (const auto renderBuffer = static_cast<HdCyclesRenderBuffer *>(aovBinding.renderBuffer)) {
+ renderBuffer->SetConverged(true);
+ }
+ }
+}
+
+bool HdCyclesOutputDriver::update_render_tile(const Tile &tile)
+{
+ std::vector<float> pixels;
+
+ for (const HdRenderPassAovBinding &aovBinding : _renderParam->GetAovBindings()) {
+ if (aovBinding == _renderParam->GetDisplayAovBinding()) {
+ continue; // Display AOV binding is already updated by Cycles display driver
+ }
+
+ if (const auto renderBuffer = static_cast<HdCyclesRenderBuffer *>(aovBinding.renderBuffer)) {
+ const HdFormat format = renderBuffer->GetFormat();
+ if (format == HdFormatInvalid) {
+ continue; // Skip invalid AOV bindings
+ }
+
+ const size_t channels = HdGetComponentCount(format);
+ // Avoid extra copy by mapping render buffer directly when dimensions/format match the tile
+ if (tile.offset.x == 0 && tile.offset.y == 0 && tile.size.x == renderBuffer->GetWidth() &&
+ tile.size.y == renderBuffer->GetHeight() &&
+ (format >= HdFormatFloat32 && format <= HdFormatFloat32Vec4)) {
+ float *const data = static_cast<float *>(renderBuffer->Map());
+ TF_VERIFY(tile.get_pass_pixels(aovBinding.aovName.GetString(), channels, data));
+ renderBuffer->Unmap();
+ }
+ else {
+ pixels.resize(channels * tile.size.x * tile.size.y);
+ if (tile.get_pass_pixels(aovBinding.aovName.GetString(), channels, pixels.data())) {
+ const bool isId = aovBinding.aovName == HdAovTokens->primId ||
+ aovBinding.aovName == HdAovTokens->elementId ||
+ aovBinding.aovName == HdAovTokens->instanceId;
+
+ renderBuffer->WritePixels(pixels.data(),
+ GfVec2i(tile.offset.x, tile.offset.y),
+ GfVec2i(tile.size.x, tile.size.y),
+ channels,
+ isId);
+ }
+ else {
+ // Do not warn on missing elementId, which is a standard AOV but is not implememted
+ if (aovBinding.aovName != HdAovTokens->elementId) {
+ TF_RUNTIME_ERROR("Could not find pass for AOV '%s'", aovBinding.aovName.GetText());
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/output_driver.h b/intern/cycles/hydra/output_driver.h
new file mode 100644
index 00000000000..f10adfccf43
--- /dev/null
+++ b/intern/cycles/hydra/output_driver.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+#include "session/output_driver.h"
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesOutputDriver final : public CCL_NS::OutputDriver {
+ public:
+ HdCyclesOutputDriver(HdCyclesSession *renderParam);
+
+ private:
+ void write_render_tile(const Tile &tile) override;
+ bool update_render_tile(const Tile &tile) override;
+
+ HdCyclesSession *const _renderParam;
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/plugInfo.json b/intern/cycles/hydra/plugInfo.json
new file mode 100644
index 00000000000..2e20f3d66a7
--- /dev/null
+++ b/intern/cycles/hydra/plugInfo.json
@@ -0,0 +1,3 @@
+{
+ "Includes": [ "*/resources/" ]
+}
diff --git a/intern/cycles/hydra/plugin.cpp b/intern/cycles/hydra/plugin.cpp
new file mode 100644
index 00000000000..8caca3068df
--- /dev/null
+++ b/intern/cycles/hydra/plugin.cpp
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/plugin.h"
+#include "hydra/render_delegate.h"
+#include "util/log.h"
+#include "util/path.h"
+
+#include <pxr/base/arch/filesystem.h>
+#include <pxr/base/plug/plugin.h>
+#include <pxr/base/plug/thisPlugin.h>
+#include <pxr/base/tf/envSetting.h>
+#include <pxr/imaging/hd/rendererPluginRegistry.h>
+
+PXR_NAMESPACE_OPEN_SCOPE
+
+#ifdef WITH_CYCLES_LOGGING
+TF_DEFINE_ENV_SETTING(CYCLES_LOGGING, false, "Enable Cycles logging")
+TF_DEFINE_ENV_SETTING(CYCLES_LOGGING_SEVERITY, 1, "Cycles logging verbosity")
+#endif
+
+HdCyclesPlugin::HdCyclesPlugin()
+{
+ const PlugPluginPtr plugin = PLUG_THIS_PLUGIN;
+ // Initialize Cycles paths relative to the plugin resource path
+ std::string rootPath = PXR_NS::ArchAbsPath(plugin->GetResourcePath());
+ CCL_NS::path_init(std::move(rootPath));
+
+#ifdef WITH_CYCLES_LOGGING
+ if (TfGetEnvSetting(CYCLES_LOGGING)) {
+ CCL_NS::util_logging_start();
+ CCL_NS::util_logging_verbosity_set(TfGetEnvSetting(CYCLES_LOGGING_SEVERITY));
+ }
+#endif
+}
+
+HdCyclesPlugin::~HdCyclesPlugin()
+{
+}
+
+bool HdCyclesPlugin::IsSupported() const
+{
+ return true;
+}
+
+HdRenderDelegate *HdCyclesPlugin::CreateRenderDelegate()
+{
+ return CreateRenderDelegate({});
+}
+
+HdRenderDelegate *HdCyclesPlugin::CreateRenderDelegate(const HdRenderSettingsMap &settingsMap)
+{
+ return new HD_CYCLES_NS::HdCyclesDelegate(settingsMap);
+}
+
+void HdCyclesPlugin::DeleteRenderDelegate(HdRenderDelegate *renderDelegate)
+{
+ delete renderDelegate;
+}
+
+// USD's type system accounts for namespace, so we'd have to register our name as
+// HdCycles::HdCyclesPlugin in plugInfo.json, which isn't all that bad for JSON,
+// but those colons may cause issues for any USD specific tooling. So just put our
+// plugin class in the pxr namespace (which USD's type system will elide).
+TF_REGISTRY_FUNCTION(TfType)
+{
+ HdRendererPluginRegistry::Define<PXR_NS::HdCyclesPlugin>();
+}
+
+PXR_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/plugin.h b/intern/cycles/hydra/plugin.h
new file mode 100644
index 00000000000..0a76c827fda
--- /dev/null
+++ b/intern/cycles/hydra/plugin.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+#include <pxr/imaging/hd/rendererPlugin.h>
+
+PXR_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesPlugin final : public PXR_NS::HdRendererPlugin {
+ public:
+ HdCyclesPlugin();
+ ~HdCyclesPlugin() override;
+
+ bool IsSupported() const override;
+
+ PXR_NS::HdRenderDelegate *CreateRenderDelegate() override;
+ PXR_NS::HdRenderDelegate *CreateRenderDelegate(const PXR_NS::HdRenderSettingsMap &) override;
+
+ void DeleteRenderDelegate(PXR_NS::HdRenderDelegate *) override;
+};
+
+PXR_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/pointcloud.cpp b/intern/cycles/hydra/pointcloud.cpp
new file mode 100644
index 00000000000..8d43fd8bfcd
--- /dev/null
+++ b/intern/cycles/hydra/pointcloud.cpp
@@ -0,0 +1,199 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/pointcloud.h"
+#include "hydra/geometry.inl"
+#include "scene/pointcloud.h"
+
+#include <pxr/imaging/hd/extComputationUtils.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+HdCyclesPoints::HdCyclesPoints(const SdfPath &rprimId
+#if PXR_VERSION < 2102
+ ,
+ const SdfPath &instancerId
+#endif
+ )
+ : HdCyclesGeometry(rprimId
+#if PXR_VERSION < 2102
+ ,
+ instancerId
+#endif
+ )
+{
+}
+
+HdCyclesPoints::~HdCyclesPoints()
+{
+}
+
+HdDirtyBits HdCyclesPoints::GetInitialDirtyBitsMask() const
+{
+ HdDirtyBits bits = HdCyclesGeometry::GetInitialDirtyBitsMask();
+ bits |= HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyWidths |
+ HdChangeTracker::DirtyPrimvar;
+ return bits;
+}
+
+HdDirtyBits HdCyclesPoints::_PropagateDirtyBits(HdDirtyBits bits) const
+{
+ // Points and widths always have to be updated together
+ if (bits & (HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyWidths)) {
+ bits |= HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyWidths;
+ }
+
+ return bits;
+}
+
+void HdCyclesPoints::Populate(HdSceneDelegate *sceneDelegate, HdDirtyBits dirtyBits, bool &rebuild)
+{
+ if (dirtyBits & (HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyWidths)) {
+ const size_t numPoints = _geom->num_points();
+
+ PopulatePoints(sceneDelegate);
+ PopulateWidths(sceneDelegate);
+
+ rebuild = _geom->num_points() != numPoints;
+
+ array<int> shaders;
+ shaders.reserve(_geom->num_points());
+ for (size_t i = 0; i < _geom->num_points(); ++i) {
+ shaders.push_back_reserved(0);
+ }
+
+ _geom->set_shader(shaders);
+ }
+
+ if (dirtyBits & HdChangeTracker::DirtyPrimvar) {
+ PopulatePrimvars(sceneDelegate);
+ }
+}
+
+void HdCyclesPoints::PopulatePoints(HdSceneDelegate *sceneDelegate)
+{
+ VtValue value;
+
+ for (const HdExtComputationPrimvarDescriptor &desc :
+ sceneDelegate->GetExtComputationPrimvarDescriptors(GetId(), HdInterpolationVertex)) {
+ if (desc.name == HdTokens->points) {
+ auto valueStore = HdExtComputationUtils::GetComputedPrimvarValues({desc}, sceneDelegate);
+ const auto valueStoreIt = valueStore.find(desc.name);
+ if (valueStoreIt != valueStore.end()) {
+ value = std::move(valueStoreIt->second);
+ }
+ break;
+ }
+ }
+
+ if (value.IsEmpty()) {
+ value = GetPrimvar(sceneDelegate, HdTokens->points);
+ }
+
+ if (!value.IsHolding<VtVec3fArray>()) {
+ TF_WARN("Invalid points data for %s", GetId().GetText());
+ return;
+ }
+
+ const auto &points = value.UncheckedGet<VtVec3fArray>();
+
+ array<float3> pointsDataCycles;
+ pointsDataCycles.reserve(points.size());
+
+ for (const GfVec3f &point : points) {
+ pointsDataCycles.push_back_reserved(make_float3(point[0], point[1], point[2]));
+ }
+
+ _geom->set_points(pointsDataCycles);
+}
+
+void HdCyclesPoints::PopulateWidths(HdSceneDelegate *sceneDelegate)
+{
+ VtValue value = GetPrimvar(sceneDelegate, HdTokens->widths);
+ const HdInterpolation interpolation = GetPrimvarInterpolation(sceneDelegate, HdTokens->widths);
+
+ if (!value.IsHolding<VtFloatArray>()) {
+ TF_WARN("Invalid widths data for %s", GetId().GetText());
+ return;
+ }
+
+ const auto &widths = value.UncheckedGet<VtFloatArray>();
+
+ array<float> radiusDataCycles;
+ radiusDataCycles.reserve(_geom->num_points());
+
+ if (interpolation == HdInterpolationConstant) {
+ TF_VERIFY(widths.size() == 1);
+
+ const float constantRadius = widths[0] * 0.5f;
+
+ for (size_t i = 0; i < _geom->num_points(); ++i) {
+ radiusDataCycles.push_back_reserved(constantRadius);
+ }
+ }
+ else if (interpolation == HdInterpolationVertex) {
+ TF_VERIFY(widths.size() == _geom->num_points());
+
+ for (size_t i = 0; i < _geom->num_points(); ++i) {
+ radiusDataCycles.push_back_reserved(widths[i] * 0.5f);
+ }
+ }
+
+ _geom->set_radius(radiusDataCycles);
+}
+
+void HdCyclesPoints::PopulatePrimvars(HdSceneDelegate *sceneDelegate)
+{
+ Scene *const scene = (Scene *)_geom->get_owner();
+
+ const std::pair<HdInterpolation, AttributeElement> interpolations[] = {
+ std::make_pair(HdInterpolationVertex, ATTR_ELEMENT_VERTEX),
+ std::make_pair(HdInterpolationConstant, ATTR_ELEMENT_OBJECT),
+ };
+
+ for (const auto &interpolation : interpolations) {
+ for (const HdPrimvarDescriptor &desc :
+ GetPrimvarDescriptors(sceneDelegate, interpolation.first)) {
+ // Skip special primvars that are handled separately
+ if (desc.name == HdTokens->points || desc.name == HdTokens->widths) {
+ continue;
+ }
+
+ VtValue value = GetPrimvar(sceneDelegate, desc.name);
+ if (value.IsEmpty()) {
+ continue;
+ }
+
+ const ustring name(desc.name.GetString());
+
+ AttributeStandard std = ATTR_STD_NONE;
+ if (desc.role == HdPrimvarRoleTokens->textureCoordinate) {
+ std = ATTR_STD_UV;
+ }
+ else if (interpolation.first == HdInterpolationVertex) {
+ if (desc.name == HdTokens->displayColor || desc.role == HdPrimvarRoleTokens->color) {
+ std = ATTR_STD_VERTEX_COLOR;
+ }
+ else if (desc.name == HdTokens->normals) {
+ std = ATTR_STD_VERTEX_NORMAL;
+ }
+ }
+ else if (desc.name == HdTokens->displayColor &&
+ interpolation.first == HdInterpolationConstant) {
+ if (value.IsHolding<VtVec3fArray>() && value.GetArraySize() == 1) {
+ const GfVec3f color = value.UncheckedGet<VtVec3fArray>()[0];
+ _instances[0]->set_color(make_float3(color[0], color[1], color[2]));
+ }
+ }
+
+ // Skip attributes that are not needed
+ if ((std != ATTR_STD_NONE && _geom->need_attribute(scene, std)) ||
+ _geom->need_attribute(scene, name)) {
+ ApplyPrimvars(_geom->attributes, name, value, interpolation.second, std);
+ }
+ }
+ }
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/pointcloud.h b/intern/cycles/hydra/pointcloud.h
new file mode 100644
index 00000000000..a014a389dcc
--- /dev/null
+++ b/intern/cycles/hydra/pointcloud.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+#include "hydra/geometry.h"
+
+#include <pxr/imaging/hd/points.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesPoints final : public HdCyclesGeometry<PXR_NS::HdPoints, CCL_NS::PointCloud> {
+ public:
+ HdCyclesPoints(
+ const PXR_NS::SdfPath &rprimId
+#if PXR_VERSION < 2102
+ ,
+ const PXR_NS::SdfPath &instancerId = {}
+#endif
+ );
+ ~HdCyclesPoints() override;
+
+ PXR_NS::HdDirtyBits GetInitialDirtyBitsMask() const override;
+
+ private:
+ PXR_NS::HdDirtyBits _PropagateDirtyBits(PXR_NS::HdDirtyBits bits) const override;
+
+ void Populate(PXR_NS::HdSceneDelegate *sceneDelegate,
+ PXR_NS::HdDirtyBits dirtyBits,
+ bool &rebuild) override;
+
+ void PopulatePoints(PXR_NS::HdSceneDelegate *sceneDelegate);
+ void PopulateWidths(PXR_NS::HdSceneDelegate *sceneDelegate);
+
+ void PopulatePrimvars(PXR_NS::HdSceneDelegate *sceneDelegate);
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/render_buffer.cpp b/intern/cycles/hydra/render_buffer.cpp
new file mode 100644
index 00000000000..4867def0624
--- /dev/null
+++ b/intern/cycles/hydra/render_buffer.cpp
@@ -0,0 +1,276 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/render_buffer.h"
+#include "hydra/session.h"
+#include "util/half.h"
+
+#include <pxr/base/gf/vec3i.h>
+#include <pxr/base/gf/vec4f.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+HdCyclesRenderBuffer::HdCyclesRenderBuffer(const SdfPath &bprimId) : HdRenderBuffer(bprimId)
+{
+}
+
+HdCyclesRenderBuffer::~HdCyclesRenderBuffer()
+{
+}
+
+void HdCyclesRenderBuffer::Finalize(HdRenderParam *renderParam)
+{
+ // Remove this render buffer from AOV bindings
+ // This ensures that 'OutputDriver' does not attempt to write to it anymore
+ static_cast<HdCyclesSession *>(renderParam)->RemoveAovBinding(this);
+
+ HdRenderBuffer::Finalize(renderParam);
+}
+
+bool HdCyclesRenderBuffer::Allocate(const GfVec3i &dimensions, HdFormat format, bool multiSampled)
+{
+ if (dimensions[2] != 1) {
+ TF_RUNTIME_ERROR("HdCyclesRenderBuffer::Allocate called with dimensions that are not 2D.");
+ return false;
+ }
+
+ const size_t oldSize = _data.size();
+ const size_t newSize = dimensions[0] * dimensions[1] * HdDataSizeOfFormat(format);
+ if (oldSize == newSize) {
+ return true;
+ }
+
+ if (IsMapped()) {
+ TF_RUNTIME_ERROR("HdCyclesRenderBuffer::Allocate called while buffer is mapped.");
+ return false;
+ }
+
+ _width = dimensions[0];
+ _height = dimensions[1];
+ _format = format;
+
+ _data.resize(newSize);
+
+ return true;
+}
+
+void HdCyclesRenderBuffer::_Deallocate()
+{
+ _width = 0u;
+ _height = 0u;
+ _format = HdFormatInvalid;
+
+ _data.clear();
+ _data.shrink_to_fit();
+
+ _resource = VtValue();
+}
+
+void *HdCyclesRenderBuffer::Map()
+{
+ // Mapping is not implemented when a resource is set
+ if (!_resource.IsEmpty()) {
+ return nullptr;
+ }
+
+ ++_mapped;
+
+ return _data.data();
+}
+
+void HdCyclesRenderBuffer::Unmap()
+{
+ --_mapped;
+}
+
+bool HdCyclesRenderBuffer::IsMapped() const
+{
+ return _mapped != 0;
+}
+
+void HdCyclesRenderBuffer::Resolve()
+{
+}
+
+bool HdCyclesRenderBuffer::IsConverged() const
+{
+ return _converged;
+}
+
+void HdCyclesRenderBuffer::SetConverged(bool converged)
+{
+ _converged = converged;
+}
+
+VtValue HdCyclesRenderBuffer::GetResource(bool multiSampled) const
+{
+ TF_UNUSED(multiSampled);
+
+ return _resource;
+}
+
+void HdCyclesRenderBuffer::SetResource(const VtValue &resource)
+{
+ _resource = resource;
+}
+
+namespace {
+
+struct SimpleConversion {
+ static float convert(float value)
+ {
+ return value;
+ }
+};
+struct IdConversion {
+ static int32_t convert(float value)
+ {
+ return static_cast<int32_t>(value) - 1;
+ }
+};
+struct UInt8Conversion {
+ static uint8_t convert(float value)
+ {
+ return static_cast<uint8_t>(value * 255.f);
+ }
+};
+struct SInt8Conversion {
+ static int8_t convert(float value)
+ {
+ return static_cast<int8_t>(value * 127.f);
+ }
+};
+struct HalfConversion {
+ static half convert(float value)
+ {
+ return float_to_half_image(value);
+ }
+};
+
+template<typename SrcT, typename DstT, typename Convertor = SimpleConversion>
+void writePixels(const SrcT *srcPtr,
+ const GfVec2i &srcSize,
+ int srcChannelCount,
+ DstT *dstPtr,
+ const GfVec2i &dstSize,
+ int dstChannelCount,
+ const Convertor &convertor = {})
+{
+ const auto writeSize = GfVec2i(GfMin(srcSize[0], dstSize[0]), GfMin(srcSize[1], dstSize[1]));
+ const auto writeChannelCount = GfMin(srcChannelCount, dstChannelCount);
+
+ for (int y = 0; y < writeSize[1]; ++y) {
+ for (int x = 0; x < writeSize[0]; ++x) {
+ for (int c = 0; c < writeChannelCount; ++c) {
+ dstPtr[x * dstChannelCount + c] = convertor.convert(srcPtr[x * srcChannelCount + c]);
+ }
+ }
+ srcPtr += srcSize[0] * srcChannelCount;
+ dstPtr += dstSize[0] * dstChannelCount;
+ }
+}
+
+} // namespace
+
+void HdCyclesRenderBuffer::WritePixels(const float *srcPixels,
+ const PXR_NS::GfVec2i &srcOffset,
+ const GfVec2i &srcDims,
+ int srcChannels,
+ bool isId)
+{
+ uint8_t *dstPixels = _data.data();
+
+ const size_t formatSize = HdDataSizeOfFormat(_format);
+ dstPixels += srcOffset[1] * (formatSize * _width) + srcOffset[0] * formatSize;
+
+ switch (_format) {
+ case HdFormatUNorm8:
+ case HdFormatUNorm8Vec2:
+ case HdFormatUNorm8Vec3:
+ case HdFormatUNorm8Vec4:
+ writePixels(srcPixels,
+ srcDims,
+ srcChannels,
+ dstPixels,
+ GfVec2i(_width, _height),
+ 1 + (_format - HdFormatUNorm8),
+ UInt8Conversion());
+ break;
+
+ case HdFormatSNorm8:
+ case HdFormatSNorm8Vec2:
+ case HdFormatSNorm8Vec3:
+ case HdFormatSNorm8Vec4:
+ writePixels(srcPixels,
+ srcDims,
+ srcChannels,
+ dstPixels,
+ GfVec2i(_width, _height),
+ 1 + (_format - HdFormatSNorm8),
+ SInt8Conversion());
+ break;
+
+ case HdFormatFloat16:
+ case HdFormatFloat16Vec2:
+ case HdFormatFloat16Vec3:
+ case HdFormatFloat16Vec4:
+ writePixels(srcPixels,
+ srcDims,
+ srcChannels,
+ reinterpret_cast<half *>(dstPixels),
+ GfVec2i(_width, _height),
+ 1 + (_format - HdFormatFloat16),
+ HalfConversion());
+ break;
+
+ case HdFormatFloat32:
+ case HdFormatFloat32Vec2:
+ case HdFormatFloat32Vec3:
+ case HdFormatFloat32Vec4:
+ writePixels(srcPixels,
+ srcDims,
+ srcChannels,
+ reinterpret_cast<float *>(dstPixels),
+ GfVec2i(_width, _height),
+ 1 + (_format - HdFormatFloat32));
+ break;
+
+ case HdFormatInt32:
+ // Special case for ID AOVs (see 'HdCyclesMesh::Sync')
+ if (isId) {
+ writePixels(srcPixels,
+ srcDims,
+ srcChannels,
+ reinterpret_cast<int *>(dstPixels),
+ GfVec2i(_width, _height),
+ 1,
+ IdConversion());
+ }
+ else {
+ writePixels(srcPixels,
+ srcDims,
+ srcChannels,
+ reinterpret_cast<int *>(dstPixels),
+ GfVec2i(_width, _height),
+ 1);
+ }
+ break;
+ case HdFormatInt32Vec2:
+ case HdFormatInt32Vec3:
+ case HdFormatInt32Vec4:
+ writePixels(srcPixels,
+ srcDims,
+ srcChannels,
+ reinterpret_cast<int *>(dstPixels),
+ GfVec2i(_width, _height),
+ 1 + (_format - HdFormatInt32));
+ break;
+
+ default:
+ TF_RUNTIME_ERROR("HdCyclesRenderBuffer::WritePixels called with unsupported format.");
+ break;
+ }
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/render_buffer.h b/intern/cycles/hydra/render_buffer.h
new file mode 100644
index 00000000000..8eb874f0068
--- /dev/null
+++ b/intern/cycles/hydra/render_buffer.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+
+#include <pxr/imaging/hd/renderBuffer.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesRenderBuffer final : public PXR_NS::HdRenderBuffer {
+ public:
+ HdCyclesRenderBuffer(const PXR_NS::SdfPath &bprimId);
+ ~HdCyclesRenderBuffer() override;
+
+ void Finalize(PXR_NS::HdRenderParam *renderParam) override;
+
+ bool Allocate(const PXR_NS::GfVec3i &dimensions,
+ PXR_NS::HdFormat format,
+ bool multiSampled) override;
+
+ unsigned int GetWidth() const override
+ {
+ return _width;
+ }
+
+ unsigned int GetHeight() const override
+ {
+ return _height;
+ }
+
+ unsigned int GetDepth() const override
+ {
+ return 1u;
+ }
+
+ PXR_NS::HdFormat GetFormat() const override
+ {
+ return _format;
+ }
+
+ bool IsMultiSampled() const override
+ {
+ return false;
+ }
+
+ void *Map() override;
+
+ void Unmap() override;
+
+ bool IsMapped() const override;
+
+ void Resolve() override;
+
+ bool IsConverged() const override;
+
+ void SetConverged(bool converged);
+
+ PXR_NS::VtValue GetResource(bool multiSampled = false) const override;
+
+ void SetResource(const PXR_NS::VtValue &resource);
+
+ void WritePixels(const float *pixels,
+ const PXR_NS::GfVec2i &offset,
+ const PXR_NS::GfVec2i &dims,
+ int channels,
+ bool isId = false);
+
+ private:
+ void _Deallocate() override;
+
+ unsigned int _width = 0u;
+ unsigned int _height = 0u;
+ PXR_NS::HdFormat _format = PXR_NS::HdFormatInvalid;
+
+ std::vector<uint8_t> _data;
+ PXR_NS::VtValue _resource;
+
+ std::atomic_int _mapped = 0;
+ std::atomic_bool _converged = false;
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/render_delegate.cpp b/intern/cycles/hydra/render_delegate.cpp
new file mode 100644
index 00000000000..748b6a66e1e
--- /dev/null
+++ b/intern/cycles/hydra/render_delegate.cpp
@@ -0,0 +1,514 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/render_delegate.h"
+#include "hydra/camera.h"
+#include "hydra/curves.h"
+#include "hydra/field.h"
+#include "hydra/instancer.h"
+#include "hydra/light.h"
+#include "hydra/material.h"
+#include "hydra/mesh.h"
+#include "hydra/node_util.h"
+#include "hydra/pointcloud.h"
+#include "hydra/render_buffer.h"
+#include "hydra/render_pass.h"
+#include "hydra/session.h"
+#include "hydra/volume.h"
+#include "scene/integrator.h"
+#include "scene/scene.h"
+#include "session/session.h"
+
+#include <pxr/base/tf/getenv.h>
+#include <pxr/imaging/hd/extComputation.h>
+#include <pxr/imaging/hgi/tokens.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+// clang-format off
+TF_DEFINE_PRIVATE_TOKENS(_tokens,
+ (cycles)
+ (openvdbAsset)
+);
+
+TF_DEFINE_PRIVATE_TOKENS(HdCyclesRenderSettingsTokens,
+ ((device, "cycles:device"))
+ ((threads, "cycles:threads"))
+ ((time_limit, "cycles:time_limit"))
+ ((samples, "cycles:samples"))
+ ((sample_offset, "cycles:sample_offset"))
+);
+// clang-format on
+
+namespace {
+
+const TfTokenVector kSupportedRPrimTypes = {
+ HdPrimTypeTokens->basisCurves,
+ HdPrimTypeTokens->mesh,
+ HdPrimTypeTokens->points,
+#ifdef WITH_OPENVDB
+ HdPrimTypeTokens->volume,
+#endif
+};
+
+const TfTokenVector kSupportedSPrimTypes = {
+ HdPrimTypeTokens->camera,
+ HdPrimTypeTokens->material,
+ HdPrimTypeTokens->diskLight,
+ HdPrimTypeTokens->distantLight,
+ HdPrimTypeTokens->domeLight,
+ HdPrimTypeTokens->rectLight,
+ HdPrimTypeTokens->sphereLight,
+ HdPrimTypeTokens->extComputation,
+};
+
+const TfTokenVector kSupportedBPrimTypes = {
+ HdPrimTypeTokens->renderBuffer,
+#ifdef WITH_OPENVDB
+ _tokens->openvdbAsset,
+#endif
+};
+
+SessionParams GetSessionParams(const HdRenderSettingsMap &settings)
+{
+ SessionParams params;
+ params.threads = 0;
+ params.background = false;
+ params.use_resolution_divider = false;
+
+ HdRenderSettingsMap::const_iterator it;
+
+ // Pull all setting that contribute to device creation first
+ it = settings.find(HdCyclesRenderSettingsTokens->threads);
+ if (it != settings.end()) {
+ params.threads = VtValue::Cast<int>(it->second).GetWithDefault(params.threads);
+ }
+
+ // Get the Cycles device from settings or environment, falling back to CPU
+ std::string deviceType = Device::string_from_type(DEVICE_CPU);
+ it = settings.find(HdCyclesRenderSettingsTokens->device);
+ if (it != settings.end()) {
+ deviceType = VtValue::Cast<std::string>(it->second).GetWithDefault(deviceType);
+ }
+ else {
+ const std::string deviceTypeEnv = TfGetenv("CYCLES_DEVICE");
+ if (!deviceTypeEnv.empty()) {
+ deviceType = deviceTypeEnv;
+ }
+ }
+
+ // Move to all uppercase for Device::type_from_string
+ std::transform(deviceType.begin(), deviceType.end(), deviceType.begin(), ::toupper);
+
+ vector<DeviceInfo> devices = Device::available_devices(
+ DEVICE_MASK(Device::type_from_string(deviceType.c_str())));
+ if (devices.empty()) {
+ devices = Device::available_devices(DEVICE_MASK_CPU);
+ if (!devices.empty()) {
+ params.device = devices.front();
+ }
+ }
+ else {
+ params.device = Device::get_multi_device(devices, params.threads, params.background);
+ }
+
+ return params;
+}
+
+} // namespace
+
+HdCyclesDelegate::HdCyclesDelegate(const HdRenderSettingsMap &settingsMap, Session *session_)
+ : HdRenderDelegate()
+{
+ _renderParam = session_ ? std::make_unique<HdCyclesSession>(session_) :
+ std::make_unique<HdCyclesSession>(GetSessionParams(settingsMap));
+
+ // If the delegate owns the session, pull any remaining settings
+ if (!session_) {
+ for (const auto &setting : settingsMap) {
+ // Skip over the settings known to be used for initialization only
+ if (setting.first == HdCyclesRenderSettingsTokens->device ||
+ setting.first == HdCyclesRenderSettingsTokens->threads) {
+ continue;
+ }
+
+ SetRenderSetting(setting.first, setting.second);
+ }
+ }
+}
+
+HdCyclesDelegate::~HdCyclesDelegate()
+{
+}
+
+void HdCyclesDelegate::SetDrivers(const HdDriverVector &drivers)
+{
+ for (HdDriver *hdDriver : drivers) {
+ if (hdDriver->name == HgiTokens->renderDriver && hdDriver->driver.IsHolding<Hgi *>()) {
+ _hgi = hdDriver->driver.UncheckedGet<Hgi *>();
+ break;
+ }
+ }
+}
+
+bool HdCyclesDelegate::IsDisplaySupported() const
+{
+#ifdef _WIN32
+ return _hgi && _hgi->GetAPIName() == HgiTokens->OpenGL;
+#else
+ return false;
+#endif
+}
+
+const TfTokenVector &HdCyclesDelegate::GetSupportedRprimTypes() const
+{
+ return kSupportedRPrimTypes;
+}
+
+const TfTokenVector &HdCyclesDelegate::GetSupportedSprimTypes() const
+{
+ return kSupportedSPrimTypes;
+}
+
+const TfTokenVector &HdCyclesDelegate::GetSupportedBprimTypes() const
+{
+ return kSupportedBPrimTypes;
+}
+
+HdRenderParam *HdCyclesDelegate::GetRenderParam() const
+{
+ return _renderParam.get();
+}
+
+HdResourceRegistrySharedPtr HdCyclesDelegate::GetResourceRegistry() const
+{
+ return HdResourceRegistrySharedPtr();
+}
+
+bool HdCyclesDelegate::IsPauseSupported() const
+{
+ return true;
+}
+
+bool HdCyclesDelegate::Pause()
+{
+ _renderParam->session->set_pause(true);
+ return true;
+}
+
+bool HdCyclesDelegate::Resume()
+{
+ _renderParam->session->set_pause(false);
+ return true;
+}
+
+HdRenderPassSharedPtr HdCyclesDelegate::CreateRenderPass(HdRenderIndex *index,
+ const HdRprimCollection &collection)
+{
+ return HdRenderPassSharedPtr(new HdCyclesRenderPass(index, collection, _renderParam.get()));
+}
+
+HdInstancer *HdCyclesDelegate::CreateInstancer(HdSceneDelegate *delegate,
+ const SdfPath &instancerId
+#if PXR_VERSION < 2102
+ ,
+ const SdfPath &parentId
+#endif
+)
+{
+ return new HdCyclesInstancer(delegate,
+ instancerId
+#if PXR_VERSION < 2102
+ ,
+ parentId
+#endif
+ );
+}
+
+void HdCyclesDelegate::DestroyInstancer(HdInstancer *instancer)
+{
+ delete instancer;
+}
+
+HdRprim *HdCyclesDelegate::CreateRprim(const TfToken &typeId,
+ const SdfPath &rprimId
+#if PXR_VERSION < 2102
+ ,
+ const SdfPath &instancerId
+#endif
+)
+{
+ if (typeId == HdPrimTypeTokens->mesh) {
+ return new HdCyclesMesh(rprimId
+#if PXR_VERSION < 2102
+ ,
+ instancerId
+#endif
+ );
+ }
+ if (typeId == HdPrimTypeTokens->basisCurves) {
+ return new HdCyclesCurves(rprimId
+#if PXR_VERSION < 2102
+ ,
+ instancerId
+#endif
+ );
+ }
+ if (typeId == HdPrimTypeTokens->points) {
+ return new HdCyclesPoints(rprimId
+#if PXR_VERSION < 2102
+ ,
+ instancerId
+#endif
+ );
+ }
+#ifdef WITH_OPENVDB
+ if (typeId == HdPrimTypeTokens->volume) {
+ return new HdCyclesVolume(rprimId
+# if PXR_VERSION < 2102
+ ,
+ instancerId
+# endif
+ );
+ }
+#endif
+
+ TF_CODING_ERROR("Unknown Rprim type %s", typeId.GetText());
+ return nullptr;
+}
+
+void HdCyclesDelegate::DestroyRprim(HdRprim *rPrim)
+{
+ delete rPrim;
+}
+
+HdSprim *HdCyclesDelegate::CreateSprim(const TfToken &typeId, const SdfPath &sprimId)
+{
+ if (typeId == HdPrimTypeTokens->camera) {
+ return new HdCyclesCamera(sprimId);
+ }
+ if (typeId == HdPrimTypeTokens->material) {
+ return new HdCyclesMaterial(sprimId);
+ }
+ if (typeId == HdPrimTypeTokens->diskLight || typeId == HdPrimTypeTokens->distantLight ||
+ typeId == HdPrimTypeTokens->domeLight || typeId == HdPrimTypeTokens->rectLight ||
+ typeId == HdPrimTypeTokens->sphereLight) {
+ return new HdCyclesLight(sprimId, typeId);
+ }
+ if (typeId == HdPrimTypeTokens->extComputation) {
+ return new HdExtComputation(sprimId);
+ }
+
+ TF_CODING_ERROR("Unknown Sprim type %s", typeId.GetText());
+ return nullptr;
+}
+
+HdSprim *HdCyclesDelegate::CreateFallbackSprim(const TfToken &typeId)
+{
+ return CreateSprim(typeId, SdfPath::EmptyPath());
+}
+
+void HdCyclesDelegate::DestroySprim(HdSprim *sPrim)
+{
+ delete sPrim;
+}
+
+HdBprim *HdCyclesDelegate::CreateBprim(const TfToken &typeId, const SdfPath &bprimId)
+{
+ if (typeId == HdPrimTypeTokens->renderBuffer) {
+ return new HdCyclesRenderBuffer(bprimId);
+ }
+#ifdef WITH_OPENVDB
+ if (typeId == _tokens->openvdbAsset) {
+ return new HdCyclesField(bprimId, typeId);
+ }
+#endif
+
+ TF_RUNTIME_ERROR("Unknown Bprim type %s", typeId.GetText());
+ return nullptr;
+}
+
+HdBprim *HdCyclesDelegate::CreateFallbackBprim(const TfToken &typeId)
+{
+ return CreateBprim(typeId, SdfPath::EmptyPath());
+}
+
+void HdCyclesDelegate::DestroyBprim(HdBprim *bPrim)
+{
+ delete bPrim;
+}
+
+void HdCyclesDelegate::CommitResources(HdChangeTracker *tracker)
+{
+ TF_UNUSED(tracker);
+
+ const SceneLock lock(_renderParam.get());
+
+ _renderParam->UpdateScene();
+}
+
+TfToken HdCyclesDelegate::GetMaterialBindingPurpose() const
+{
+ return HdTokens->full;
+}
+
+#if HD_API_VERSION < 41
+TfToken HdCyclesDelegate::GetMaterialNetworkSelector() const
+{
+ return _tokens->cycles;
+}
+#else
+TfTokenVector HdCyclesDelegate::GetMaterialRenderContexts() const
+{
+ return {_tokens->cycles};
+}
+#endif
+
+VtDictionary HdCyclesDelegate::GetRenderStats() const
+{
+ const Stats &stats = _renderParam->session->stats;
+ const Progress &progress = _renderParam->session->progress;
+
+ double totalTime, renderTime;
+ progress.get_time(totalTime, renderTime);
+ double fractionDone = progress.get_progress();
+
+ std::string status, substatus;
+ progress.get_status(status, substatus);
+ if (!substatus.empty()) {
+ status += " | " + substatus;
+ }
+
+ return {{"rendererName", VtValue("Cycles")},
+ {"rendererVersion", VtValue(GfVec3i(0, 0, 0))},
+ {"percentDone", VtValue(floor_to_int(fractionDone * 100))},
+ {"fractionDone", VtValue(fractionDone)},
+ {"loadClockTime", VtValue(totalTime - renderTime)},
+ {"peakMemory", VtValue(stats.mem_peak)},
+ {"totalClockTime", VtValue(totalTime)},
+ {"totalMemory", VtValue(stats.mem_used)},
+ {"renderProgressAnnotation", VtValue(status)}};
+}
+
+HdAovDescriptor HdCyclesDelegate::GetDefaultAovDescriptor(const TfToken &name) const
+{
+ if (name == HdAovTokens->color) {
+ HdFormat colorFormat = HdFormatFloat32Vec4;
+ if (IsDisplaySupported()) {
+ // Can use Cycles 'DisplayDriver' in OpenGL, but it only supports 'half4' format
+ colorFormat = HdFormatFloat16Vec4;
+ }
+
+ return HdAovDescriptor(colorFormat, false, VtValue(GfVec4f(0.0f)));
+ }
+ if (name == HdAovTokens->depth) {
+ return HdAovDescriptor(HdFormatFloat32, false, VtValue(1.0f));
+ }
+ if (name == HdAovTokens->normal) {
+ return HdAovDescriptor(HdFormatFloat32Vec3, false, VtValue(GfVec3f(0.0f)));
+ }
+ if (name == HdAovTokens->primId || name == HdAovTokens->instanceId ||
+ name == HdAovTokens->elementId) {
+ return HdAovDescriptor(HdFormatInt32, false, VtValue(-1));
+ }
+
+ return HdAovDescriptor();
+}
+
+HdRenderSettingDescriptorList HdCyclesDelegate::GetRenderSettingDescriptors() const
+{
+ Scene *const scene = _renderParam->session->scene;
+
+ HdRenderSettingDescriptorList descriptors;
+
+ descriptors.push_back({
+ "Time Limit",
+ HdCyclesRenderSettingsTokens->time_limit,
+ VtValue(0.0),
+ });
+ descriptors.push_back({
+ "Sample Count",
+ HdCyclesRenderSettingsTokens->samples,
+ VtValue(1024),
+ });
+ descriptors.push_back({
+ "Sample Offset",
+ HdCyclesRenderSettingsTokens->sample_offset,
+ VtValue(0),
+ });
+
+ for (const SocketType &socket : scene->integrator->type->inputs) {
+ descriptors.push_back({socket.ui_name.string(),
+ TfToken("cycles:integrator:" + socket.name.string()),
+ GetNodeValue(scene->integrator, socket)});
+ }
+
+ return descriptors;
+}
+
+void HdCyclesDelegate::SetRenderSetting(const PXR_NS::TfToken &key, const PXR_NS::VtValue &value)
+{
+ Scene *const scene = _renderParam->session->scene;
+ Session *const session = _renderParam->session;
+
+ if (key == HdCyclesRenderSettingsTokens->time_limit) {
+ session->set_time_limit(
+ VtValue::Cast<double>(value).GetWithDefault(session->params.time_limit));
+ }
+ else if (key == HdCyclesRenderSettingsTokens->samples) {
+ int samples = VtValue::Cast<int>(value).GetWithDefault(session->params.samples);
+ samples = std::min(std::max(1, samples), Integrator::MAX_SAMPLES);
+ session->set_samples(samples);
+ }
+ else if (key == HdCyclesRenderSettingsTokens->sample_offset) {
+ session->params.sample_offset = VtValue::Cast<int>(value).GetWithDefault(
+ session->params.sample_offset);
+ ++_settingsVersion;
+ }
+ else {
+ const std::string &keyString = key.GetString();
+ if (keyString.rfind("cycles:integrator:", 0) == 0) {
+ ustring socketName(keyString, sizeof("cycles:integrator:") - 1);
+ if (const SocketType *socket = scene->integrator->type->find_input(socketName)) {
+ SetNodeValue(scene->integrator, *socket, value);
+ ++_settingsVersion;
+ }
+ }
+ }
+}
+
+VtValue HdCyclesDelegate::GetRenderSetting(const TfToken &key) const
+{
+ Scene *const scene = _renderParam->session->scene;
+ Session *const session = _renderParam->session;
+
+ if (key == HdCyclesRenderSettingsTokens->device) {
+ return VtValue(TfToken(Device::string_from_type(session->params.device.type)));
+ }
+ else if (key == HdCyclesRenderSettingsTokens->threads) {
+ return VtValue(session->params.threads);
+ }
+ else if (key == HdCyclesRenderSettingsTokens->time_limit) {
+ return VtValue(session->params.time_limit);
+ }
+ else if (key == HdCyclesRenderSettingsTokens->samples) {
+ return VtValue(session->params.samples);
+ }
+ else if (key == HdCyclesRenderSettingsTokens->sample_offset) {
+ return VtValue(session->params.sample_offset);
+ }
+ else {
+ const std::string &keyString = key.GetString();
+ if (keyString.rfind("cycles:integrator:", 0) == 0) {
+ ustring socketName(keyString, sizeof("cycles:integrator:") - 1);
+ if (const SocketType *socket = scene->integrator->type->find_input(socketName)) {
+ return GetNodeValue(scene->integrator, *socket);
+ }
+ }
+ }
+
+ return VtValue();
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/render_delegate.h b/intern/cycles/hydra/render_delegate.h
new file mode 100644
index 00000000000..9c15c8d5281
--- /dev/null
+++ b/intern/cycles/hydra/render_delegate.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+
+#include <pxr/imaging/hd/renderDelegate.h>
+#include <pxr/imaging/hgi/hgi.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesDelegate final : public PXR_NS::HdRenderDelegate {
+ public:
+ HdCyclesDelegate(const PXR_NS::HdRenderSettingsMap &settingsMap,
+ CCL_NS::Session *session_ = nullptr);
+ ~HdCyclesDelegate() override;
+
+ void SetDrivers(const PXR_NS::HdDriverVector &drivers) override;
+
+ bool IsDisplaySupported() const;
+
+ PXR_NS::Hgi *GetHgi() const
+ {
+ return _hgi;
+ }
+
+ const PXR_NS::TfTokenVector &GetSupportedRprimTypes() const override;
+ const PXR_NS::TfTokenVector &GetSupportedSprimTypes() const override;
+ const PXR_NS::TfTokenVector &GetSupportedBprimTypes() const override;
+
+ PXR_NS::HdRenderParam *GetRenderParam() const override;
+
+ PXR_NS::HdResourceRegistrySharedPtr GetResourceRegistry() const override;
+
+ PXR_NS::HdRenderSettingDescriptorList GetRenderSettingDescriptors() const override;
+
+ bool IsPauseSupported() const override;
+
+ bool Pause() override;
+ bool Resume() override;
+
+ PXR_NS::HdRenderPassSharedPtr CreateRenderPass(
+ PXR_NS::HdRenderIndex *index, const PXR_NS::HdRprimCollection &collection) override;
+
+ PXR_NS::HdInstancer *CreateInstancer(PXR_NS::HdSceneDelegate *delegate,
+ const PXR_NS::SdfPath &id
+#if PXR_VERSION < 2102
+ ,
+ const PXR_NS::SdfPath &instancerId
+#endif
+ ) override;
+ void DestroyInstancer(PXR_NS::HdInstancer *instancer) override;
+
+ PXR_NS::HdRprim *CreateRprim(const PXR_NS::TfToken &typeId,
+ const PXR_NS::SdfPath &rprimId
+#if PXR_VERSION < 2102
+ ,
+ const PXR_NS::SdfPath &instancerId
+#endif
+ ) override;
+ void DestroyRprim(PXR_NS::HdRprim *rPrim) override;
+
+ PXR_NS::HdSprim *CreateSprim(const PXR_NS::TfToken &typeId,
+ const PXR_NS::SdfPath &sprimId) override;
+ PXR_NS::HdSprim *CreateFallbackSprim(const PXR_NS::TfToken &typeId) override;
+ void DestroySprim(PXR_NS::HdSprim *sPrim) override;
+
+ PXR_NS::HdBprim *CreateBprim(const PXR_NS::TfToken &typeId,
+ const PXR_NS::SdfPath &bprimId) override;
+ PXR_NS::HdBprim *CreateFallbackBprim(const PXR_NS::TfToken &typeId) override;
+ void DestroyBprim(PXR_NS::HdBprim *bPrim) override;
+
+ void CommitResources(PXR_NS::HdChangeTracker *tracker) override;
+
+ PXR_NS::TfToken GetMaterialBindingPurpose() const override;
+
+#if HD_API_VERSION < 41
+ PXR_NS::TfToken GetMaterialNetworkSelector() const override;
+#else
+ PXR_NS::TfTokenVector GetMaterialRenderContexts() const override;
+#endif
+
+ PXR_NS::VtDictionary GetRenderStats() const override;
+
+ PXR_NS::HdAovDescriptor GetDefaultAovDescriptor(const PXR_NS::TfToken &name) const override;
+
+ void SetRenderSetting(const PXR_NS::TfToken &key, const PXR_NS::VtValue &value) override;
+
+ PXR_NS::VtValue GetRenderSetting(const PXR_NS::TfToken &key) const override;
+
+ private:
+ PXR_NS::Hgi *_hgi = nullptr;
+ std::unique_ptr<HdCyclesSession> _renderParam;
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/render_pass.cpp b/intern/cycles/hydra/render_pass.cpp
new file mode 100644
index 00000000000..9d47dfc5c8d
--- /dev/null
+++ b/intern/cycles/hydra/render_pass.cpp
@@ -0,0 +1,175 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/render_pass.h"
+#include "hydra/camera.h"
+#include "hydra/display_driver.h"
+#include "hydra/output_driver.h"
+#include "hydra/render_buffer.h"
+#include "hydra/render_delegate.h"
+#include "hydra/session.h"
+#include "scene/camera.h"
+#include "scene/integrator.h"
+#include "scene/scene.h"
+#include "session/session.h"
+
+#include <pxr/imaging/hd/renderPassState.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+HdCyclesRenderPass::HdCyclesRenderPass(HdRenderIndex *index,
+ HdRprimCollection const &collection,
+ HdCyclesSession *renderParam)
+ : HdRenderPass(index, collection), _renderParam(renderParam)
+{
+ Session *const session = _renderParam->session;
+ // Reset cancel state so session thread can continue rendering
+ session->progress.reset();
+
+ session->set_output_driver(make_unique<HdCyclesOutputDriver>(renderParam));
+
+ const auto renderDelegate = static_cast<const HdCyclesDelegate *>(
+ GetRenderIndex()->GetRenderDelegate());
+ if (renderDelegate->IsDisplaySupported()) {
+ session->set_display_driver(
+ make_unique<HdCyclesDisplayDriver>(renderParam, renderDelegate->GetHgi()));
+ }
+}
+
+HdCyclesRenderPass::~HdCyclesRenderPass()
+{
+ Session *const session = _renderParam->session;
+ session->cancel(true);
+}
+
+bool HdCyclesRenderPass::IsConverged() const
+{
+ for (const HdRenderPassAovBinding &aovBinding : _renderParam->GetAovBindings()) {
+ if (aovBinding.renderBuffer && !aovBinding.renderBuffer->IsConverged()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void HdCyclesRenderPass::ResetConverged()
+{
+ for (const HdRenderPassAovBinding &aovBinding : _renderParam->GetAovBindings()) {
+ if (const auto renderBuffer = static_cast<HdCyclesRenderBuffer *>(aovBinding.renderBuffer)) {
+ renderBuffer->SetConverged(false);
+ }
+ }
+}
+
+void HdCyclesRenderPass::_Execute(const HdRenderPassStateSharedPtr &renderPassState,
+ const TfTokenVector &renderTags)
+{
+ Scene *const scene = _renderParam->session->scene;
+ Session *const session = _renderParam->session;
+
+ if (session->progress.get_cancel()) {
+ return; // Something went wrong and cannot continue without recreating the session
+ }
+
+ if (scene->mutex.try_lock()) {
+ const auto renderDelegate = static_cast<HdCyclesDelegate *>(
+ GetRenderIndex()->GetRenderDelegate());
+
+ const unsigned int settingsVersion = renderDelegate->GetRenderSettingsVersion();
+
+ // Update requested AOV bindings
+ const HdRenderPassAovBindingVector &aovBindings = renderPassState->GetAovBindings();
+ if (_renderParam->GetAovBindings() != aovBindings ||
+ // Need to resync passes when denoising is enabled or disabled to update the pass mode
+ (settingsVersion != _lastSettingsVersion &&
+ scene->integrator->use_denoise_is_modified())) {
+ _renderParam->SyncAovBindings(aovBindings);
+
+ if (renderDelegate->IsDisplaySupported()) {
+ // Update display pass to the first requested color AOV
+ HdRenderPassAovBinding displayAovBinding = !aovBindings.empty() ? aovBindings.front() :
+ HdRenderPassAovBinding();
+ if (displayAovBinding.aovName == HdAovTokens->color && displayAovBinding.renderBuffer) {
+ _renderParam->SetDisplayAovBinding(displayAovBinding);
+ }
+ else {
+ _renderParam->SetDisplayAovBinding(HdRenderPassAovBinding());
+ }
+ }
+ }
+
+ // Update camera dimensions to the viewport size
+#if PXR_VERSION >= 2102
+ CameraUtilFraming framing = renderPassState->GetFraming();
+ if (!framing.IsValid()) {
+ const GfVec4f vp = renderPassState->GetViewport();
+ framing = CameraUtilFraming(GfRect2i(GfVec2i(0), int(vp[2]), int(vp[3])));
+ }
+
+ scene->camera->set_full_width(framing.dataWindow.GetWidth());
+ scene->camera->set_full_height(framing.dataWindow.GetHeight());
+#else
+ const GfVec4f vp = renderPassState->GetViewport();
+ scene->camera->set_full_width(int(vp[2]));
+ scene->camera->set_full_height(int(vp[3]));
+#endif
+
+ if (const auto camera = static_cast<const HdCyclesCamera *>(renderPassState->GetCamera())) {
+ camera->ApplyCameraSettings(scene->camera);
+ }
+ else {
+ HdCyclesCamera::ApplyCameraSettings(renderPassState->GetWorldToViewMatrix(),
+ renderPassState->GetProjectionMatrix(),
+ renderPassState->GetClipPlanes(),
+ scene->camera);
+ }
+
+ // Reset session if the session, scene, camera or AOV bindings changed
+ if (scene->need_reset() || settingsVersion != _lastSettingsVersion) {
+ _lastSettingsVersion = settingsVersion;
+
+ // Reset convergence state of all render buffers
+ ResetConverged();
+
+ BufferParams buffer_params;
+#if PXR_VERSION >= 2102
+ buffer_params.full_x = static_cast<int>(framing.displayWindow.GetMin()[0]);
+ buffer_params.full_y = static_cast<int>(framing.displayWindow.GetMin()[1]);
+ buffer_params.full_width = static_cast<int>(framing.displayWindow.GetSize()[0]);
+ buffer_params.full_height = static_cast<int>(framing.displayWindow.GetSize()[1]);
+
+ buffer_params.window_x = framing.dataWindow.GetMinX() - buffer_params.full_x;
+ buffer_params.window_y = framing.dataWindow.GetMinY() - buffer_params.full_y;
+ buffer_params.window_width = framing.dataWindow.GetWidth();
+ buffer_params.window_height = framing.dataWindow.GetHeight();
+
+ buffer_params.width = buffer_params.window_width;
+ buffer_params.height = buffer_params.window_height;
+#else
+ buffer_params.width = static_cast<int>(vp[2]);
+ buffer_params.height = static_cast<int>(vp[3]);
+ buffer_params.full_width = buffer_params.width;
+ buffer_params.full_height = buffer_params.height;
+ buffer_params.window_width = buffer_params.width;
+ buffer_params.window_height = buffer_params.height;
+#endif
+
+ session->reset(session->params, buffer_params);
+ }
+
+ scene->mutex.unlock();
+
+ // Start Cycles render thread if not already running
+ session->start();
+ }
+
+ session->draw();
+}
+
+void HdCyclesRenderPass::_MarkCollectionDirty()
+{
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/render_pass.h b/intern/cycles/hydra/render_pass.h
new file mode 100644
index 00000000000..f04c97097a6
--- /dev/null
+++ b/intern/cycles/hydra/render_pass.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+
+#include <pxr/imaging/hd/renderPass.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesRenderPass final : public PXR_NS::HdRenderPass {
+ public:
+ HdCyclesRenderPass(PXR_NS::HdRenderIndex *index,
+ const PXR_NS::HdRprimCollection &collection,
+ HdCyclesSession *renderParam);
+ ~HdCyclesRenderPass() override;
+
+ bool IsConverged() const override;
+
+ private:
+ void ResetConverged();
+
+ void _Execute(const PXR_NS::HdRenderPassStateSharedPtr &renderPassState,
+ const PXR_NS::TfTokenVector &renderTags) override;
+
+ void _MarkCollectionDirty() override;
+
+ HdCyclesSession *_renderParam;
+ unsigned int _lastSettingsVersion = 0;
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/resources/plugInfo.json b/intern/cycles/hydra/resources/plugInfo.json
new file mode 100644
index 00000000000..94fe778ea44
--- /dev/null
+++ b/intern/cycles/hydra/resources/plugInfo.json
@@ -0,0 +1,22 @@
+{
+ "Plugins": [
+ {
+ "Info": {
+ "Types": {
+ "HdCyclesPlugin": {
+ "bases": [
+ "HdRendererPlugin"
+ ],
+ "displayName": "Cycles",
+ "priority": 0
+ }
+ }
+ },
+ "LibraryPath": "@PLUG_INFO_LIBRARY_PATH@",
+ "Name": "hdCycles",
+ "ResourcePath": "@PLUG_INFO_RESOURCE_PATH@",
+ "Root": "@PLUG_INFO_ROOT@",
+ "Type": "library"
+ }
+ ]
+}
diff --git a/intern/cycles/hydra/session.cpp b/intern/cycles/hydra/session.cpp
new file mode 100644
index 00000000000..f6865bdedd1
--- /dev/null
+++ b/intern/cycles/hydra/session.cpp
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/session.h"
+#include "scene/shader.h"
+// Have to include shader.h before background.h so that 'set_shader' uses the correct 'set'
+// overload taking a 'Node *', rather than the one taking a 'bool'
+#include "scene/background.h"
+#include "scene/light.h"
+#include "scene/shader_graph.h"
+#include "scene/shader_nodes.h"
+#include "session/session.h"
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+namespace {
+
+const std::unordered_map<TfToken, PassType, TfToken::HashFunctor> kAovToPass = {
+ {HdAovTokens->color, PASS_COMBINED},
+ {HdAovTokens->depth, PASS_DEPTH},
+ {HdAovTokens->normal, PASS_NORMAL},
+ {HdAovTokens->primId, PASS_OBJECT_ID},
+ {HdAovTokens->instanceId, PASS_AOV_VALUE},
+};
+
+} // namespace
+
+SceneLock::SceneLock(const HdRenderParam *renderParam)
+ : scene(static_cast<const HdCyclesSession *>(renderParam)->session->scene),
+ sceneLock(scene->mutex)
+{
+}
+
+SceneLock::~SceneLock()
+{
+}
+
+HdCyclesSession::HdCyclesSession(Session *session_) : session(session_), _ownCyclesSession(false)
+{
+}
+
+HdCyclesSession::HdCyclesSession(const SessionParams &params)
+ : session(new Session(params, SceneParams())), _ownCyclesSession(true)
+{
+ Scene *const scene = session->scene;
+
+ // Create background with ambient light
+ {
+ ShaderGraph *graph = new ShaderGraph();
+
+ BackgroundNode *bgNode = graph->create_node<BackgroundNode>();
+ bgNode->set_color(one_float3());
+ graph->add(bgNode);
+
+ graph->connect(bgNode->output("Background"), graph->output()->input("Surface"));
+
+ scene->default_background->set_graph(graph);
+ scene->default_background->tag_update(scene);
+ }
+
+ // Wire up object color in default surface material
+ {
+ ShaderGraph *graph = new ShaderGraph();
+
+ ObjectInfoNode *objectNode = graph->create_node<ObjectInfoNode>();
+ graph->add(objectNode);
+
+ DiffuseBsdfNode *diffuseNode = graph->create_node<DiffuseBsdfNode>();
+ graph->add(diffuseNode);
+
+ graph->connect(objectNode->output("Color"), diffuseNode->input("Color"));
+ graph->connect(diffuseNode->output("BSDF"), graph->output()->input("Surface"));
+
+#if 1
+ // Create the instanceId AOV output
+ const ustring instanceId(HdAovTokens->instanceId.GetString());
+
+ OutputAOVNode *aovNode = graph->create_node<OutputAOVNode>();
+ aovNode->set_name(instanceId);
+ graph->add(aovNode);
+
+ AttributeNode *instanceIdNode = graph->create_node<AttributeNode>();
+ instanceIdNode->set_attribute(instanceId);
+ graph->add(instanceIdNode);
+
+ graph->connect(instanceIdNode->output("Fac"), aovNode->input("Value"));
+#endif
+
+ scene->default_surface->set_graph(graph);
+ scene->default_surface->tag_update(scene);
+ }
+}
+
+HdCyclesSession::~HdCyclesSession()
+{
+ if (_ownCyclesSession) {
+ delete session;
+ }
+}
+
+void HdCyclesSession::UpdateScene()
+{
+ Scene *const scene = session->scene;
+
+ // Update background depending on presence of a background light
+ if (scene->light_manager->need_update()) {
+ Light *background_light = nullptr;
+ for (Light *light : scene->lights) {
+ if (light->get_light_type() == LIGHT_BACKGROUND) {
+ background_light = light;
+ break;
+ }
+ }
+
+ if (!background_light) {
+ scene->background->set_shader(scene->default_background);
+ scene->background->set_transparent(true);
+ }
+ else {
+ scene->background->set_shader(background_light->get_shader());
+ scene->background->set_transparent(false);
+ }
+
+ scene->background->tag_update(scene);
+ }
+}
+
+void HdCyclesSession::SyncAovBindings(const HdRenderPassAovBindingVector &aovBindings)
+{
+ Scene *const scene = session->scene;
+
+ // Delete all existing passes
+ scene->delete_nodes(set<Pass *>(scene->passes.begin(), scene->passes.end()));
+
+ // Update passes with requested AOV bindings
+ _aovBindings = aovBindings;
+ for (const HdRenderPassAovBinding &aovBinding : aovBindings) {
+ const auto cyclesAov = kAovToPass.find(aovBinding.aovName);
+ if (cyclesAov == kAovToPass.end()) {
+ // TODO: Use PASS_AOV_COLOR and PASS_AOV_VALUE for these?
+ TF_WARN("Unknown pass %s", aovBinding.aovName.GetText());
+ continue;
+ }
+
+ const PassType type = cyclesAov->second;
+ const PassMode mode = PassMode::DENOISED;
+
+ Pass *pass = scene->create_node<Pass>();
+ pass->set_type(type);
+ pass->set_mode(mode);
+ pass->set_name(ustring(aovBinding.aovName.GetString()));
+ }
+}
+
+void HdCyclesSession::RemoveAovBinding(HdRenderBuffer *renderBuffer)
+{
+ for (HdRenderPassAovBinding &aovBinding : _aovBindings) {
+ if (renderBuffer == aovBinding.renderBuffer) {
+ aovBinding.renderBuffer = nullptr;
+ break;
+ }
+ }
+
+ if (renderBuffer == _displayAovBinding.renderBuffer) {
+ _displayAovBinding.renderBuffer = nullptr;
+ }
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/session.h b/intern/cycles/hydra/session.h
new file mode 100644
index 00000000000..7e649c1847a
--- /dev/null
+++ b/intern/cycles/hydra/session.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+#include "util/thread.h"
+
+#include <pxr/imaging/hd/renderDelegate.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+struct SceneLock {
+ SceneLock(const PXR_NS::HdRenderParam *renderParam);
+ ~SceneLock();
+
+ CCL_NS::Scene *scene;
+
+ private:
+ CCL_NS::thread_scoped_lock sceneLock;
+};
+
+class HdCyclesSession final : public PXR_NS::HdRenderParam {
+ public:
+ HdCyclesSession(CCL_NS::Session *session_);
+ HdCyclesSession(const CCL_NS::SessionParams &params);
+ ~HdCyclesSession() override;
+
+ void UpdateScene();
+
+ PXR_NS::HdRenderPassAovBinding GetDisplayAovBinding() const
+ {
+ return _displayAovBinding;
+ }
+
+ void SetDisplayAovBinding(const PXR_NS::HdRenderPassAovBinding &aovBinding)
+ {
+ _displayAovBinding = aovBinding;
+ }
+
+ const PXR_NS::HdRenderPassAovBindingVector &GetAovBindings() const
+ {
+ return _aovBindings;
+ }
+
+ void SyncAovBindings(const PXR_NS::HdRenderPassAovBindingVector &aovBindings);
+
+ void RemoveAovBinding(PXR_NS::HdRenderBuffer *renderBuffer);
+
+ CCL_NS::Session *session;
+
+ private:
+ const bool _ownCyclesSession;
+ PXR_NS::HdRenderPassAovBindingVector _aovBindings;
+ PXR_NS::HdRenderPassAovBinding _displayAovBinding;
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/volume.cpp b/intern/cycles/hydra/volume.cpp
new file mode 100644
index 00000000000..7b965c613ed
--- /dev/null
+++ b/intern/cycles/hydra/volume.cpp
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#include "hydra/volume.h"
+#include "hydra/field.h"
+#include "hydra/geometry.inl"
+#include "scene/volume.h"
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+// clang-format off
+TF_DEFINE_PRIVATE_TOKENS(_tokens,
+ (openvdbAsset)
+);
+// clang-format on
+
+HdCyclesVolume::HdCyclesVolume(const SdfPath &rprimId
+#if PXR_VERSION < 2102
+ ,
+ const SdfPath &instancerId
+#endif
+ )
+ : HdCyclesGeometry(rprimId
+#if PXR_VERSION < 2102
+ ,
+ instancerId
+#endif
+ )
+{
+}
+
+HdCyclesVolume::~HdCyclesVolume()
+{
+}
+
+HdDirtyBits HdCyclesVolume::GetInitialDirtyBitsMask() const
+{
+ HdDirtyBits bits = HdCyclesGeometry::GetInitialDirtyBitsMask();
+ bits |= HdChangeTracker::DirtyVolumeField;
+ return bits;
+}
+
+void HdCyclesVolume::Populate(HdSceneDelegate *sceneDelegate, HdDirtyBits dirtyBits, bool &rebuild)
+{
+ Scene *const scene = (Scene *)_geom->get_owner();
+
+ if (dirtyBits & HdChangeTracker::DirtyVolumeField) {
+ for (const HdVolumeFieldDescriptor &field :
+ sceneDelegate->GetVolumeFieldDescriptors(GetId())) {
+ if (const auto openvdbAsset = static_cast<HdCyclesField *>(
+ sceneDelegate->GetRenderIndex().GetBprim(_tokens->openvdbAsset, field.fieldId))) {
+ const ustring name(field.fieldName.GetString());
+
+ AttributeStandard std = ATTR_STD_NONE;
+ if (name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) {
+ std = ATTR_STD_VOLUME_DENSITY;
+ }
+ else if (name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) {
+ std = ATTR_STD_VOLUME_COLOR;
+ }
+ else if (name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) {
+ std = ATTR_STD_VOLUME_FLAME;
+ }
+ else if (name == Attribute::standard_name(ATTR_STD_VOLUME_HEAT)) {
+ std = ATTR_STD_VOLUME_HEAT;
+ }
+ else if (name == Attribute::standard_name(ATTR_STD_VOLUME_TEMPERATURE)) {
+ std = ATTR_STD_VOLUME_TEMPERATURE;
+ }
+ else if (name == Attribute::standard_name(ATTR_STD_VOLUME_VELOCITY)) {
+ std = ATTR_STD_VOLUME_VELOCITY;
+ }
+
+ // Skip attributes that are not needed
+ if ((std != ATTR_STD_NONE && _geom->need_attribute(scene, std)) ||
+ _geom->need_attribute(scene, name)) {
+ Attribute *const attr = (std != ATTR_STD_NONE) ?
+ _geom->attributes.add(std) :
+ _geom->attributes.add(
+ name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL);
+ attr->data_voxel() = openvdbAsset->GetImageHandle();
+ }
+ }
+ }
+
+ rebuild = true;
+ }
+}
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/hydra/volume.h b/intern/cycles/hydra/volume.h
new file mode 100644
index 00000000000..7fb5fa779b5
--- /dev/null
+++ b/intern/cycles/hydra/volume.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2022 NVIDIA Corporation
+ * Copyright 2022 Blender Foundation */
+
+#pragma once
+
+#include "hydra/config.h"
+#include "hydra/geometry.h"
+
+#include <pxr/imaging/hd/volume.h>
+
+HDCYCLES_NAMESPACE_OPEN_SCOPE
+
+class HdCyclesVolume final : public HdCyclesGeometry<PXR_NS::HdVolume, CCL_NS::Volume> {
+ public:
+ HdCyclesVolume(
+ const PXR_NS::SdfPath &rprimId
+#if PXR_VERSION < 2102
+ ,
+ const PXR_NS::SdfPath &instancerId = {}
+#endif
+ );
+ ~HdCyclesVolume() override;
+
+ PXR_NS::HdDirtyBits GetInitialDirtyBitsMask() const override;
+
+ private:
+ void Populate(PXR_NS::HdSceneDelegate *sceneDelegate,
+ PXR_NS::HdDirtyBits dirtyBits,
+ bool &rebuild) override;
+};
+
+HDCYCLES_NAMESPACE_CLOSE_SCOPE
diff --git a/intern/cycles/integrator/render_scheduler.cpp b/intern/cycles/integrator/render_scheduler.cpp
index 90a5a01320b..a75662c90d8 100644
--- a/intern/cycles/integrator/render_scheduler.cpp
+++ b/intern/cycles/integrator/render_scheduler.cpp
@@ -20,7 +20,7 @@ RenderScheduler::RenderScheduler(TileManager &tile_manager, const SessionParams
background_(params.background),
pixel_size_(params.pixel_size),
tile_manager_(tile_manager),
- default_start_resolution_divider_(pixel_size_ * 8)
+ default_start_resolution_divider_(params.use_resolution_divider ? pixel_size_ * 8 : 0)
{
use_progressive_noise_floor_ = !background_;
}
@@ -119,7 +119,7 @@ void RenderScheduler::reset(const BufferParams &buffer_params, int num_samples,
/* In background mode never do lower resolution render preview, as it is not really supported
* by the software. */
- if (background_) {
+ if (background_ || start_resolution_divider_ == 0) {
state_.resolution_divider = 1;
}
else {
@@ -1050,6 +1050,10 @@ bool RenderScheduler::work_need_rebalance()
void RenderScheduler::update_start_resolution_divider()
{
+ if (default_start_resolution_divider_ == 0) {
+ return;
+ }
+
if (start_resolution_divider_ == 0) {
/* Resolution divider has never been calculated before: use default resolution, so that we have
* somewhat good initial behavior, giving a chance to collect real numbers. */
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 8e7b46ab574..6e3ac1bd32f 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -50,7 +50,6 @@ set(SRC_KERNEL_DEVICE_GPU_HEADERS
device/gpu/kernel.h
device/gpu/parallel_active_index.h
device/gpu/parallel_prefix_sum.h
- device/gpu/parallel_reduce.h
device/gpu/parallel_sorted_index.h
device/gpu/work_stealing.h
)
diff --git a/intern/cycles/kernel/device/cpu/image.h b/intern/cycles/kernel/device/cpu/image.h
index b6bcd19b9ea..3b714a3e580 100644
--- a/intern/cycles/kernel/device/cpu/image.h
+++ b/intern/cycles/kernel/device/cpu/image.h
@@ -31,7 +31,17 @@ ccl_device_inline float frac(float x, int *ix)
return x - (float)i;
}
-template<typename T> struct TextureInterpolator {
+template<typename TexT, typename OutT = float4> struct TextureInterpolator {
+
+ static ccl_always_inline OutT zero()
+ {
+ if constexpr (std::is_same<OutT, float4>::value) {
+ return zero_float4();
+ }
+ else {
+ return 0.0f;
+ }
+ }
static ccl_always_inline float4 read(float4 r)
{
@@ -40,21 +50,18 @@ template<typename T> struct TextureInterpolator {
static ccl_always_inline float4 read(uchar4 r)
{
- float f = 1.0f / 255.0f;
+ const float f = 1.0f / 255.0f;
return make_float4(r.x * f, r.y * f, r.z * f, r.w * f);
}
- static ccl_always_inline float4 read(uchar r)
+ static ccl_always_inline float read(uchar r)
{
- float f = r * (1.0f / 255.0f);
- return make_float4(f, f, f, 1.0f);
+ return r * (1.0f / 255.0f);
}
- static ccl_always_inline float4 read(float r)
+ static ccl_always_inline float read(float r)
{
- /* TODO(dingto): Optimize this, so interpolation
- * happens on float instead of float4 */
- return make_float4(r, r, r, 1.0f);
+ return r;
}
static ccl_always_inline float4 read(half4 r)
@@ -62,37 +69,131 @@ template<typename T> struct TextureInterpolator {
return half4_to_float4_image(r);
}
- static ccl_always_inline float4 read(half r)
+ static ccl_always_inline float read(half r)
{
- float f = half_to_float_image(r);
- return make_float4(f, f, f, 1.0f);
+ return half_to_float_image(r);
}
- static ccl_always_inline float4 read(uint16_t r)
+ static ccl_always_inline float read(uint16_t r)
{
- float f = r * (1.0f / 65535.0f);
- return make_float4(f, f, f, 1.0f);
+ return r * (1.0f / 65535.0f);
}
static ccl_always_inline float4 read(ushort4 r)
{
- float f = 1.0f / 65535.0f;
+ const float f = 1.0f / 65535.0f;
return make_float4(r.x * f, r.y * f, r.z * f, r.w * f);
}
- static ccl_always_inline float4 read(const T *data, int x, int y, int width, int height)
+ /* Read 2D Texture Data
+ * Does not check if data request is in bounds. */
+ static ccl_always_inline OutT read(const TexT *data, int x, int y, int width, int height)
+ {
+ return read(data[y * width + x]);
+ }
+
+ /* Read 2D Texture Data Clip
+ * Returns transparent black if data request is out of bounds. */
+ static ccl_always_inline OutT read_clip(const TexT *data, int x, int y, int width, int height)
{
- if (x < 0 || y < 0 || x >= width || y >= height) {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ if (x < 0 || x >= width || y < 0 || y >= height) {
+ return zero();
}
return read(data[y * width + x]);
}
+ /* Read 3D Texture Data
+ * Does not check if data request is in bounds. */
+ static ccl_always_inline OutT
+ read(const TexT *data, int x, int y, int z, int width, int height, int depth)
+ {
+ return read(data[x + y * width + z * width * height]);
+ }
+
+ /* Read 3D Texture Data Clip
+ * Returns transparent black if data request is out of bounds. */
+ static ccl_always_inline OutT
+ read_clip(const TexT *data, int x, int y, int z, int width, int height, int depth)
+ {
+ if (x < 0 || x >= width || y < 0 || y >= height || z < 0 || z >= depth) {
+ return zero();
+ }
+ return read(data[x + y * width + z * width * height]);
+ }
+
+ /* Trilinear Interpolation */
+ static ccl_always_inline OutT
+ trilinear_lookup(const TexT *data,
+ float tx,
+ float ty,
+ float tz,
+ int ix,
+ int iy,
+ int iz,
+ int nix,
+ int niy,
+ int niz,
+ int width,
+ int height,
+ int depth,
+ OutT read(const TexT *, int, int, int, int, int, int))
+ {
+ OutT r = (1.0f - tz) * (1.0f - ty) * (1.0f - tx) *
+ read(data, ix, iy, iz, width, height, depth);
+ r += (1.0f - tz) * (1.0f - ty) * tx * read(data, nix, iy, iz, width, height, depth);
+ r += (1.0f - tz) * ty * (1.0f - tx) * read(data, ix, niy, iz, width, height, depth);
+ r += (1.0f - tz) * ty * tx * read(data, nix, niy, iz, width, height, depth);
+
+ r += tz * (1.0f - ty) * (1.0f - tx) * read(data, ix, iy, niz, width, height, depth);
+ r += tz * (1.0f - ty) * tx * read(data, nix, iy, niz, width, height, depth);
+ r += tz * ty * (1.0f - tx) * read(data, ix, niy, niz, width, height, depth);
+ r += tz * ty * tx * read(data, nix, niy, niz, width, height, depth);
+ return r;
+ }
+
+ /** Tricubic Interpolation */
+ static ccl_always_inline OutT
+ tricubic_lookup(const TexT *data,
+ float tx,
+ float ty,
+ float tz,
+ const int xc[4],
+ const int yc[4],
+ const int zc[4],
+ int width,
+ int height,
+ int depth,
+ OutT read(const TexT *, int, int, int, int, int, int))
+ {
+ float u[4], v[4], w[4];
+
+ /* Some helper macros to keep code size reasonable.
+ * Lets the compiler inline all the matrix multiplications.
+ */
+#define DATA(x, y, z) (read(data, xc[x], yc[y], zc[z], width, height, depth))
+#define COL_TERM(col, row) \
+ (v[col] * (u[0] * DATA(0, col, row) + u[1] * DATA(1, col, row) + u[2] * DATA(2, col, row) + \
+ u[3] * DATA(3, col, row)))
+#define ROW_TERM(row) \
+ (w[row] * (COL_TERM(0, row) + COL_TERM(1, row) + COL_TERM(2, row) + COL_TERM(3, row)))
+
+ SET_CUBIC_SPLINE_WEIGHTS(u, tx);
+ SET_CUBIC_SPLINE_WEIGHTS(v, ty);
+ SET_CUBIC_SPLINE_WEIGHTS(w, tz);
+ /* Actual interpolation. */
+ return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3);
+
+#undef COL_TERM
+#undef ROW_TERM
+#undef DATA
+ }
+
static ccl_always_inline int wrap_periodic(int x, int width)
{
x %= width;
- if (x < 0)
+ if (x < 0) {
x += width;
+ }
return x;
}
@@ -103,9 +204,8 @@ template<typename T> struct TextureInterpolator {
/* ******** 2D interpolation ******** */
- static ccl_always_inline float4 interp_closest(const TextureInfo &info, float x, float y)
+ static ccl_always_inline OutT interp_closest(const TextureInfo &info, float x, float y)
{
- const T *data = (const T *)info.data;
const int width = info.width;
const int height = info.height;
int ix, iy;
@@ -117,105 +217,134 @@ template<typename T> struct TextureInterpolator {
iy = wrap_periodic(iy, height);
break;
case EXTENSION_CLIP:
- if (x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ /* No samples are inside the clip region. */
+ if (ix < 0 || ix >= width || iy < 0 || iy >= height) {
+ return zero();
}
- ATTR_FALLTHROUGH;
+ break;
case EXTENSION_EXTEND:
ix = wrap_clamp(ix, width);
iy = wrap_clamp(iy, height);
break;
default:
kernel_assert(0);
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return zero();
}
- return read(data[ix + iy * width]);
+
+ const TexT *data = (const TexT *)info.data;
+ return read((const TexT *)data, ix, iy, width, height);
}
- static ccl_always_inline float4 interp_linear(const TextureInfo &info, float x, float y)
+ static ccl_always_inline OutT interp_linear(const TextureInfo &info, float x, float y)
{
- const T *data = (const T *)info.data;
const int width = info.width;
const int height = info.height;
- int ix, iy, nix, niy;
+
+ /* A -0.5 offset is used to center the linear samples around the sample point. */
+ int ix, iy;
+ int nix, niy;
const float tx = frac(x * (float)width - 0.5f, &ix);
const float ty = frac(y * (float)height - 0.5f, &iy);
+
switch (info.extension) {
case EXTENSION_REPEAT:
ix = wrap_periodic(ix, width);
- iy = wrap_periodic(iy, height);
nix = wrap_periodic(ix + 1, width);
+
+ iy = wrap_periodic(iy, height);
niy = wrap_periodic(iy + 1, height);
break;
case EXTENSION_CLIP:
+ /* No linear samples are inside the clip region. */
+ if (ix < -1 || ix >= width || iy < -1 || iy >= height) {
+ return zero();
+ }
nix = ix + 1;
niy = iy + 1;
break;
case EXTENSION_EXTEND:
nix = wrap_clamp(ix + 1, width);
- niy = wrap_clamp(iy + 1, height);
ix = wrap_clamp(ix, width);
+ niy = wrap_clamp(iy + 1, height);
iy = wrap_clamp(iy, height);
break;
default:
kernel_assert(0);
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return zero();
}
- return (1.0f - ty) * (1.0f - tx) * read(data, ix, iy, width, height) +
- (1.0f - ty) * tx * read(data, nix, iy, width, height) +
- ty * (1.0f - tx) * read(data, ix, niy, width, height) +
- ty * tx * read(data, nix, niy, width, height);
+
+ const TexT *data = (const TexT *)info.data;
+ return (1.0f - ty) * (1.0f - tx) * read_clip(data, ix, iy, width, height) +
+ (1.0f - ty) * tx * read_clip(data, nix, iy, width, height) +
+ ty * (1.0f - tx) * read_clip(data, ix, niy, width, height) +
+ ty * tx * read_clip(data, nix, niy, width, height);
}
- static ccl_always_inline float4 interp_cubic(const TextureInfo &info, float x, float y)
+ static ccl_always_inline OutT interp_cubic(const TextureInfo &info, float x, float y)
{
- const T *data = (const T *)info.data;
const int width = info.width;
const int height = info.height;
- int ix, iy, nix, niy;
+
+ /* A -0.5 offset is used to center the cubic samples around the sample point. */
+ int ix, iy;
const float tx = frac(x * (float)width - 0.5f, &ix);
const float ty = frac(y * (float)height - 0.5f, &iy);
- int pix, piy, nnix, nniy;
+
+ int pix, piy;
+ int nix, niy;
+ int nnix, nniy;
+
switch (info.extension) {
case EXTENSION_REPEAT:
ix = wrap_periodic(ix, width);
- iy = wrap_periodic(iy, height);
pix = wrap_periodic(ix - 1, width);
- piy = wrap_periodic(iy - 1, height);
nix = wrap_periodic(ix + 1, width);
- niy = wrap_periodic(iy + 1, height);
nnix = wrap_periodic(ix + 2, width);
+
+ iy = wrap_periodic(iy, height);
+ piy = wrap_periodic(iy - 1, height);
+ niy = wrap_periodic(iy + 1, height);
nniy = wrap_periodic(iy + 2, height);
break;
case EXTENSION_CLIP:
+ /* No cubic samples are inside the clip region. */
+ if (ix < -2 || ix > width || iy < -2 || iy > height) {
+ return zero();
+ }
+
pix = ix - 1;
- piy = iy - 1;
nix = ix + 1;
- niy = iy + 1;
nnix = ix + 2;
+
+ piy = iy - 1;
+ niy = iy + 1;
nniy = iy + 2;
break;
case EXTENSION_EXTEND:
pix = wrap_clamp(ix - 1, width);
- piy = wrap_clamp(iy - 1, height);
nix = wrap_clamp(ix + 1, width);
- niy = wrap_clamp(iy + 1, height);
nnix = wrap_clamp(ix + 2, width);
- nniy = wrap_clamp(iy + 2, height);
ix = wrap_clamp(ix, width);
+
+ piy = wrap_clamp(iy - 1, height);
+ niy = wrap_clamp(iy + 1, height);
+ nniy = wrap_clamp(iy + 2, height);
iy = wrap_clamp(iy, height);
break;
default:
kernel_assert(0);
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return zero();
}
+
+ const TexT *data = (const TexT *)info.data;
const int xc[4] = {pix, ix, nix, nnix};
const int yc[4] = {piy, iy, niy, nniy};
float u[4], v[4];
- /* Some helper macro to keep code reasonable size,
- * let compiler to inline all the matrix multiplications.
+
+ /* Some helper macros to keep code size reasonable.
+ * Lets the compiler inline all the matrix multiplications.
*/
-#define DATA(x, y) (read(data, xc[x], yc[y], width, height))
+#define DATA(x, y) (read_clip(data, xc[x], yc[y], width, height))
#define TERM(col) \
(v[col] * \
(u[0] * DATA(0, col) + u[1] * DATA(1, col) + u[2] * DATA(2, col) + u[3] * DATA(3, col)))
@@ -229,11 +358,8 @@ template<typename T> struct TextureInterpolator {
#undef DATA
}
- static ccl_always_inline float4 interp(const TextureInfo &info, float x, float y)
+ static ccl_always_inline OutT interp(const TextureInfo &info, float x, float y)
{
- if (UNLIKELY(!info.data)) {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- }
switch (info.interpolation) {
case INTERPOLATION_CLOSEST:
return interp_closest(info, x, y);
@@ -246,14 +372,14 @@ template<typename T> struct TextureInterpolator {
/* ******** 3D interpolation ******** */
- static ccl_always_inline float4 interp_3d_closest(const TextureInfo &info,
- float x,
- float y,
- float z)
+ static ccl_always_inline OutT interp_3d_closest(const TextureInfo &info,
+ float x,
+ float y,
+ float z)
{
- int width = info.width;
- int height = info.height;
- int depth = info.depth;
+ const int width = info.width;
+ const int height = info.height;
+ const int depth = info.depth;
int ix, iy, iz;
frac(x * (float)width, &ix);
@@ -267,10 +393,11 @@ template<typename T> struct TextureInterpolator {
iz = wrap_periodic(iz, depth);
break;
case EXTENSION_CLIP:
- if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ /* No samples are inside the clip region. */
+ if (ix < 0 || ix >= width || iy < 0 || iy >= height || iz < 0 || iz >= depth) {
+ return zero();
}
- ATTR_FALLTHROUGH;
+ break;
case EXTENSION_EXTEND:
ix = wrap_clamp(ix, width);
iy = wrap_clamp(iy, height);
@@ -278,24 +405,25 @@ template<typename T> struct TextureInterpolator {
break;
default:
kernel_assert(0);
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return zero();
}
- const T *data = (const T *)info.data;
- return read(data[ix + iy * width + iz * width * height]);
+ const TexT *data = (const TexT *)info.data;
+ return read(data, ix, iy, iz, width, height, depth);
}
- static ccl_always_inline float4 interp_3d_linear(const TextureInfo &info,
- float x,
- float y,
- float z)
+ static ccl_always_inline OutT interp_3d_linear(const TextureInfo &info,
+ float x,
+ float y,
+ float z)
{
- int width = info.width;
- int height = info.height;
- int depth = info.depth;
+ const int width = info.width;
+ const int height = info.height;
+ const int depth = info.depth;
int ix, iy, iz;
int nix, niy, niz;
+ /* A -0.5 offset is used to center the linear samples around the sample point. */
float tx = frac(x * (float)width - 0.5f, &ix);
float ty = frac(y * (float)height - 0.5f, &iy);
float tz = frac(z * (float)depth - 0.5f, &iz);
@@ -303,50 +431,79 @@ template<typename T> struct TextureInterpolator {
switch (info.extension) {
case EXTENSION_REPEAT:
ix = wrap_periodic(ix, width);
- iy = wrap_periodic(iy, height);
- iz = wrap_periodic(iz, depth);
-
nix = wrap_periodic(ix + 1, width);
+
+ iy = wrap_periodic(iy, height);
niy = wrap_periodic(iy + 1, height);
+
+ iz = wrap_periodic(iz, depth);
niz = wrap_periodic(iz + 1, depth);
break;
case EXTENSION_CLIP:
- if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ /* No linear samples are inside the clip region. */
+ if (ix < -1 || ix >= width || iy < -1 || iy >= height || iz < -1 || iz >= depth) {
+ return zero();
+ }
+
+ nix = ix + 1;
+ niy = iy + 1;
+ niz = iz + 1;
+
+ /* All linear samples are inside the clip region. */
+ if (ix >= 0 && nix < width && iy >= 0 && niy < height && iz >= 0 && niz < depth) {
+ break;
}
- ATTR_FALLTHROUGH;
+
+ /* The linear samples span the clip border.
+ * #read_clip is used to ensure proper interpolation across the clip border. */
+ return trilinear_lookup((const TexT *)info.data,
+ tx,
+ ty,
+ tz,
+ ix,
+ iy,
+ iz,
+ nix,
+ niy,
+ niz,
+ width,
+ height,
+ depth,
+ read_clip);
case EXTENSION_EXTEND:
nix = wrap_clamp(ix + 1, width);
- niy = wrap_clamp(iy + 1, height);
- niz = wrap_clamp(iz + 1, depth);
-
ix = wrap_clamp(ix, width);
+
+ niy = wrap_clamp(iy + 1, height);
iy = wrap_clamp(iy, height);
+
+ niz = wrap_clamp(iz + 1, depth);
iz = wrap_clamp(iz, depth);
break;
default:
kernel_assert(0);
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return zero();
}
- const T *data = (const T *)info.data;
- float4 r;
-
- r = (1.0f - tz) * (1.0f - ty) * (1.0f - tx) *
- read(data[ix + iy * width + iz * width * height]);
- r += (1.0f - tz) * (1.0f - ty) * tx * read(data[nix + iy * width + iz * width * height]);
- r += (1.0f - tz) * ty * (1.0f - tx) * read(data[ix + niy * width + iz * width * height]);
- r += (1.0f - tz) * ty * tx * read(data[nix + niy * width + iz * width * height]);
-
- r += tz * (1.0f - ty) * (1.0f - tx) * read(data[ix + iy * width + niz * width * height]);
- r += tz * (1.0f - ty) * tx * read(data[nix + iy * width + niz * width * height]);
- r += tz * ty * (1.0f - tx) * read(data[ix + niy * width + niz * width * height]);
- r += tz * ty * tx * read(data[nix + niy * width + niz * width * height]);
-
- return r;
+ return trilinear_lookup((const TexT *)info.data,
+ tx,
+ ty,
+ tz,
+ ix,
+ iy,
+ iz,
+ nix,
+ niy,
+ niz,
+ width,
+ height,
+ depth,
+ read);
}
- /* TODO(sergey): For some unspeakable reason both GCC-6 and Clang-3.9 are
+ /* Tricubic b-spline interpolation.
+ *
+ * TODO(sergey): For some unspeakable reason both GCC-6 and Clang-3.9 are
* causing stack overflow issue in this function unless it is inlined.
*
* Only happens for AVX2 kernel and global __KERNEL_SSE__ vectorization
@@ -357,100 +514,101 @@ template<typename T> struct TextureInterpolator {
#else
static ccl_never_inline
#endif
- float4
+ OutT
interp_3d_cubic(const TextureInfo &info, float x, float y, float z)
{
int width = info.width;
int height = info.height;
int depth = info.depth;
int ix, iy, iz;
- int nix, niy, niz;
- /* Tricubic b-spline interpolation. */
+
+ /* A -0.5 offset is used to center the cubic samples around the sample point. */
const float tx = frac(x * (float)width - 0.5f, &ix);
const float ty = frac(y * (float)height - 0.5f, &iy);
const float tz = frac(z * (float)depth - 0.5f, &iz);
- int pix, piy, piz, nnix, nniy, nniz;
+
+ int pix, piy, piz;
+ int nix, niy, niz;
+ int nnix, nniy, nniz;
switch (info.extension) {
case EXTENSION_REPEAT:
ix = wrap_periodic(ix, width);
- iy = wrap_periodic(iy, height);
- iz = wrap_periodic(iz, depth);
-
pix = wrap_periodic(ix - 1, width);
- piy = wrap_periodic(iy - 1, height);
- piz = wrap_periodic(iz - 1, depth);
-
nix = wrap_periodic(ix + 1, width);
- niy = wrap_periodic(iy + 1, height);
- niz = wrap_periodic(iz + 1, depth);
-
nnix = wrap_periodic(ix + 2, width);
+
+ iy = wrap_periodic(iy, height);
+ niy = wrap_periodic(iy + 1, height);
+ piy = wrap_periodic(iy - 1, height);
nniy = wrap_periodic(iy + 2, height);
+
+ iz = wrap_periodic(iz, depth);
+ piz = wrap_periodic(iz - 1, depth);
+ niz = wrap_periodic(iz + 1, depth);
nniz = wrap_periodic(iz + 2, depth);
break;
- case EXTENSION_CLIP:
- if (x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ case EXTENSION_CLIP: {
+ /* No cubic samples are inside the clip region. */
+ if (ix < -2 || ix > width || iy < -2 || iy > height || iz < -2 || iz > depth) {
+ return zero();
+ }
+
+ pix = ix - 1;
+ nnix = ix + 2;
+ nix = ix + 1;
+
+ piy = iy - 1;
+ niy = iy + 1;
+ nniy = iy + 2;
+
+ piz = iz - 1;
+ niz = iz + 1;
+ nniz = iz + 2;
+
+ /* All cubic samples are inside the clip region. */
+ if (pix >= 0 && nnix < width && piy >= 0 && nniy < height && piz >= 0 && nniz < depth) {
+ break;
}
- ATTR_FALLTHROUGH;
+
+ /* The Cubic samples span the clip border.
+ * read_clip is used to ensure proper interpolation across the clip border. */
+ const int xc[4] = {pix, ix, nix, nnix};
+ const int yc[4] = {piy, iy, niy, nniy};
+ const int zc[4] = {piz, iz, niz, nniz};
+ return tricubic_lookup(
+ (const TexT *)info.data, tx, ty, tz, xc, yc, zc, width, height, depth, read_clip);
+ }
case EXTENSION_EXTEND:
pix = wrap_clamp(ix - 1, width);
- piy = wrap_clamp(iy - 1, height);
- piz = wrap_clamp(iz - 1, depth);
-
nix = wrap_clamp(ix + 1, width);
- niy = wrap_clamp(iy + 1, height);
- niz = wrap_clamp(iz + 1, depth);
-
nnix = wrap_clamp(ix + 2, width);
- nniy = wrap_clamp(iy + 2, height);
- nniz = wrap_clamp(iz + 2, depth);
-
ix = wrap_clamp(ix, width);
+
+ piy = wrap_clamp(iy - 1, height);
+ niy = wrap_clamp(iy + 1, height);
+ nniy = wrap_clamp(iy + 2, height);
iy = wrap_clamp(iy, height);
+
+ piz = wrap_clamp(iz - 1, depth);
+ niz = wrap_clamp(iz + 1, depth);
+ nniz = wrap_clamp(iz + 2, depth);
iz = wrap_clamp(iz, depth);
break;
default:
kernel_assert(0);
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return zero();
}
-
const int xc[4] = {pix, ix, nix, nnix};
- const int yc[4] = {width * piy, width * iy, width * niy, width * nniy};
- const int zc[4] = {
- width * height * piz, width * height * iz, width * height * niz, width * height * nniz};
- float u[4], v[4], w[4];
-
- /* Some helper macro to keep code reasonable size,
- * let compiler to inline all the matrix multiplications.
- */
-#define DATA(x, y, z) (read(data[xc[x] + yc[y] + zc[z]]))
-#define COL_TERM(col, row) \
- (v[col] * (u[0] * DATA(0, col, row) + u[1] * DATA(1, col, row) + u[2] * DATA(2, col, row) + \
- u[3] * DATA(3, col, row)))
-#define ROW_TERM(row) \
- (w[row] * (COL_TERM(0, row) + COL_TERM(1, row) + COL_TERM(2, row) + COL_TERM(3, row)))
-
- SET_CUBIC_SPLINE_WEIGHTS(u, tx);
- SET_CUBIC_SPLINE_WEIGHTS(v, ty);
- SET_CUBIC_SPLINE_WEIGHTS(w, tz);
-
- /* Actual interpolation. */
- const T *data = (const T *)info.data;
- return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3);
-
-#undef COL_TERM
-#undef ROW_TERM
-#undef DATA
+ const int yc[4] = {piy, iy, niy, nniy};
+ const int zc[4] = {piz, iz, niz, nniz};
+ const TexT *data = (const TexT *)info.data;
+ return tricubic_lookup(data, tx, ty, tz, xc, yc, zc, width, height, depth, read);
}
- static ccl_always_inline float4
+ static ccl_always_inline OutT
interp_3d(const TextureInfo &info, float x, float y, float z, InterpolationType interp)
{
- if (UNLIKELY(!info.data))
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-
switch ((interp == INTERPOLATION_NONE) ? info.interpolation : interp) {
case INTERPOLATION_CLOSEST:
return interp_3d_closest(info, x, y, z);
@@ -463,13 +621,13 @@ template<typename T> struct TextureInterpolator {
};
#ifdef WITH_NANOVDB
-template<typename T> struct NanoVDBInterpolator {
+template<typename TexT, typename OutT = float4> struct NanoVDBInterpolator {
- typedef typename nanovdb::NanoGrid<T>::AccessorType AccessorType;
+ typedef typename nanovdb::NanoGrid<TexT>::AccessorType AccessorType;
- static ccl_always_inline float4 read(float r)
+ static ccl_always_inline float read(float r)
{
- return make_float4(r, r, r, 1.0f);
+ return r;
}
static ccl_always_inline float4 read(nanovdb::Vec3f r)
@@ -477,40 +635,43 @@ template<typename T> struct NanoVDBInterpolator {
return make_float4(r[0], r[1], r[2], 1.0f);
}
- static ccl_always_inline float4 interp_3d_closest(const AccessorType &acc,
- float x,
- float y,
- float z)
+ static ccl_always_inline OutT interp_3d_closest(const AccessorType &acc,
+ float x,
+ float y,
+ float z)
{
const nanovdb::Vec3f xyz(x, y, z);
return read(nanovdb::SampleFromVoxels<AccessorType, 0, false>(acc)(xyz));
}
- static ccl_always_inline float4 interp_3d_linear(const AccessorType &acc,
- float x,
- float y,
- float z)
+ static ccl_always_inline OutT interp_3d_linear(const AccessorType &acc,
+ float x,
+ float y,
+ float z)
{
const nanovdb::Vec3f xyz(x - 0.5f, y - 0.5f, z - 0.5f);
return read(nanovdb::SampleFromVoxels<AccessorType, 1, false>(acc)(xyz));
}
+ /* Tricubic b-spline interpolation. */
# if defined(__GNUC__) || defined(__clang__)
static ccl_always_inline
# else
static ccl_never_inline
# endif
- float4
+ OutT
interp_3d_cubic(const AccessorType &acc, float x, float y, float z)
{
int ix, iy, iz;
int nix, niy, niz;
int pix, piy, piz;
int nnix, nniy, nniz;
- /* Tricubic b-spline interpolation. */
+
+ /* A -0.5 offset is used to center the cubic samples around the sample point. */
const float tx = frac(x - 0.5f, &ix);
const float ty = frac(y - 0.5f, &iy);
const float tz = frac(z - 0.5f, &iz);
+
pix = ix - 1;
piy = iy - 1;
piz = iz - 1;
@@ -526,8 +687,8 @@ template<typename T> struct NanoVDBInterpolator {
const int zc[4] = {piz, iz, niz, nniz};
float u[4], v[4], w[4];
- /* Some helper macro to keep code reasonable size,
- * let compiler to inline all the matrix multiplications.
+ /* Some helper macros to keep code size reasonable.
+ * Lets the compiler inline all the matrix multiplications.
*/
# define DATA(x, y, z) (read(acc.getValue(nanovdb::Coord(xc[x], yc[y], zc[z]))))
# define COL_TERM(col, row) \
@@ -548,12 +709,12 @@ template<typename T> struct NanoVDBInterpolator {
# undef DATA
}
- static ccl_always_inline float4
+ static ccl_always_inline OutT
interp_3d(const TextureInfo &info, float x, float y, float z, InterpolationType interp)
{
using namespace nanovdb;
- NanoGrid<T> *const grid = (NanoGrid<T> *)info.data;
+ NanoGrid<TexT> *const grid = (NanoGrid<TexT> *)info.data;
AccessorType acc = grid->getAccessor();
switch ((interp == INTERPOLATION_NONE) ? info.interpolation : interp) {
@@ -574,15 +735,27 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals kg, int id, float x, flo
{
const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
+ if (UNLIKELY(!info.data)) {
+ return zero_float4();
+ }
+
switch (info.data_type) {
- case IMAGE_DATA_TYPE_HALF:
- return TextureInterpolator<half>::interp(info, x, y);
- case IMAGE_DATA_TYPE_BYTE:
- return TextureInterpolator<uchar>::interp(info, x, y);
- case IMAGE_DATA_TYPE_USHORT:
- return TextureInterpolator<uint16_t>::interp(info, x, y);
- case IMAGE_DATA_TYPE_FLOAT:
- return TextureInterpolator<float>::interp(info, x, y);
+ case IMAGE_DATA_TYPE_HALF: {
+ const float f = TextureInterpolator<half, float>::interp(info, x, y);
+ return make_float4(f, f, f, 1.0f);
+ }
+ case IMAGE_DATA_TYPE_BYTE: {
+ const float f = TextureInterpolator<uchar, float>::interp(info, x, y);
+ return make_float4(f, f, f, 1.0f);
+ }
+ case IMAGE_DATA_TYPE_USHORT: {
+ const float f = TextureInterpolator<uint16_t, float>::interp(info, x, y);
+ return make_float4(f, f, f, 1.0f);
+ }
+ case IMAGE_DATA_TYPE_FLOAT: {
+ const float f = TextureInterpolator<float, float>::interp(info, x, y);
+ return make_float4(f, f, f, 1.0f);
+ }
case IMAGE_DATA_TYPE_HALF4:
return TextureInterpolator<half4>::interp(info, x, y);
case IMAGE_DATA_TYPE_BYTE4:
@@ -605,19 +778,30 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg,
{
const TextureInfo &info = kernel_tex_fetch(__texture_info, id);
+ if (UNLIKELY(!info.data)) {
+ return zero_float4();
+ }
+
if (info.use_transform_3d) {
P = transform_point(&info.transform_3d, P);
}
-
switch (info.data_type) {
- case IMAGE_DATA_TYPE_HALF:
- return TextureInterpolator<half>::interp_3d(info, P.x, P.y, P.z, interp);
- case IMAGE_DATA_TYPE_BYTE:
- return TextureInterpolator<uchar>::interp_3d(info, P.x, P.y, P.z, interp);
- case IMAGE_DATA_TYPE_USHORT:
- return TextureInterpolator<uint16_t>::interp_3d(info, P.x, P.y, P.z, interp);
- case IMAGE_DATA_TYPE_FLOAT:
- return TextureInterpolator<float>::interp_3d(info, P.x, P.y, P.z, interp);
+ case IMAGE_DATA_TYPE_HALF: {
+ const float f = TextureInterpolator<half, float>::interp_3d(info, P.x, P.y, P.z, interp);
+ return make_float4(f, f, f, 1.0f);
+ }
+ case IMAGE_DATA_TYPE_BYTE: {
+ const float f = TextureInterpolator<uchar, float>::interp_3d(info, P.x, P.y, P.z, interp);
+ return make_float4(f, f, f, 1.0f);
+ }
+ case IMAGE_DATA_TYPE_USHORT: {
+ const float f = TextureInterpolator<uint16_t, float>::interp_3d(info, P.x, P.y, P.z, interp);
+ return make_float4(f, f, f, 1.0f);
+ }
+ case IMAGE_DATA_TYPE_FLOAT: {
+ const float f = TextureInterpolator<float, float>::interp_3d(info, P.x, P.y, P.z, interp);
+ return make_float4(f, f, f, 1.0f);
+ }
case IMAGE_DATA_TYPE_HALF4:
return TextureInterpolator<half4>::interp_3d(info, P.x, P.y, P.z, interp);
case IMAGE_DATA_TYPE_BYTE4:
@@ -627,8 +811,10 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg,
case IMAGE_DATA_TYPE_FLOAT4:
return TextureInterpolator<float4>::interp_3d(info, P.x, P.y, P.z, interp);
#ifdef WITH_NANOVDB
- case IMAGE_DATA_TYPE_NANOVDB_FLOAT:
- return NanoVDBInterpolator<float>::interp_3d(info, P.x, P.y, P.z, interp);
+ case IMAGE_DATA_TYPE_NANOVDB_FLOAT: {
+ const float f = NanoVDBInterpolator<float, float>::interp_3d(info, P.x, P.y, P.z, interp);
+ return make_float4(f, f, f, 1.0f);
+ }
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
return NanoVDBInterpolator<nanovdb::Vec3f>::interp_3d(info, P.x, P.y, P.z, interp);
#endif
diff --git a/intern/cycles/kernel/device/cuda/compat.h b/intern/cycles/kernel/device/cuda/compat.h
index d7365e631aa..b392455c740 100644
--- a/intern/cycles/kernel/device/cuda/compat.h
+++ b/intern/cycles/kernel/device/cuda/compat.h
@@ -72,7 +72,6 @@ typedef unsigned long long uint64_t;
#define ccl_gpu_syncthreads() __syncthreads()
#define ccl_gpu_ballot(predicate) __ballot_sync(0xFFFFFFFF, predicate)
-#define ccl_gpu_shfl_down_sync(mask, var, detla) __shfl_down_sync(mask, var, detla)
/* GPU texture objects */
diff --git a/intern/cycles/kernel/device/gpu/parallel_reduce.h b/intern/cycles/kernel/device/gpu/parallel_reduce.h
deleted file mode 100644
index 2b30dc9c666..00000000000
--- a/intern/cycles/kernel/device/gpu/parallel_reduce.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* SPDX-License-Identifier: Apache-2.0
- * Copyright 2021-2022 Blender Foundation */
-
-#pragma once
-
-CCL_NAMESPACE_BEGIN
-
-/* Parallel sum of array input_data with size n into output_sum.
- *
- * Adapted from "Optimizing Parallel Reduction in GPU", Mark Harris.
- *
- * This version adds multiple elements per thread sequentially. This reduces
- * the overall cost of the algorithm while keeping the work complexity O(n) and
- * the step complexity O(log n). (Brent's Theorem optimization) */
-
-#ifdef __HIP__
-# define GPU_PARALLEL_SUM_DEFAULT_BLOCK_SIZE 1024
-#else
-# define GPU_PARALLEL_SUM_DEFAULT_BLOCK_SIZE 512
-#endif
-
-template<uint blocksize, typename InputT, typename OutputT, typename ConvertOp>
-__device__ void gpu_parallel_sum(
- const InputT *input_data, const uint n, OutputT *output_sum, OutputT zero, ConvertOp convert)
-{
- extern ccl_gpu_shared OutputT shared_data[];
-
- const uint tid = ccl_gpu_thread_idx_x;
- const uint gridsize = blocksize * ccl_gpu_grid_dim_x();
-
- OutputT sum = zero;
- for (uint i = ccl_gpu_block_idx_x * blocksize + tid; i < n; i += gridsize) {
- sum += convert(input_data[i]);
- }
- shared_data[tid] = sum;
-
- ccl_gpu_syncthreads();
-
- if (blocksize >= 512 && tid < 256) {
- shared_data[tid] = sum = sum + shared_data[tid + 256];
- }
-
- ccl_gpu_syncthreads();
-
- if (blocksize >= 256 && tid < 128) {
- shared_data[tid] = sum = sum + shared_data[tid + 128];
- }
-
- ccl_gpu_syncthreads();
-
- if (blocksize >= 128 && tid < 64) {
- shared_data[tid] = sum = sum + shared_data[tid + 64];
- }
-
- ccl_gpu_syncthreads();
-
- if (blocksize >= 64 && tid < 32) {
- shared_data[tid] = sum = sum + shared_data[tid + 32];
- }
-
- ccl_gpu_syncthreads();
-
- if (tid < 32) {
- for (int offset = ccl_gpu_warp_size / 2; offset > 0; offset /= 2) {
- sum += ccl_shfl_down_sync(0xFFFFFFFF, sum, offset);
- }
- }
-
- if (tid == 0) {
- output_sum[ccl_gpu_block_idx_x] = sum;
- }
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/device/hip/compat.h b/intern/cycles/kernel/device/hip/compat.h
index 6e117b84337..29fbc119cd1 100644
--- a/intern/cycles/kernel/device/hip/compat.h
+++ b/intern/cycles/kernel/device/hip/compat.h
@@ -62,7 +62,7 @@ typedef unsigned long long uint64_t;
#define ccl_gpu_block_idx_x (blockIdx.x)
#define ccl_gpu_grid_dim_x (gridDim.x)
#define ccl_gpu_warp_size (warpSize)
-#define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp))
+#define ccl_gpu_thread_mask(thread_warp) uint64_t(0xFFFFFFFFFFFFFFFF >> (64 - thread_warp))
#define ccl_gpu_global_id_x() (ccl_gpu_block_idx_x * ccl_gpu_block_dim_x + ccl_gpu_thread_idx_x)
#define ccl_gpu_global_size_x() (ccl_gpu_grid_dim_x * ccl_gpu_block_dim_x)
@@ -71,7 +71,6 @@ typedef unsigned long long uint64_t;
#define ccl_gpu_syncthreads() __syncthreads()
#define ccl_gpu_ballot(predicate) __ballot(predicate)
-#define ccl_gpu_shfl_down_sync(mask, var, detla) __shfl_down(var, detla)
/* GPU texture objects */
typedef hipTextureObject_t ccl_gpu_tex_object;
diff --git a/intern/cycles/kernel/device/optix/compat.h b/intern/cycles/kernel/device/optix/compat.h
index e7fe7139cc1..ae7a0309e51 100644
--- a/intern/cycles/kernel/device/optix/compat.h
+++ b/intern/cycles/kernel/device/optix/compat.h
@@ -74,7 +74,6 @@ typedef unsigned long long uint64_t;
#define ccl_gpu_syncthreads() __syncthreads()
#define ccl_gpu_ballot(predicate) __ballot_sync(0xFFFFFFFF, predicate)
-#define ccl_gpu_shfl_down_sync(mask, var, detla) __shfl_down_sync(mask, var, detla)
/* GPU texture objects */
diff --git a/intern/cycles/kernel/film/accumulate.h b/intern/cycles/kernel/film/accumulate.h
index 6345430e4f4..d6a385a4bff 100644
--- a/intern/cycles/kernel/film/accumulate.h
+++ b/intern/cycles/kernel/film/accumulate.h
@@ -352,6 +352,12 @@ ccl_device_inline void kernel_accum_emission_or_background_pass(KernelGlobals kg
pass_offset = pass;
}
else if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
+ /* Don't write any light passes for shadow catcher, for easier
+ * compositing back together of the combined pass. */
+ if (path_flag & PATH_RAY_SHADOW_CATCHER_HIT) {
+ return;
+ }
+
if (path_flag & PATH_RAY_SURFACE_PASS) {
/* Indirectly visible through reflection. */
const float3 diffuse_weight = INTEGRATOR_STATE(state, path, pass_diffuse_weight);
@@ -437,6 +443,12 @@ ccl_device_inline void kernel_accum_light(KernelGlobals kg,
if (kernel_data.film.light_pass_flag & PASS_ANY) {
const uint32_t path_flag = INTEGRATOR_STATE(state, shadow_path, flag);
+ /* Don't write any light passes for shadow catcher, for easier
+ * compositing back together of the combined pass. */
+ if (path_flag & PATH_RAY_SHADOW_CATCHER_HIT) {
+ return;
+ }
+
if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
int pass_offset = PASS_UNUSED;
diff --git a/intern/cycles/kernel/film/read.h b/intern/cycles/kernel/film/read.h
index 0931e14ee84..a0236909f4b 100644
--- a/intern/cycles/kernel/film/read.h
+++ b/intern/cycles/kernel/film/read.h
@@ -451,7 +451,7 @@ ccl_device_inline float4 film_calculate_shadow_catcher_matte_with_shadow(
float scale, scale_exposure;
if (!film_get_scale_and_scale_exposure(kfilm_convert, buffer, &scale, &scale_exposure)) {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return zero_float4();
}
ccl_global const float *in_matte = buffer + kfilm_convert->pass_shadow_catcher_matte;
diff --git a/intern/cycles/kernel/geom/curve.h b/intern/cycles/kernel/geom/curve.h
index 79366f11082..4dbc6d4f6db 100644
--- a/intern/cycles/kernel/geom/curve.h
+++ b/intern/cycles/kernel/geom/curve.h
@@ -164,7 +164,7 @@ ccl_device float4 curve_attribute_float4(KernelGlobals kg,
if (dx)
*dx = sd->du.dx * (f1 - f0);
if (dy)
- *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dy = zero_float4();
# endif
return (1.0f - sd->u) * f0 + sd->u * f1;
@@ -172,9 +172,9 @@ ccl_device float4 curve_attribute_float4(KernelGlobals kg,
else {
# ifdef __RAY_DIFFERENTIALS__
if (dx)
- *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dx = zero_float4();
if (dy)
- *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dy = zero_float4();
# endif
if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
@@ -183,7 +183,7 @@ ccl_device float4 curve_attribute_float4(KernelGlobals kg,
return kernel_tex_fetch(__attributes_float4, offset);
}
else {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return zero_float4();
}
}
}
diff --git a/intern/cycles/kernel/geom/patch.h b/intern/cycles/kernel/geom/patch.h
index 9a006baf7bf..1c63a00e30d 100644
--- a/intern/cycles/kernel/geom/patch.h
+++ b/intern/cycles/kernel/geom/patch.h
@@ -391,11 +391,11 @@ ccl_device float4 patch_eval_float4(KernelGlobals kg,
int num_control = patch_eval_control_verts(
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
- float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 val = zero_float4();
if (du)
- *du = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *du = zero_float4();
if (dv)
- *dv = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dv = zero_float4();
for (int i = 0; i < num_control; i++) {
float4 v = kernel_tex_fetch(__attributes_float4, offset + indices[i]);
@@ -428,11 +428,11 @@ ccl_device float4 patch_eval_uchar4(KernelGlobals kg,
int num_control = patch_eval_control_verts(
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
- float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 val = zero_float4();
if (du)
- *du = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *du = zero_float4();
if (dv)
- *dv = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dv = zero_float4();
for (int i = 0; i < num_control; i++) {
float4 v = color_srgb_to_linear_v4(
diff --git a/intern/cycles/kernel/geom/point.h b/intern/cycles/kernel/geom/point.h
index 041ecb3c2cf..ee7eca9e0c6 100644
--- a/intern/cycles/kernel/geom/point.h
+++ b/intern/cycles/kernel/geom/point.h
@@ -83,16 +83,16 @@ ccl_device float4 point_attribute_float4(KernelGlobals kg,
{
# ifdef __RAY_DIFFERENTIALS__
if (dx)
- *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dx = zero_float4();
if (dy)
- *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dy = zero_float4();
# 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);
+ return zero_float4();
}
}
diff --git a/intern/cycles/kernel/geom/primitive.h b/intern/cycles/kernel/geom/primitive.h
index 63d1168364c..9b4b61fbd84 100644
--- a/intern/cycles/kernel/geom/primitive.h
+++ b/intern/cycles/kernel/geom/primitive.h
@@ -135,10 +135,10 @@ ccl_device_forceinline float4 primitive_surface_attribute_float4(KernelGlobals k
#endif
else {
if (dx)
- *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dx = zero_float4();
if (dy)
- *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dy = zero_float4();
+ return zero_float4();
}
}
@@ -187,7 +187,7 @@ ccl_device_inline float4 primitive_volume_attribute_float4(KernelGlobals kg,
return volume_attribute_float4(kg, sd, desc);
}
else {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return zero_float4();
}
}
#endif
diff --git a/intern/cycles/kernel/geom/subd_triangle.h b/intern/cycles/kernel/geom/subd_triangle.h
index 0ff5292b5b5..24e1e454b8c 100644
--- a/intern/cycles/kernel/geom/subd_triangle.h
+++ b/intern/cycles/kernel/geom/subd_triangle.h
@@ -566,9 +566,9 @@ ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg,
#endif /* __PATCH_EVAL__ */
if (desc.element == ATTR_ELEMENT_FACE) {
if (dx)
- *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dx = zero_float4();
if (dy)
- *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dy = zero_float4();
return kernel_tex_fetch(__attributes_float4,
desc.offset + subd_triangle_patch_face(kg, patch));
@@ -648,19 +648,19 @@ ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg,
}
else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) {
if (dx)
- *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dx = zero_float4();
if (dy)
- *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dy = zero_float4();
return kernel_tex_fetch(__attributes_float4, desc.offset);
}
else {
if (dx)
- *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dx = zero_float4();
if (dy)
- *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dy = zero_float4();
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return zero_float4();
}
}
diff --git a/intern/cycles/kernel/geom/triangle.h b/intern/cycles/kernel/geom/triangle.h
index 865bf549ae3..8ac7e67ff05 100644
--- a/intern/cycles/kernel/geom/triangle.h
+++ b/intern/cycles/kernel/geom/triangle.h
@@ -338,9 +338,9 @@ ccl_device float4 triangle_attribute_float4(KernelGlobals kg,
else {
#ifdef __RAY_DIFFERENTIALS__
if (dx)
- *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dx = zero_float4();
if (dy)
- *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ *dy = zero_float4();
#endif
if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) {
@@ -349,7 +349,7 @@ ccl_device float4 triangle_attribute_float4(KernelGlobals kg,
return kernel_tex_fetch(__attributes_float4, offset);
}
else {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return zero_float4();
}
}
}
diff --git a/intern/cycles/kernel/geom/volume.h b/intern/cycles/kernel/geom/volume.h
index aa6f3b42bf2..22715dee5bf 100644
--- a/intern/cycles/kernel/geom/volume.h
+++ b/intern/cycles/kernel/geom/volume.h
@@ -75,7 +75,7 @@ ccl_device float4 volume_attribute_float4(KernelGlobals kg,
return kernel_tex_image_interp_3d(kg, desc.offset, P, interp);
}
else {
- return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return zero_float4();
}
}
diff --git a/intern/cycles/kernel/integrator/intersect_volume_stack.h b/intern/cycles/kernel/integrator/intersect_volume_stack.h
index 4cc933aff50..49ef01dc870 100644
--- a/intern/cycles/kernel/integrator/intersect_volume_stack.h
+++ b/intern/cycles/kernel/integrator/intersect_volume_stack.h
@@ -59,6 +59,8 @@ ccl_device void integrator_volume_stack_update_for_subsurface(KernelGlobals kg,
/* Move ray forward. */
volume_ray.P = stack_sd->P;
+ volume_ray.self.object = isect.object;
+ volume_ray.self.prim = isect.prim;
if (volume_ray.t != FLT_MAX) {
volume_ray.D = normalize_len(to_P - volume_ray.P, &volume_ray.t);
}
@@ -198,6 +200,8 @@ ccl_device void integrator_volume_stack_init(KernelGlobals kg, IntegratorState s
/* Move ray forward. */
volume_ray.P = stack_sd->P;
+ volume_ray.self.object = isect.object;
+ volume_ray.self.prim = isect.prim;
++step;
}
#endif
diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h
index d2442755646..df9af6ca107 100644
--- a/intern/cycles/kernel/integrator/shade_surface.h
+++ b/intern/cycles/kernel/integrator/shade_surface.h
@@ -352,13 +352,15 @@ ccl_device_forceinline void integrate_surface_ao(KernelGlobals kg,
float ao_pdf;
sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
+ bool skip_self = true;
+
Ray ray ccl_optional_struct_init;
- ray.P = shadow_ray_offset(kg, sd, ao_D);
+ ray.P = shadow_ray_offset(kg, sd, ao_D, &skip_self);
ray.D = ao_D;
ray.t = kernel_data.integrator.ao_bounces_distance;
ray.time = sd->time;
- ray.self.object = sd->object;
- ray.self.prim = sd->prim;
+ ray.self.object = (skip_self) ? sd->object : OBJECT_NONE;
+ ray.self.prim = (skip_self) ? sd->prim : PRIM_NONE;
ray.self.light_object = OBJECT_NONE;
ray.self.light_prim = PRIM_NONE;
ray.dP = differential_zero_compact();
diff --git a/intern/cycles/kernel/light/sample.h b/intern/cycles/kernel/light/sample.h
index 41882e4b3ee..5acfc92cca1 100644
--- a/intern/cycles/kernel/light/sample.h
+++ b/intern/cycles/kernel/light/sample.h
@@ -180,11 +180,9 @@ ccl_device_inline float3 shadow_ray_smooth_surface_offset(
ccl_device_inline float3 shadow_ray_offset(KernelGlobals kg,
ccl_private const ShaderData *ccl_restrict sd,
- float3 L)
+ float3 L,
+ ccl_private bool *r_skip_self)
{
- float NL = dot(sd->N, L);
- bool transmit = (NL < 0.0f);
- float3 Ng = (transmit ? -sd->Ng : sd->Ng);
float3 P = sd->P;
if ((sd->type & PRIMITIVE_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) {
@@ -194,19 +192,25 @@ ccl_device_inline float3 shadow_ray_offset(KernelGlobals kg,
* offset_cutoff = 0.1f means that 10-20% of rays will be affected. Also
* make a smooth transition near the threshold. */
if (offset_cutoff > 0.0f) {
- float NgL = dot(Ng, L);
- float offset_amount = 0.0f;
+ float NL = dot(sd->N, L);
+ const bool transmit = (NL < 0.0f);
if (NL < 0) {
NL = -NL;
}
- if (NL < offset_cutoff) {
- offset_amount = clamp(2.0f - (NgL + NL) / offset_cutoff, 0.0f, 1.0f);
- }
- else {
- offset_amount = clamp(1.0f - NgL / offset_cutoff, 0.0f, 1.0f);
- }
+
+ const float3 Ng = (transmit ? -sd->Ng : sd->Ng);
+ const float NgL = dot(Ng, L);
+
+ const float offset_amount = (NL < offset_cutoff) ?
+ clamp(2.0f - (NgL + NL) / offset_cutoff, 0.0f, 1.0f) :
+ clamp(1.0f - NgL / offset_cutoff, 0.0f, 1.0f);
+
if (offset_amount > 0.0f) {
P += shadow_ray_smooth_surface_offset(kg, sd, Ng) * offset_amount;
+
+ /* Only skip self intersections if light direction and geometric normal point in the same
+ * direction, otherwise we're meant to hit this surface. */
+ *r_skip_self = (NgL > 0.0f);
}
}
}
@@ -217,7 +221,8 @@ ccl_device_inline float3 shadow_ray_offset(KernelGlobals kg,
ccl_device_inline void shadow_ray_setup(ccl_private const ShaderData *ccl_restrict sd,
ccl_private const LightSample *ccl_restrict ls,
const float3 P,
- ccl_private Ray *ray)
+ ccl_private Ray *ray,
+ const bool skip_self)
{
if (ls->shader & SHADER_CAST_SHADOW) {
/* setup ray */
@@ -246,10 +251,10 @@ ccl_device_inline void shadow_ray_setup(ccl_private const ShaderData *ccl_restri
ray->time = sd->time;
/* Fill in intersection surface and light details. */
- ray->self.prim = sd->prim;
- ray->self.object = sd->object;
- ray->self.light_prim = ls->prim;
+ ray->self.object = (skip_self) ? sd->object : OBJECT_NONE;
+ ray->self.prim = (skip_self) ? sd->prim : PRIM_NONE;
ray->self.light_object = ls->object;
+ ray->self.light_prim = ls->prim;
}
/* Create shadow ray towards light sample. */
@@ -259,8 +264,9 @@ ccl_device_inline void light_sample_to_surface_shadow_ray(
ccl_private const LightSample *ccl_restrict ls,
ccl_private Ray *ray)
{
- const float3 P = shadow_ray_offset(kg, sd, ls->D);
- shadow_ray_setup(sd, ls, P, ray);
+ bool skip_self = true;
+ const float3 P = shadow_ray_offset(kg, sd, ls->D, &skip_self);
+ shadow_ray_setup(sd, ls, P, ray, skip_self);
}
/* Create shadow ray towards light sample. */
@@ -271,7 +277,7 @@ ccl_device_inline void light_sample_to_volume_shadow_ray(
const float3 P,
ccl_private Ray *ray)
{
- shadow_ray_setup(sd, ls, P, ray);
+ shadow_ray_setup(sd, ls, P, ray, false);
}
ccl_device_inline float light_sample_mis_weight_forward(KernelGlobals kg,
diff --git a/intern/cycles/kernel/osl/services.cpp b/intern/cycles/kernel/osl/services.cpp
index 79547872c68..832498f1f73 100644
--- a/intern/cycles/kernel/osl/services.cpp
+++ b/intern/cycles/kernel/osl/services.cpp
@@ -595,8 +595,8 @@ static bool set_attribute_float4(float4 f, TypeDesc type, bool derivatives, void
float4 fv[3];
fv[0] = f;
- fv[1] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- fv[2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ fv[1] = zero_float4();
+ fv[2] = zero_float4();
return set_attribute_float4(fv, type, derivatives, val);
}
diff --git a/intern/cycles/kernel/osl/shaders/node_float_curve.osl b/intern/cycles/kernel/osl/shaders/node_float_curve.osl
index 265a21bd4aa..70de1217877 100644
--- a/intern/cycles/kernel/osl/shaders/node_float_curve.osl
+++ b/intern/cycles/kernel/osl/shaders/node_float_curve.osl
@@ -7,13 +7,15 @@
shader node_float_curve(float ramp[] = {0.0},
float min_x = 0.0,
float max_x = 1.0,
+ int extrapolate = 1,
+
float ValueIn = 0.0,
float Factor = 0.0,
output float ValueOut = 0.0)
{
float c = (ValueIn - min_x) / (max_x - min_x);
- ValueOut = rgb_ramp_lookup(ramp, c, 1, 1);
+ ValueOut = rgb_ramp_lookup(ramp, c, 1, extrapolate);
ValueOut = mix(ValueIn, ValueOut, Factor);
}
diff --git a/intern/cycles/kernel/osl/shaders/node_rgb_curves.osl b/intern/cycles/kernel/osl/shaders/node_rgb_curves.osl
index b73c74801ee..388fdd05b70 100644
--- a/intern/cycles/kernel/osl/shaders/node_rgb_curves.osl
+++ b/intern/cycles/kernel/osl/shaders/node_rgb_curves.osl
@@ -7,6 +7,7 @@
shader node_rgb_curves(color ramp[] = {0.0},
float min_x = 0.0,
float max_x = 1.0,
+ int extrapolate = 1,
color ColorIn = 0.0,
float Fac = 0.0,
@@ -14,9 +15,9 @@ shader node_rgb_curves(color ramp[] = {0.0},
{
color c = (ColorIn - color(min_x, min_x, min_x)) / (max_x - min_x);
- color r = rgb_ramp_lookup(ramp, c[0], 1, 1);
- color g = rgb_ramp_lookup(ramp, c[1], 1, 1);
- color b = rgb_ramp_lookup(ramp, c[2], 1, 1);
+ color r = rgb_ramp_lookup(ramp, c[0], 1, extrapolate);
+ color g = rgb_ramp_lookup(ramp, c[1], 1, extrapolate);
+ color b = rgb_ramp_lookup(ramp, c[2], 1, extrapolate);
ColorOut[0] = r[0];
ColorOut[1] = g[1];
diff --git a/intern/cycles/kernel/osl/shaders/node_vector_curves.osl b/intern/cycles/kernel/osl/shaders/node_vector_curves.osl
index a3bf1209e6e..3ef720ad6d6 100644
--- a/intern/cycles/kernel/osl/shaders/node_vector_curves.osl
+++ b/intern/cycles/kernel/osl/shaders/node_vector_curves.osl
@@ -7,6 +7,7 @@
shader node_vector_curves(color ramp[] = {0.0},
float min_x = 0.0,
float max_x = 1.0,
+ int extrapolate = 1,
vector VectorIn = vector(0.0, 0.0, 0.0),
float Fac = 0.0,
@@ -14,9 +15,9 @@ shader node_vector_curves(color ramp[] = {0.0},
{
vector c = (VectorIn - vector(min_x, min_x, min_x)) / (max_x - min_x);
- color r = rgb_ramp_lookup(ramp, c[0], 1, 1);
- color g = rgb_ramp_lookup(ramp, c[0], 1, 1);
- color b = rgb_ramp_lookup(ramp, c[0], 1, 1);
+ color r = rgb_ramp_lookup(ramp, c[0], 1, extrapolate);
+ color g = rgb_ramp_lookup(ramp, c[0], 1, extrapolate);
+ color b = rgb_ramp_lookup(ramp, c[0], 1, extrapolate);
VectorOut[0] = r[0];
VectorOut[1] = g[1];
diff --git a/intern/cycles/kernel/svm/image.h b/intern/cycles/kernel/svm/image.h
index e9669800f4c..31f29531740 100644
--- a/intern/cycles/kernel/svm/image.h
+++ b/intern/cycles/kernel/svm/image.h
@@ -186,7 +186,7 @@ ccl_device_noinline void svm_node_tex_image_box(KernelGlobals kg,
float3 co = stack_load_float3(stack, co_offset);
uint id = node.y;
- float4 f = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 f = zero_float4();
/* Map so that no textures are flipped, rotation is somewhat arbitrary. */
if (weight.x > 0.0f) {
diff --git a/intern/cycles/kernel/svm/ramp.h b/intern/cycles/kernel/svm/ramp.h
index aba90284a2e..342b15da9ed 100644
--- a/intern/cycles/kernel/svm/ramp.h
+++ b/intern/cycles/kernel/svm/ramp.h
@@ -102,8 +102,8 @@ ccl_device_noinline int svm_node_rgb_ramp(
ccl_device_noinline int svm_node_curves(
KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
{
- uint fac_offset, color_offset, out_offset;
- svm_unpack_node_uchar3(node.y, &fac_offset, &color_offset, &out_offset);
+ uint fac_offset, color_offset, out_offset, extrapolate;
+ svm_unpack_node_uchar4(node.y, &fac_offset, &color_offset, &out_offset, &extrapolate);
uint table_size = read_node(kg, &offset).x;
@@ -114,9 +114,9 @@ ccl_device_noinline int svm_node_curves(
const float range_x = max_x - min_x;
const float3 relpos = (color - make_float3(min_x, min_x, min_x)) / range_x;
- float r = rgb_ramp_lookup(kg, offset, relpos.x, true, true, table_size).x;
- float g = rgb_ramp_lookup(kg, offset, relpos.y, true, true, table_size).y;
- float b = rgb_ramp_lookup(kg, offset, relpos.z, true, true, table_size).z;
+ float r = rgb_ramp_lookup(kg, offset, relpos.x, true, extrapolate, table_size).x;
+ float g = rgb_ramp_lookup(kg, offset, relpos.y, true, extrapolate, table_size).y;
+ float b = rgb_ramp_lookup(kg, offset, relpos.z, true, extrapolate, table_size).z;
color = (1.0f - fac) * color + fac * make_float3(r, g, b);
stack_store_float3(stack, out_offset, color);
@@ -128,8 +128,8 @@ ccl_device_noinline int svm_node_curves(
ccl_device_noinline int svm_node_curve(
KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float *stack, uint4 node, int offset)
{
- uint fac_offset, value_in_offset, out_offset;
- svm_unpack_node_uchar3(node.y, &fac_offset, &value_in_offset, &out_offset);
+ uint fac_offset, value_in_offset, out_offset, extrapolate;
+ svm_unpack_node_uchar4(node.y, &fac_offset, &value_in_offset, &out_offset, &extrapolate);
uint table_size = read_node(kg, &offset).x;
@@ -140,7 +140,7 @@ ccl_device_noinline int svm_node_curve(
const float range = max - min;
const float relpos = (in - min) / range;
- float v = float_ramp_lookup(kg, offset, relpos, true, true, table_size);
+ float v = float_ramp_lookup(kg, offset, relpos, true, extrapolate, table_size);
in = (1.0f - fac) * in + fac * v;
stack_store_float(stack, out_offset, in);
diff --git a/intern/cycles/kernel/svm/vertex_color.h b/intern/cycles/kernel/svm/vertex_color.h
index 231c388618c..bf8d5677114 100644
--- a/intern/cycles/kernel/svm/vertex_color.h
+++ b/intern/cycles/kernel/svm/vertex_color.h
@@ -14,9 +14,16 @@ ccl_device_noinline void svm_node_vertex_color(KernelGlobals kg,
{
AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
if (descriptor.offset != ATTR_STD_NOT_FOUND) {
- float4 vertex_color = primitive_surface_attribute_float4(kg, sd, descriptor, NULL, NULL);
- stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
- stack_store_float(stack, alpha_offset, vertex_color.w);
+ if (descriptor.type == NODE_ATTR_FLOAT4 || descriptor.type == NODE_ATTR_RGBA) {
+ float4 vertex_color = primitive_surface_attribute_float4(kg, sd, descriptor, NULL, NULL);
+ stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
+ stack_store_float(stack, alpha_offset, vertex_color.w);
+ }
+ else {
+ float3 vertex_color = primitive_surface_attribute_float3(kg, sd, descriptor, NULL, NULL);
+ stack_store_float3(stack, color_offset, vertex_color);
+ stack_store_float(stack, alpha_offset, 1.0f);
+ }
}
else {
stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
@@ -33,11 +40,20 @@ ccl_device_noinline void svm_node_vertex_color_bump_dx(KernelGlobals kg,
{
AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
if (descriptor.offset != ATTR_STD_NOT_FOUND) {
- float4 dx;
- float4 vertex_color = primitive_surface_attribute_float4(kg, sd, descriptor, &dx, NULL);
- vertex_color += dx;
- stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
- stack_store_float(stack, alpha_offset, vertex_color.w);
+ if (descriptor.type == NODE_ATTR_FLOAT4 || descriptor.type == NODE_ATTR_RGBA) {
+ float4 dx;
+ float4 vertex_color = primitive_surface_attribute_float4(kg, sd, descriptor, &dx, NULL);
+ vertex_color += dx;
+ stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
+ stack_store_float(stack, alpha_offset, vertex_color.w);
+ }
+ else {
+ float3 dx;
+ float3 vertex_color = primitive_surface_attribute_float3(kg, sd, descriptor, &dx, NULL);
+ vertex_color += dx;
+ stack_store_float3(stack, color_offset, vertex_color);
+ stack_store_float(stack, alpha_offset, 1.0f);
+ }
}
else {
stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
@@ -54,11 +70,20 @@ ccl_device_noinline void svm_node_vertex_color_bump_dy(KernelGlobals kg,
{
AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
if (descriptor.offset != ATTR_STD_NOT_FOUND) {
- float4 dy;
- float4 vertex_color = primitive_surface_attribute_float4(kg, sd, descriptor, NULL, &dy);
- vertex_color += dy;
- stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
- stack_store_float(stack, alpha_offset, vertex_color.w);
+ if (descriptor.type == NODE_ATTR_FLOAT4 || descriptor.type == NODE_ATTR_RGBA) {
+ float4 dy;
+ float4 vertex_color = primitive_surface_attribute_float4(kg, sd, descriptor, NULL, &dy);
+ vertex_color += dy;
+ stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
+ stack_store_float(stack, alpha_offset, vertex_color.w);
+ }
+ else {
+ float3 dy;
+ float3 vertex_color = primitive_surface_attribute_float3(kg, sd, descriptor, NULL, &dy);
+ vertex_color += dy;
+ stack_store_float3(stack, color_offset, vertex_color);
+ stack_store_float(stack, alpha_offset, 1.0f);
+ }
}
else {
stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
diff --git a/intern/cycles/kernel/svm/voronoi.h b/intern/cycles/kernel/svm/voronoi.h
index 8afd7cc9b5f..4ff1047aab7 100644
--- a/intern/cycles/kernel/svm/voronoi.h
+++ b/intern/cycles/kernel/svm/voronoi.h
@@ -684,8 +684,8 @@ ccl_device void voronoi_f1_4d(float4 coord,
float4 localPosition = coord - cellPosition;
float minDistance = 8.0f;
- float4 targetOffset = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- float4 targetPosition = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 targetOffset = zero_float4();
+ float4 targetPosition = zero_float4();
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
@@ -724,7 +724,7 @@ ccl_device void voronoi_smooth_f1_4d(float4 coord,
float smoothDistance = 8.0f;
float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
- float4 smoothPosition = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 smoothPosition = zero_float4();
for (int u = -2; u <= 2; u++) {
for (int k = -2; k <= 2; k++) {
ccl_loop_no_unroll for (int j = -2; j <= 2; j++)
@@ -765,10 +765,10 @@ ccl_device void voronoi_f2_4d(float4 coord,
float distanceF1 = 8.0f;
float distanceF2 = 8.0f;
- float4 offsetF1 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- float4 positionF1 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- float4 offsetF2 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- float4 positionF2 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 offsetF1 = zero_float4();
+ float4 positionF1 = zero_float4();
+ float4 offsetF2 = zero_float4();
+ float4 positionF2 = zero_float4();
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
@@ -808,7 +808,7 @@ ccl_device void voronoi_distance_to_edge_4d(float4 coord,
float4 cellPosition = floor(coord);
float4 localPosition = coord - cellPosition;
- float4 vectorToClosest = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 vectorToClosest = zero_float4();
float minDistance = 8.0f;
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
@@ -859,8 +859,8 @@ ccl_device void voronoi_n_sphere_radius_4d(float4 coord,
float4 cellPosition = floor(coord);
float4 localPosition = coord - cellPosition;
- float4 closestPoint = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
- float4 closestPointOffset = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 closestPoint = zero_float4();
+ float4 closestPointOffset = zero_float4();
float minDistance = 8.0f;
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
@@ -882,7 +882,7 @@ ccl_device void voronoi_n_sphere_radius_4d(float4 coord,
}
minDistance = 8.0f;
- float4 closestPointToClosestPoint = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 closestPointToClosestPoint = zero_float4();
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
ccl_loop_no_unroll for (int j = -1; j <= 1; j++)
diff --git a/intern/cycles/kernel/svm/voxel.h b/intern/cycles/kernel/svm/voxel.h
index c5f6a6f004a..553a00cd09a 100644
--- a/intern/cycles/kernel/svm/voxel.h
+++ b/intern/cycles/kernel/svm/voxel.h
@@ -30,7 +30,7 @@ ccl_device_noinline int svm_node_tex_voxel(
float4 r = kernel_tex_image_interp_3d(kg, id, co, INTERPOLATION_NONE);
#else
- float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 r = zero_float4();
#endif
if (stack_valid(density_out_offset))
stack_store_float(stack, density_out_offset, r.w);
diff --git a/intern/cycles/scene/integrator.cpp b/intern/cycles/scene/integrator.cpp
index 64c95538f82..fd559178073 100644
--- a/intern/cycles/scene/integrator.cpp
+++ b/intern/cycles/scene/integrator.cpp
@@ -109,8 +109,10 @@ NODE_DEFINE(Integrator)
SOCKET_INT(denoise_start_sample, "Start Sample to Denoise", 0);
SOCKET_BOOLEAN(use_denoise_pass_albedo, "Use Albedo Pass for Denoiser", true);
SOCKET_BOOLEAN(use_denoise_pass_normal, "Use Normal Pass for Denoiser", true);
- SOCKET_ENUM(
- denoiser_prefilter, "Denoiser Type", denoiser_prefilter_enum, DENOISER_PREFILTER_ACCURATE);
+ SOCKET_ENUM(denoiser_prefilter,
+ "Denoiser Prefilter",
+ denoiser_prefilter_enum,
+ DENOISER_PREFILTER_ACCURATE);
return type;
}
diff --git a/intern/cycles/scene/mesh.cpp b/intern/cycles/scene/mesh.cpp
index a459195efee..05024a7790e 100644
--- a/intern/cycles/scene/mesh.cpp
+++ b/intern/cycles/scene/mesh.cpp
@@ -142,8 +142,8 @@ NODE_DEFINE(Mesh)
SOCKET_INT(num_ngons, "NGons Number", 0);
/* Subdivisions parameters */
- SOCKET_FLOAT(subd_dicing_rate, "Subdivision Dicing Rate", 0.0f)
- SOCKET_INT(subd_max_level, "Subdivision Dicing Rate", 0);
+ SOCKET_FLOAT(subd_dicing_rate, "Subdivision Dicing Rate", 1.0f)
+ SOCKET_INT(subd_max_level, "Max Subdivision Level", 1);
SOCKET_TRANSFORM(subd_objecttoworld, "Subdivision Object Transform", transform_identity());
return type;
@@ -357,7 +357,7 @@ void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_)
}
}
-void Mesh::add_subd_face(int *corners, int num_corners, int shader_, bool smooth_)
+void Mesh::add_subd_face(const int *corners, int num_corners, int shader_, bool smooth_)
{
int start_corner = subd_face_corners.size();
@@ -411,8 +411,6 @@ void Mesh::add_edge_crease(int v0, int v1, float weight)
void Mesh::add_vertex_crease(int v, float weight)
{
- assert(v < verts.size());
-
subd_vert_creases.push_back_slow(v);
subd_vert_creases_weight.push_back_slow(weight);
diff --git a/intern/cycles/scene/mesh.h b/intern/cycles/scene/mesh.h
index 4e6991a3960..a09f192d969 100644
--- a/intern/cycles/scene/mesh.h
+++ b/intern/cycles/scene/mesh.h
@@ -199,7 +199,7 @@ class Mesh : public Geometry {
void add_vertex(float3 P);
void add_vertex_slow(float3 P);
void add_triangle(int v0, int v1, int v2, int shader, bool smooth);
- void add_subd_face(int *corners, int num_corners, int shader_, bool smooth_);
+ void add_subd_face(const int *corners, int num_corners, int shader_, bool smooth_);
void add_edge_crease(int v0, int v1, float weight);
void add_vertex_crease(int v, float weight);
diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp
index 272a0dde7d8..a951a558731 100644
--- a/intern/cycles/scene/shader_nodes.cpp
+++ b/intern/cycles/scene/shader_nodes.cpp
@@ -6529,9 +6529,9 @@ void CurvesNode::constant_fold(const ConstantFolder &folder, ShaderInput *value_
float3 pos = (value - make_float3(min_x, min_x, min_x)) / (max_x - min_x);
float3 result;
- result[0] = rgb_ramp_lookup(curves.data(), pos[0], true, true, curves.size()).x;
- result[1] = rgb_ramp_lookup(curves.data(), pos[1], true, true, curves.size()).y;
- result[2] = rgb_ramp_lookup(curves.data(), pos[2], true, true, curves.size()).z;
+ result[0] = rgb_ramp_lookup(curves.data(), pos[0], true, extrapolate, curves.size()).x;
+ result[1] = rgb_ramp_lookup(curves.data(), pos[1], true, extrapolate, curves.size()).y;
+ result[2] = rgb_ramp_lookup(curves.data(), pos[2], true, extrapolate, curves.size()).z;
folder.make_constant(interp(value, result, fac));
}
@@ -6555,7 +6555,8 @@ void CurvesNode::compile(SVMCompiler &compiler,
compiler.add_node(type,
compiler.encode_uchar4(compiler.stack_assign(fac_in),
compiler.stack_assign(value_in),
- compiler.stack_assign(value_out)),
+ compiler.stack_assign(value_out),
+ extrapolate),
__float_as_int(min_x),
__float_as_int(max_x));
@@ -6572,6 +6573,7 @@ void CurvesNode::compile(OSLCompiler &compiler, const char *name)
compiler.parameter_color_array("ramp", curves);
compiler.parameter(this, "min_x");
compiler.parameter(this, "max_x");
+ compiler.parameter(this, "extrapolate");
compiler.add(this, name);
}
@@ -6594,6 +6596,7 @@ NODE_DEFINE(RGBCurvesNode)
SOCKET_COLOR_ARRAY(curves, "Curves", array<float3>());
SOCKET_FLOAT(min_x, "Min X", 0.0f);
SOCKET_FLOAT(max_x, "Max X", 1.0f);
+ SOCKET_BOOLEAN(extrapolate, "Extrapolate", true);
SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
SOCKET_IN_COLOR(value, "Color", zero_float3());
@@ -6631,6 +6634,7 @@ NODE_DEFINE(VectorCurvesNode)
SOCKET_VECTOR_ARRAY(curves, "Curves", array<float3>());
SOCKET_FLOAT(min_x, "Min X", 0.0f);
SOCKET_FLOAT(max_x, "Max X", 1.0f);
+ SOCKET_BOOLEAN(extrapolate, "Extrapolate", true);
SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
SOCKET_IN_VECTOR(value, "Vector", zero_float3());
@@ -6668,6 +6672,7 @@ NODE_DEFINE(FloatCurveNode)
SOCKET_FLOAT_ARRAY(curve, "Curve", array<float>());
SOCKET_FLOAT(min_x, "Min X", 0.0f);
SOCKET_FLOAT(max_x, "Max X", 1.0f);
+ SOCKET_BOOLEAN(extrapolate, "Extrapolate", true);
SOCKET_IN_FLOAT(fac, "Factor", 0.0f);
SOCKET_IN_FLOAT(value, "Value", 0.0f);
@@ -6693,7 +6698,7 @@ void FloatCurveNode::constant_fold(const ConstantFolder &folder)
}
float pos = (value - min_x) / (max_x - min_x);
- float result = float_ramp_lookup(curve.data(), pos, true, true, curve.size());
+ float result = float_ramp_lookup(curve.data(), pos, true, extrapolate, curve.size());
folder.make_constant(value + fac * (result - value));
}
@@ -6716,7 +6721,8 @@ void FloatCurveNode::compile(SVMCompiler &compiler)
compiler.add_node(NODE_FLOAT_CURVE,
compiler.encode_uchar4(compiler.stack_assign(fac_in),
compiler.stack_assign(value_in),
- compiler.stack_assign(value_out)),
+ compiler.stack_assign(value_out),
+ extrapolate),
__float_as_int(min_x),
__float_as_int(max_x));
@@ -6733,6 +6739,7 @@ void FloatCurveNode::compile(OSLCompiler &compiler)
compiler.parameter_array("ramp", curve.data(), curve.size());
compiler.parameter(this, "min_x");
compiler.parameter(this, "max_x");
+ compiler.parameter(this, "extrapolate");
compiler.add(this, "node_float_curve");
}
diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h
index ef9e8772961..9aef5d3151f 100644
--- a/intern/cycles/scene/shader_nodes.h
+++ b/intern/cycles/scene/shader_nodes.h
@@ -1391,6 +1391,7 @@ class CurvesNode : public ShaderNode {
NODE_SOCKET_API(float, max_x)
NODE_SOCKET_API(float, fac)
NODE_SOCKET_API(float3, value)
+ NODE_SOCKET_API(bool, extrapolate)
protected:
using ShaderNode::constant_fold;
@@ -1421,6 +1422,7 @@ class FloatCurveNode : public ShaderNode {
NODE_SOCKET_API(float, max_x)
NODE_SOCKET_API(float, fac)
NODE_SOCKET_API(float, value)
+ NODE_SOCKET_API(bool, extrapolate)
};
class RGBRampNode : public ShaderNode {
diff --git a/intern/cycles/session/session.h b/intern/cycles/session/session.h
index 3e90b41e3e9..d431c61a5fc 100644
--- a/intern/cycles/session/session.h
+++ b/intern/cycles/session/session.h
@@ -54,6 +54,8 @@ class SessionParams {
bool use_auto_tile;
int tile_size;
+ bool use_resolution_divider;
+
ShadingSystem shadingsystem;
/* Session-specific temporary directory to store in-progress EXR files in. */
@@ -76,6 +78,8 @@ class SessionParams {
use_auto_tile = true;
tile_size = 2048;
+ use_resolution_divider = true;
+
shadingsystem = SHADINGSYSTEM_SVM;
}
diff --git a/intern/cycles/session/tile.cpp b/intern/cycles/session/tile.cpp
index 755e85450a3..82272a7dbf5 100644
--- a/intern/cycles/session/tile.cpp
+++ b/intern/cycles/session/tile.cpp
@@ -43,7 +43,6 @@ static std::vector<std::string> exr_channel_names_for_passes(const BufferParams
static const char *component_suffixes[] = {"R", "G", "B", "A"};
int pass_index = 0;
- int num_channels = 0;
std::vector<std::string> channel_names;
for (const BufferPass &pass : buffer_params.passes) {
if (pass.offset == PASS_UNUSED) {
@@ -51,7 +50,6 @@ static std::vector<std::string> exr_channel_names_for_passes(const BufferParams
}
const PassInfo pass_info = pass.get_info();
- num_channels += pass_info.num_components;
/* EXR canonically expects first part of channel names to be sorted alphabetically, which is
* not guaranteed to be the case with passes names. Assign a prefix based on the pass index
diff --git a/intern/cycles/util/math_float4.h b/intern/cycles/util/math_float4.h
index 9f4a1a904b5..ae9dfe75a9c 100644
--- a/intern/cycles/util/math_float4.h
+++ b/intern/cycles/util/math_float4.h
@@ -297,7 +297,7 @@ ccl_device_inline float4 cross(const float4 &a, const float4 &b)
ccl_device_inline bool is_zero(const float4 &a)
{
# ifdef __KERNEL_SSE__
- return a == make_float4(0.0f);
+ return a == zero_float4();
# else
return (a.x == 0.0f && a.y == 0.0f && a.z == 0.0f && a.w == 0.0f);
# endif
@@ -458,7 +458,7 @@ ccl_device_inline float4 select(const int4 &mask, const float4 &a, const float4
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
{
/* Replace elements of x with zero where mask isn't set. */
- return select(mask, a, make_float4(0.0f));
+ return select(mask, a, zero_float4());
}
ccl_device_inline float4 reduce_min(const float4 &a)
diff --git a/intern/cycles/util/math_matrix.h b/intern/cycles/util/math_matrix.h
index a4318fda6e8..b10d9b3c938 100644
--- a/intern/cycles/util/math_matrix.h
+++ b/intern/cycles/util/math_matrix.h
@@ -376,7 +376,7 @@ ccl_device void math_matrix_jacobi_eigendecomposition(ccl_private float *A,
ccl_device_inline void math_vector_zero_sse(float4 *A, int n)
{
for (int i = 0; i < n; i++) {
- A[i] = make_float4(0.0f);
+ A[i] = zero_float4();
}
}
@@ -384,7 +384,7 @@ ccl_device_inline void math_matrix_zero_sse(float4 *A, int n)
{
for (int row = 0; row < n; row++) {
for (int col = 0; col <= row; col++) {
- MAT(A, n, row, col) = make_float4(0.0f);
+ MAT(A, n, row, col) = zero_float4();
}
}
}
diff --git a/intern/cycles/util/tbb.h b/intern/cycles/util/tbb.h
index 2c26c3a5170..7105ddda0f8 100644
--- a/intern/cycles/util/tbb.h
+++ b/intern/cycles/util/tbb.h
@@ -16,6 +16,7 @@
#if TBB_INTERFACE_VERSION_MAJOR >= 10
# define WITH_TBB_GLOBAL_CONTROL
+# define TBB_PREVIEW_GLOBAL_CONTROL 1
# include <tbb/global_control.h>
#endif
diff --git a/intern/dualcon/intern/octree.cpp b/intern/dualcon/intern/octree.cpp
index 9e360848e6b..18242d48292 100644
--- a/intern/dualcon/intern/octree.cpp
+++ b/intern/dualcon/intern/octree.cpp
@@ -242,6 +242,10 @@ void Octree::printMemUsage()
dc_printf("Total allocated bytes on disk: %d \n", totalbytes);
dc_printf("Total leaf nodes: %d\n", totalLeafs);
+
+ /* Unused when not debuggining. */
+ (void)totalbytes;
+ (void)totalLeafs;
}
void Octree::resetMinimalEdges()
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index 4e48a908c00..a82f634183d 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -146,7 +146,7 @@ extern void GHOST_GetAllDisplayDimensions(GHOST_SystemHandle systemhandle,
* The new window is added to the list of windows managed.
* Never explicitly delete the window, use disposeWindow() instead.
* \param systemhandle: The handle to the system.
- * \param parentWindow: Handle of parent (or owner) window, or NULL
+ * \param parent_windowhandle: Handle of parent (or owner) window, or NULL
* \param title: The name of the window.
* (displayed in the title bar of the window if the OS supports it).
* \param left: The coordinate of the left edge of the window.
@@ -175,7 +175,7 @@ extern GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
* Create a new off-screen context.
* Never explicitly delete the context, use #disposeContext() instead.
* \param systemhandle: The handle to the system.
- * \param platform_support_callback: An optional callback to check platform support.
+ * \param glSettings: Misc OpenGL options.
* \return A handle to the new context ( == NULL if creation failed).
*/
extern GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemhandle,
diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm
index 9322b6cee7a..dd800ef52a3 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.mm
+++ b/intern/ghost/intern/GHOST_ContextCGL.mm
@@ -7,6 +7,12 @@
* Definition of GHOST_ContextCGL class.
*/
+/* Don't generate OpenGL deprecation warning. This is a known thing, and is not something easily
+ * solvable in a short term. */
+#ifdef __clang__
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
#include "GHOST_ContextCGL.h"
#include <Cocoa/Cocoa.h>
diff --git a/intern/ghost/intern/GHOST_ImeWin32.cpp b/intern/ghost/intern/GHOST_ImeWin32.cpp
index 702c10d377b..c3fcd7214ca 100644
--- a/intern/ghost/intern/GHOST_ImeWin32.cpp
+++ b/intern/ghost/intern/GHOST_ImeWin32.cpp
@@ -88,9 +88,14 @@ bool GHOST_ImeWin32::IsImeKeyEvent(char ascii, GHOST_TKey key)
if (IsLanguage(IMELANG_JAPANESE) && (ascii >= ' ' && ascii <= '~')) {
return true;
}
- else if (IsLanguage(IMELANG_CHINESE) && ascii && strchr("!\"$'(),.:;<>?[\\]^_`/", ascii) &&
- !(key == GHOST_kKeyNumpadPeriod)) {
- return true;
+ if (IsLanguage(IMELANG_CHINESE)) {
+ if (ascii && strchr("!\"$'(),.:;<>?[\\]^_`/", ascii) && !(key == GHOST_kKeyNumpadPeriod)) {
+ return true;
+ }
+ if (conversion_modes_ & IME_CMODE_FULLSHAPE && (ascii >= '0' && ascii <= '9')) {
+ /* When in Full Width mode the number keys are also converted. */
+ return true;
+ }
}
}
return false;
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index f0db6b6fdfc..b6836614962 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -1050,8 +1050,6 @@ void GHOST_SystemCocoa::notifyExternalEventProcessed()
GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
GHOST_WindowCocoa *window)
{
- NSArray *windowsList;
- windowsList = [NSApp orderedWindows];
if (!validWindow(window)) {
return GHOST_kFailure;
}
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 0f4b5147082..11a3c097958 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -151,6 +151,12 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
::SetWindowPos(m_hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
+ if (parentwindow) {
+ /* Release any parent capture to allow immediate interaction (T90110). */
+ ::ReleaseCapture();
+ parentwindow->lostMouseCapture();
+ }
+
/* Show the window. */
int nCmdShow;
switch (state) {
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index 79b4e9d0cf6..d5f47871aff 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -206,9 +206,7 @@ class GHOST_WindowWin32 : public GHOST_Window {
GHOST_TSuccess endProgressBar();
/**
- * Register a mouse capture state (should be called
- * for any real button press, controls mouse
- * capturing).
+ * Set or Release mouse capture (should be called for any real button press).
*
* \param event: Whether mouse was pressed and released,
* or an operator grabbed or ungrabbed the mouse.
@@ -216,8 +214,9 @@ class GHOST_WindowWin32 : public GHOST_Window {
void updateMouseCapture(GHOST_MouseCaptureEventWin32 event);
/**
- * Inform the window that it has lost mouse capture,
- * called in response to native window system messages.
+ * Inform the window that it has lost mouse capture, called in response to native window system
+ * messages (WA_INACTIVE, WM_CAPTURECHANGED) or if ReleaseCapture() is explicitly called (for new
+ * window creation).
*/
void lostMouseCapture();
diff --git a/intern/ghost/intern/GHOST_XrControllerModel.cpp b/intern/ghost/intern/GHOST_XrControllerModel.cpp
index 78d81651e92..5be3a8e70ad 100644
--- a/intern/ghost/intern/GHOST_XrControllerModel.cpp
+++ b/intern/ghost/intern/GHOST_XrControllerModel.cpp
@@ -234,7 +234,7 @@ static void calc_node_transforms(const tinygltf::Node &gltf_node,
{(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);
+ memcpy(r_local_transform, m, sizeof(float[4][4]));
}
else {
/* No matrix is present, so construct a matrix from the TRS values (each one is optional). */
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index d8a8c1181e4..8cd2c9f94dd 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -279,6 +279,24 @@ template<typename T> inline T *MEM_cnew(const char *allocation_name)
}
/**
+ * Allocate memory for an object of type #T and copy construct an object from `other`.
+ * Only applicable for a trivial types.
+ *
+ * This function works around problem of copy-constructing DNA structs which contains deprecated
+ * fields: some compilers will generate access deprecated field in implicitly defined copy
+ * constructors.
+ *
+ * This is a better alternative to #MEM_dupallocN.
+ */
+template<typename T> inline T *MEM_cnew(const char *allocation_name, const T &other)
+{
+ static_assert(std::is_trivial_v<T>, "For non-trivial types, MEM_new should be used.");
+ T *new_object = static_cast<T *>(MEM_mallocN(sizeof(T), allocation_name));
+ memcpy(new_object, &other, sizeof(T));
+ return new_object;
+}
+
+/**
* Destructs and deallocates an object previously allocated with any `MEM_*` function.
* Passing in null does nothing.
*/
diff --git a/intern/itasc/Armature.cpp b/intern/itasc/Armature.cpp
index f365d40e9f1..e6968faf19a 100644
--- a/intern/itasc/Armature.cpp
+++ b/intern/itasc/Armature.cpp
@@ -1,12 +1,9 @@
-/** \file itasc/Armature.cpp
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Benoit Bolsee. */
+
+/** \file
* \ingroup intern_itasc
*/
-/*
- * Armature.cpp
- *
- * Created on: Feb 3, 2009
- * Author: benoitbolsee
- */
#include "Armature.hpp"
#include <algorithm>
diff --git a/intern/itasc/Armature.hpp b/intern/itasc/Armature.hpp
index 3167247ab03..ce47869c55b 100644
--- a/intern/itasc/Armature.hpp
+++ b/intern/itasc/Armature.hpp
@@ -1,8 +1,8 @@
-/*
- * Armature.hpp
- *
- * Created on: Feb 3, 2009
- * Author: benoitbolsee
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Benoit Bolsee. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef ARMATURE_HPP_
diff --git a/intern/itasc/Cache.cpp b/intern/itasc/Cache.cpp
index 28e6fbd22b1..1d5e63ba298 100644
--- a/intern/itasc/Cache.cpp
+++ b/intern/itasc/Cache.cpp
@@ -1,12 +1,10 @@
-/** \file itasc/Cache.cpp
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Benoit Bolsee. */
+
+/** \file
* \ingroup intern_itasc
*/
-/*
- * Cache.cpp
- *
- * Created on: Feb 24, 2009
- * Author: benoit bolsee
- */
+
#include <string.h>
#include <assert.h>
#include <math.h>
diff --git a/intern/itasc/Cache.hpp b/intern/itasc/Cache.hpp
index d461bb32fa8..27f95f16ec4 100644
--- a/intern/itasc/Cache.hpp
+++ b/intern/itasc/Cache.hpp
@@ -1,8 +1,8 @@
-/*
- * Cache.hpp
- *
- * Created on: Feb 24, 2009
- * Author: benoit tbolsee
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Benoit Bolsee. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef CACHE_HPP_
diff --git a/intern/itasc/ConstraintSet.cpp b/intern/itasc/ConstraintSet.cpp
index fda1ee9d70d..f731f4c5a5f 100644
--- a/intern/itasc/ConstraintSet.cpp
+++ b/intern/itasc/ConstraintSet.cpp
@@ -1,12 +1,9 @@
-/** \file itasc/ConstraintSet.cpp
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
* \ingroup intern_itasc
*/
-/*
- * ConstraintSet.cpp
- *
- * Created on: Jan 5, 2009
- * Author: rubensmits
- */
#include "ConstraintSet.hpp"
#include "kdl/utilities/svd_eigen_HH.hpp"
diff --git a/intern/itasc/ConstraintSet.hpp b/intern/itasc/ConstraintSet.hpp
index bf29190a050..ad92a8d9779 100644
--- a/intern/itasc/ConstraintSet.hpp
+++ b/intern/itasc/ConstraintSet.hpp
@@ -1,8 +1,8 @@
-/*
- * ConstraintSet.hpp
- *
- * Created on: Jan 5, 2009
- * Author: rubensmits
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef CONSTRAINTSET_HPP_
diff --git a/intern/itasc/ControlledObject.cpp b/intern/itasc/ControlledObject.cpp
index bb2e4117361..231a96d7813 100644
--- a/intern/itasc/ControlledObject.cpp
+++ b/intern/itasc/ControlledObject.cpp
@@ -1,12 +1,9 @@
-/** \file itasc/ControlledObject.cpp
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
* \ingroup intern_itasc
*/
-/*
- * ControlledObject.cpp
- *
- * Created on: Jan 5, 2009
- * Author: rubensmits
- */
#include "ControlledObject.hpp"
diff --git a/intern/itasc/ControlledObject.hpp b/intern/itasc/ControlledObject.hpp
index 4530bf9823b..8ffb68cfb79 100644
--- a/intern/itasc/ControlledObject.hpp
+++ b/intern/itasc/ControlledObject.hpp
@@ -1,8 +1,8 @@
-/*
- * ControlledObject.hpp
- *
- * Created on: Jan 5, 2009
- * Author: rubensmits
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef CONTROLLEDOBJECT_HPP_
diff --git a/intern/itasc/CopyPose.cpp b/intern/itasc/CopyPose.cpp
index a9b6d3cd680..9b4ff5cb6a0 100644
--- a/intern/itasc/CopyPose.cpp
+++ b/intern/itasc/CopyPose.cpp
@@ -1,12 +1,9 @@
-/** \file itasc/CopyPose.cpp
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Benoit Bolsee. */
+
+/** \file
* \ingroup intern_itasc
*/
-/*
- * CopyPose.cpp
- *
- * Created on: Mar 17, 2009
- * Author: benoit bolsee
- */
#include "CopyPose.hpp"
#include "kdl/kinfam_io.hpp"
diff --git a/intern/itasc/CopyPose.hpp b/intern/itasc/CopyPose.hpp
index fd8a5451310..92966b85b6f 100644
--- a/intern/itasc/CopyPose.hpp
+++ b/intern/itasc/CopyPose.hpp
@@ -1,8 +1,8 @@
-/*
- * CopyPose.h
- *
- * Created on: Mar 17, 2009
- * Author: benoit bolsee
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Benoit Bolsee. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef COPYPOSE_H_
diff --git a/intern/itasc/Distance.cpp b/intern/itasc/Distance.cpp
index 6a368944ed3..7359a45dec0 100644
--- a/intern/itasc/Distance.cpp
+++ b/intern/itasc/Distance.cpp
@@ -1,12 +1,9 @@
-/** \file itasc/Distance.cpp
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
* \ingroup intern_itasc
*/
-/*
- * Distance.cpp
- *
- * Created on: Jan 30, 2009
- * Author: rsmits
- */
#include "Distance.hpp"
#include "kdl/kinfam_io.hpp"
diff --git a/intern/itasc/Distance.hpp b/intern/itasc/Distance.hpp
index 5c56dd871ef..02a8f9d9f29 100644
--- a/intern/itasc/Distance.hpp
+++ b/intern/itasc/Distance.hpp
@@ -1,8 +1,8 @@
-/*
- * Distance.hpp
- *
- * Created on: Jan 30, 2009
- * Author: rsmits
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef DISTANCE_HPP_
diff --git a/intern/itasc/FixedObject.cpp b/intern/itasc/FixedObject.cpp
index 8a547ac2b05..1fa4b77dfe5 100644
--- a/intern/itasc/FixedObject.cpp
+++ b/intern/itasc/FixedObject.cpp
@@ -1,12 +1,9 @@
-/** \file itasc/FixedObject.cpp
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Benoit Bolsee. */
+
+/** \file
* \ingroup intern_itasc
*/
-/*
- * FixedObject.cpp
- *
- * Created on: Feb 10, 2009
- * Author: benoitbolsee
- */
#include "FixedObject.hpp"
diff --git a/intern/itasc/FixedObject.hpp b/intern/itasc/FixedObject.hpp
index ad26e7cb2d6..1b8544a90e5 100644
--- a/intern/itasc/FixedObject.hpp
+++ b/intern/itasc/FixedObject.hpp
@@ -1,8 +1,8 @@
-/*
- * FixedObject.h
- *
- * Created on: Feb 10, 2009
- * Author: benoitbolsee
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Benoit Bolsee. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef FIXEDOBJECT_HPP_
diff --git a/intern/itasc/MovingFrame.cpp b/intern/itasc/MovingFrame.cpp
index e3f4d612155..cda9ae8b3fa 100644
--- a/intern/itasc/MovingFrame.cpp
+++ b/intern/itasc/MovingFrame.cpp
@@ -1,12 +1,9 @@
-/** \file itasc/MovingFrame.cpp
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Benoit Bolsee. */
+
+/** \file
* \ingroup intern_itasc
*/
-/*
- * MovingFrame.cpp
- *
- * Created on: Feb 10, 2009
- * Author: benoitbolsee
- */
#include "MovingFrame.hpp"
#include <string.h>
diff --git a/intern/itasc/MovingFrame.hpp b/intern/itasc/MovingFrame.hpp
index 2e9c2f64bd6..9e499610812 100644
--- a/intern/itasc/MovingFrame.hpp
+++ b/intern/itasc/MovingFrame.hpp
@@ -1,8 +1,8 @@
-/*
- * MovingFrame.h
- *
- * Created on: Feb 10, 2009
- * Author: benoitbolsee
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Benoit Bolsee. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef MOVINGFRAME_HPP_
diff --git a/intern/itasc/Object.hpp b/intern/itasc/Object.hpp
index bf80d83e5aa..00c1b9e9fca 100644
--- a/intern/itasc/Object.hpp
+++ b/intern/itasc/Object.hpp
@@ -1,8 +1,8 @@
-/*
- * Object.hpp
- *
- * Created on: Jan 5, 2009
- * Author: rubensmits
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef OBJECT_HPP_
diff --git a/intern/itasc/Scene.cpp b/intern/itasc/Scene.cpp
index b5f8e4df386..0b9c8cb1056 100644
--- a/intern/itasc/Scene.cpp
+++ b/intern/itasc/Scene.cpp
@@ -1,12 +1,9 @@
-/** \file itasc/Scene.cpp
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
* \ingroup intern_itasc
*/
-/*
- * Scene.cpp
- *
- * Created on: Jan 5, 2009
- * Author: rubensmits
- */
#include "Scene.hpp"
#include "ControlledObject.hpp"
@@ -270,7 +267,7 @@ bool Scene::initialize()
m_ytask.resize(m_ncTotal);
bool toggle = true;
- int cnt = 0;
+ int count = 0;
// Initialize all ConstraintSets:
for (ConstraintMap::iterator it = constraints.begin(); it != constraints.end(); ++it) {
// Calculate the external pose:
@@ -279,8 +276,8 @@ bool Scene::initialize()
getConstraintPose(cs->task, cs, external_pose);
result &= cs->task->initialise(external_pose);
cs->task->initCache(m_cache);
- for (int i = 0; i < cs->constraintrange.count; i++, cnt++) {
- m_ytask[cnt] = toggle;
+ for (int i = 0; i < cs->constraintrange.count; i++, count++) {
+ m_ytask[count] = toggle;
}
toggle = !toggle;
project(m_Cf, cs->constraintrange, cs->featurerange) = cs->task->getCf();
diff --git a/intern/itasc/Scene.hpp b/intern/itasc/Scene.hpp
index 5ed031b543e..92ded8c8d9d 100644
--- a/intern/itasc/Scene.hpp
+++ b/intern/itasc/Scene.hpp
@@ -1,8 +1,8 @@
-/*
- * Scene.hpp
- *
- * Created on: Jan 5, 2009
- * Author: rubensmits
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef SCENE_HPP_
diff --git a/intern/itasc/Solver.hpp b/intern/itasc/Solver.hpp
index 809c03d9bce..2213834f114 100644
--- a/intern/itasc/Solver.hpp
+++ b/intern/itasc/Solver.hpp
@@ -1,8 +1,8 @@
-/*
- * Solver.hpp
- *
- * Created on: Jan 8, 2009
- * Author: rubensmits
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef SOLVER_HPP_
diff --git a/intern/itasc/UncontrolledObject.cpp b/intern/itasc/UncontrolledObject.cpp
index 3083b711217..d8c5db9a7c5 100644
--- a/intern/itasc/UncontrolledObject.cpp
+++ b/intern/itasc/UncontrolledObject.cpp
@@ -1,12 +1,9 @@
-/** \file itasc/UncontrolledObject.cpp
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
* \ingroup intern_itasc
*/
-/*
- * UncontrolledObject.cpp
- *
- * Created on: Jan 5, 2009
- * Author: rubensmits
- */
#include "UncontrolledObject.hpp"
diff --git a/intern/itasc/UncontrolledObject.hpp b/intern/itasc/UncontrolledObject.hpp
index 81445538fa6..fad3be61653 100644
--- a/intern/itasc/UncontrolledObject.hpp
+++ b/intern/itasc/UncontrolledObject.hpp
@@ -1,8 +1,8 @@
-/*
- * UncontrolledObject.h
- *
- * Created on: Jan 5, 2009
- * Author: rubensmits
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef UNCONTROLLEDOBJECT_HPP_
diff --git a/intern/itasc/WDLSSolver.cpp b/intern/itasc/WDLSSolver.cpp
index c5221fc2767..37190a88974 100644
--- a/intern/itasc/WDLSSolver.cpp
+++ b/intern/itasc/WDLSSolver.cpp
@@ -1,12 +1,9 @@
-/** \file itasc/WDLSSolver.cpp
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
* \ingroup intern_itasc
*/
-/*
- * WDLSSolver.hpp.cpp
- *
- * Created on: Jan 8, 2009
- * Author: rubensmits
- */
#include "WDLSSolver.hpp"
#include "kdl/utilities/svd_eigen_HH.hpp"
diff --git a/intern/itasc/WDLSSolver.hpp b/intern/itasc/WDLSSolver.hpp
index 4e72490cf1b..61c96d29c77 100644
--- a/intern/itasc/WDLSSolver.hpp
+++ b/intern/itasc/WDLSSolver.hpp
@@ -1,8 +1,8 @@
-/*
- * WDLSSolver.hpp
- *
- * Created on: Jan 8, 2009
- * Author: rubensmits
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef WDLSSOLVER_HPP_
diff --git a/intern/itasc/WSDLSSolver.cpp b/intern/itasc/WSDLSSolver.cpp
index 32273828acc..bd1f1407185 100644
--- a/intern/itasc/WSDLSSolver.cpp
+++ b/intern/itasc/WSDLSSolver.cpp
@@ -1,12 +1,9 @@
-/** \file itasc/WSDLSSolver.cpp
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
* \ingroup intern_itasc
*/
-/*
- * WDLSSolver.hpp.cpp
- *
- * Created on: Jan 8, 2009
- * Author: rubensmits
- */
#include "WSDLSSolver.hpp"
#include "kdl/utilities/svd_eigen_HH.hpp"
diff --git a/intern/itasc/WSDLSSolver.hpp b/intern/itasc/WSDLSSolver.hpp
index e6516031428..9456879d40e 100644
--- a/intern/itasc/WSDLSSolver.hpp
+++ b/intern/itasc/WSDLSSolver.hpp
@@ -1,8 +1,8 @@
-/*
- * WSDLSSolver.hpp
- *
- * Created on: Mar 26, 2009
- * Author: benoit bolsee
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Benoit Bolsee. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef WSDLSSOLVER_HPP_
diff --git a/intern/itasc/WorldObject.cpp b/intern/itasc/WorldObject.cpp
index 34641478ea0..69a80385d1a 100644
--- a/intern/itasc/WorldObject.cpp
+++ b/intern/itasc/WorldObject.cpp
@@ -1,12 +1,9 @@
-/** \file itasc/WorldObject.cpp
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Benoit Bolsee. */
+
+/** \file
* \ingroup intern_itasc
*/
-/*
- * WorldObject.cpp
- *
- * Created on: Feb 10, 2009
- * Author: benoitbolsee
- */
#include "WorldObject.hpp"
diff --git a/intern/itasc/WorldObject.hpp b/intern/itasc/WorldObject.hpp
index 99756dcd684..49b275fef92 100644
--- a/intern/itasc/WorldObject.hpp
+++ b/intern/itasc/WorldObject.hpp
@@ -1,8 +1,8 @@
-/*
- * WorldObject.h
- *
- * Created on: Feb 10, 2009
- * Author: benoitbolsee
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef WORLDOBJECT_HPP_
diff --git a/intern/itasc/eigen_types.cpp b/intern/itasc/eigen_types.cpp
index a1c0525766e..f0ae03b1e0c 100644
--- a/intern/itasc/eigen_types.cpp
+++ b/intern/itasc/eigen_types.cpp
@@ -1,12 +1,9 @@
-/** \file itasc/eigen_types.cpp
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Benoit Bolsee. */
+
+/** \file
* \ingroup intern_itasc
*/
-/*
- * eigen_types.cpp
- *
- * Created on: March 19, 2009
- * Author: benoit bolsee
- */
#include "eigen_types.hpp"
diff --git a/intern/itasc/eigen_types.hpp b/intern/itasc/eigen_types.hpp
index 601b69274d9..2ab4da1cb72 100644
--- a/intern/itasc/eigen_types.hpp
+++ b/intern/itasc/eigen_types.hpp
@@ -1,8 +1,8 @@
-/*
- * eigen_types.hpp
- *
- * Created on: March 6, 2009
- * Author: benoit bolsee
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Benoit Bolsee. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef EIGEN_TYPES_HPP_
diff --git a/intern/itasc/ublas_types.hpp b/intern/itasc/ublas_types.hpp
index bf9bdcc26f2..3ba5b4a1e21 100644
--- a/intern/itasc/ublas_types.hpp
+++ b/intern/itasc/ublas_types.hpp
@@ -1,8 +1,8 @@
-/*
- * ublas_types.hpp
- *
- * Created on: Jan 5, 2009
- * Author: rubensmits
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * Copyright 2009 Ruben Smits. */
+
+/** \file
+ * \ingroup intern_itasc
*/
#ifndef UBLAS_TYPES_HPP_
diff --git a/intern/mantaflow/intern/MANTA_main.cpp b/intern/mantaflow/intern/MANTA_main.cpp
index 6083c4908a1..282fbdb3f77 100644
--- a/intern/mantaflow/intern/MANTA_main.cpp
+++ b/intern/mantaflow/intern/MANTA_main.cpp
@@ -263,6 +263,8 @@ MANTA::MANTA(int *res, FluidModifierData *fmd)
}
/* All requested initializations must not fail in constructor. */
BLI_assert(initSuccess);
+ (void)initSuccess; /* Ignored in release. */
+
updatePointers(fmd);
}
diff --git a/intern/mantaflow/intern/strings/fluid_script.h b/intern/mantaflow/intern/strings/fluid_script.h
index 48e0c243e16..548606f1b32 100644
--- a/intern/mantaflow/intern/strings/fluid_script.h
+++ b/intern/mantaflow/intern/strings/fluid_script.h
@@ -739,13 +739,13 @@ file_format_data = '$CACHE_DATA_FORMAT$'\n\
file_format_mesh = '$CACHE_MESH_FORMAT$'\n\
\n\
# How many frame to load from cache\n\
-from_cache_cnt = 100\n\
+from_cache_count = 100\n\
\n\
-loop_cnt = 0\n\
+loop_count = 0\n\
while current_frame_s$ID$ <= end_frame_s$ID$:\n\
\n\
# Load already simulated data from cache:\n\
- if loop_cnt < from_cache_cnt:\n\
+ if loop_count < from_cache_count:\n\
load_data(current_frame_s$ID$, cache_resumable)\n\
\n\
# Otherwise simulate new data\n\
@@ -756,7 +756,7 @@ while current_frame_s$ID$ <= end_frame_s$ID$:\n\
step(current_frame_s$ID$)\n\
\n\
current_frame_s$ID$ += 1\n\
- loop_cnt += 1\n\
+ loop_count += 1\n\
\n\
if gui:\n\
gui.pause()\n";
diff --git a/intern/mikktspace/mikktspace.c b/intern/mikktspace/mikktspace.c
index fe302eb5e7c..794590d30a4 100644
--- a/intern/mikktspace/mikktspace.c
+++ b/intern/mikktspace/mikktspace.c
@@ -1114,7 +1114,7 @@ static tbool GenerateTSpaces(STSpace psTspace[],
STSpace *pSubGroupTspace = NULL;
SSubGroup *pUniSubGroups = NULL;
int *pTmpMembers = NULL;
- int iMaxNrFaces = 0, iUniqueTspaces = 0, g = 0, i = 0;
+ int iMaxNrFaces = 0, g = 0, i = 0;
for (g = 0; g < iNrActiveGroups; g++)
if (iMaxNrFaces < pGroups[g].iNrFaces)
iMaxNrFaces = pGroups[g].iNrFaces;
@@ -1136,7 +1136,6 @@ static tbool GenerateTSpaces(STSpace psTspace[],
return TFALSE;
}
- iUniqueTspaces = 0;
for (g = 0; g < iNrActiveGroups; g++) {
const SGroup *pGroup = &pGroups[g];
int iUniqueSubGroups = 0, s = 0;
@@ -1211,9 +1210,7 @@ static tbool GenerateTSpaces(STSpace psTspace[],
++l;
}
- // assign tangent space index
assert(bFound || l == iUniqueSubGroups);
- // piTempTangIndices[f*3+index] = iUniqueTspaces+l;
// if no match was found we allocate a new subgroup
if (!bFound) {
@@ -1262,10 +1259,9 @@ static tbool GenerateTSpaces(STSpace psTspace[],
}
}
- // clean up and offset iUniqueTspaces
+ // clean up
for (s = 0; s < iUniqueSubGroups; s++)
free(pUniSubGroups[s].pTriMembers);
- iUniqueTspaces += iUniqueSubGroups;
}
// clean up
diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc
index 82bd4d9fc36..aaab8b4e6b9 100644
--- a/intern/opencolorio/fallback_impl.cc
+++ b/intern/opencolorio/fallback_impl.cc
@@ -445,6 +445,16 @@ const char *FallbackImpl::colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr * /*cs*/
return "";
}
+int FallbackImpl::colorSpaceGetNumAliases(OCIO_ConstColorSpaceRcPtr * /*cs*/)
+{
+ return 0;
+}
+const char *FallbackImpl::colorSpaceGetAlias(OCIO_ConstColorSpaceRcPtr * /*cs*/,
+ const int /*index*/)
+{
+ return "";
+}
+
OCIO_ConstProcessorRcPtr *FallbackImpl::createDisplayProcessor(OCIO_ConstConfigRcPtr * /*config*/,
const char * /*input*/,
const char * /*view*/,
diff --git a/intern/opencolorio/ocio_capi.cc b/intern/opencolorio/ocio_capi.cc
index 7e7710843e2..91784a288c8 100644
--- a/intern/opencolorio/ocio_capi.cc
+++ b/intern/opencolorio/ocio_capi.cc
@@ -234,6 +234,16 @@ const char *OCIO_colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *cs)
return impl->colorSpaceGetFamily(cs);
}
+int OCIO_colorSpaceGetNumAliases(OCIO_ConstColorSpaceRcPtr *cs)
+{
+ return impl->colorSpaceGetNumAliases(cs);
+}
+
+const char *OCIO_colorSpaceGetAlias(OCIO_ConstColorSpaceRcPtr *cs, const int index)
+{
+ return impl->colorSpaceGetAlias(cs, index);
+}
+
OCIO_ConstProcessorRcPtr *OCIO_createDisplayProcessor(OCIO_ConstConfigRcPtr *config,
const char *input,
const char *view,
diff --git a/intern/opencolorio/ocio_capi.h b/intern/opencolorio/ocio_capi.h
index 87a8043aec6..5c036ec263a 100644
--- a/intern/opencolorio/ocio_capi.h
+++ b/intern/opencolorio/ocio_capi.h
@@ -157,6 +157,8 @@ void OCIO_cpuProcessorRelease(OCIO_ConstCPUProcessorRcPtr *processor);
const char *OCIO_colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs);
const char *OCIO_colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs);
const char *OCIO_colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *cs);
+int OCIO_colorSpaceGetNumAliases(OCIO_ConstColorSpaceRcPtr *cs);
+const char *OCIO_colorSpaceGetAlias(OCIO_ConstColorSpaceRcPtr *cs, const int index);
OCIO_ConstProcessorRcPtr *OCIO_createDisplayProcessor(OCIO_ConstConfigRcPtr *config,
const char *input,
diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc
index a02a37522b9..ca1b7cc42e1 100644
--- a/intern/opencolorio/ocio_impl.cc
+++ b/intern/opencolorio/ocio_impl.cc
@@ -640,6 +640,15 @@ const char *OCIOImpl::colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *cs)
return (*(ConstColorSpaceRcPtr *)cs)->getFamily();
}
+int OCIOImpl::colorSpaceGetNumAliases(OCIO_ConstColorSpaceRcPtr *cs)
+{
+ return (*(ConstColorSpaceRcPtr *)cs)->getNumAliases();
+}
+const char *OCIOImpl::colorSpaceGetAlias(OCIO_ConstColorSpaceRcPtr *cs, const int index)
+{
+ return (*(ConstColorSpaceRcPtr *)cs)->getAlias(index);
+}
+
OCIO_ConstProcessorRcPtr *OCIOImpl::createDisplayProcessor(OCIO_ConstConfigRcPtr *config_,
const char *input,
const char *view,
diff --git a/intern/opencolorio/ocio_impl.h b/intern/opencolorio/ocio_impl.h
index 5be1d3aacf8..d42fa58121f 100644
--- a/intern/opencolorio/ocio_impl.h
+++ b/intern/opencolorio/ocio_impl.h
@@ -76,6 +76,8 @@ class IOCIOImpl {
virtual const char *colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs) = 0;
virtual const char *colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs) = 0;
virtual const char *colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *cs) = 0;
+ virtual int colorSpaceGetNumAliases(OCIO_ConstColorSpaceRcPtr *cs) = 0;
+ virtual const char *colorSpaceGetAlias(OCIO_ConstColorSpaceRcPtr *cs, const int index) = 0;
virtual OCIO_ConstProcessorRcPtr *createDisplayProcessor(OCIO_ConstConfigRcPtr *config,
const char *input,
@@ -190,6 +192,8 @@ class FallbackImpl : public IOCIOImpl {
const char *colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs);
const char *colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs);
const char *colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *cs);
+ int colorSpaceGetNumAliases(OCIO_ConstColorSpaceRcPtr *cs);
+ const char *colorSpaceGetAlias(OCIO_ConstColorSpaceRcPtr *cs, const int index);
OCIO_ConstProcessorRcPtr *createDisplayProcessor(OCIO_ConstConfigRcPtr *config,
const char *input,
@@ -277,6 +281,8 @@ class OCIOImpl : public IOCIOImpl {
const char *colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs);
const char *colorSpaceGetDescription(OCIO_ConstColorSpaceRcPtr *cs);
const char *colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr *cs);
+ int colorSpaceGetNumAliases(OCIO_ConstColorSpaceRcPtr *cs);
+ const char *colorSpaceGetAlias(OCIO_ConstColorSpaceRcPtr *cs, const int index);
OCIO_ConstProcessorRcPtr *createDisplayProcessor(OCIO_ConstConfigRcPtr *config,
const char *input,
diff --git a/intern/opencolorio/ocio_impl_glsl.cc b/intern/opencolorio/ocio_impl_glsl.cc
index e3d44ae9d55..fcaab5dd752 100644
--- a/intern/opencolorio/ocio_impl_glsl.cc
+++ b/intern/opencolorio/ocio_impl_glsl.cc
@@ -177,6 +177,7 @@ static bool createGPUShader(OCIO_GPUShader &shader,
ShaderCreateInfo info("OCIO_Display");
/* Work around OpenColorIO not supporting latest GLSL yet. */
+ info.define("texture1D", "texture");
info.define("texture2D", "texture");
info.define("texture3D", "texture");
info.typedef_source("ocio_shader_shared.hh");
@@ -192,6 +193,11 @@ static bool createGPUShader(OCIO_GPUShader &shader,
info.fragment_source("gpu_shader_display_transform_frag.glsl");
info.fragment_source_generated = source;
+ /* T96502: Work around for incorrect OCIO GLSL code generation when using
+ * GradingPrimaryTransform. Should be reevaluated when changing to a next version of OCIO.
+ * (currently v2.1.1). */
+ info.define("inf 1e32");
+
if (use_curve_mapping) {
info.define("USE_CURVE_MAPPING");
info.uniform_buf(UNIFORMBUF_SLOT_CURVEMAP, "OCIO_GPUCurveMappingParameters", "curve_mapping");
@@ -201,8 +207,11 @@ static bool createGPUShader(OCIO_GPUShader &shader,
/* Set LUT textures. */
int slot = TEXTURE_SLOT_LUTS_OFFSET;
for (OCIO_GPULutTexture &texture : textures.luts) {
- ImageType type = GPU_texture_dimensions(texture.texture) == 2 ? ImageType::FLOAT_2D :
- ImageType::FLOAT_3D;
+ const int dimensions = GPU_texture_dimensions(texture.texture);
+ ImageType type = (dimensions == 1) ? ImageType::FLOAT_1D :
+ (dimensions == 2) ? ImageType::FLOAT_2D :
+ ImageType::FLOAT_3D;
+
info.sampler(slot++, type, texture.sampler_name.c_str());
}
@@ -300,9 +309,9 @@ static bool addGPUUniform(OCIO_GPUTextures &textures,
return true;
}
-static bool addGPULut2D(OCIO_GPUTextures &textures,
- const GpuShaderDescRcPtr &shader_desc,
- int index)
+static bool addGPULut1D2D(OCIO_GPUTextures &textures,
+ const GpuShaderDescRcPtr &shader_desc,
+ int index)
{
const char *texture_name = nullptr;
const char *sampler_name = nullptr;
@@ -324,7 +333,15 @@ static bool addGPULut2D(OCIO_GPUTextures &textures,
GPU_R16F;
OCIO_GPULutTexture lut;
- lut.texture = GPU_texture_create_2d(texture_name, width, height, 1, format, values);
+ /* There does not appear to be an explicit way to check if a texture is 1D or 2D.
+ * It depends on more than height. So check instead by looking at the source. */
+ std::string sampler1D_name = std::string("sampler1D ") + sampler_name;
+ if (strstr(shader_desc->getShaderText(), sampler1D_name.c_str()) != nullptr) {
+ lut.texture = GPU_texture_create_1d(texture_name, width, 1, format, values);
+ }
+ else {
+ lut.texture = GPU_texture_create_2d(texture_name, width, height, 1, format, values);
+ }
if (lut.texture == nullptr) {
return false;
}
@@ -385,7 +402,7 @@ static bool createGPUTextures(OCIO_GPUTextures &textures,
}
}
for (int index = 0; index < shaderdesc_to_scene_linear->getNumTextures(); index++) {
- if (!addGPULut2D(textures, shaderdesc_to_scene_linear, index)) {
+ if (!addGPULut1D2D(textures, shaderdesc_to_scene_linear, index)) {
return false;
}
}
@@ -400,7 +417,7 @@ static bool createGPUTextures(OCIO_GPUTextures &textures,
}
}
for (int index = 0; index < shaderdesc_to_display->getNumTextures(); index++) {
- if (!addGPULut2D(textures, shaderdesc_to_display, index)) {
+ if (!addGPULut1D2D(textures, shaderdesc_to_display, index)) {
return false;
}
}
diff --git a/release/datafiles/blender_icons16/icon16_hair.dat b/release/datafiles/blender_icons16/icon16_curves.dat
index 6d550c12209..6d550c12209 100644
--- a/release/datafiles/blender_icons16/icon16_hair.dat
+++ b/release/datafiles/blender_icons16/icon16_curves.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_hair_data.dat b/release/datafiles/blender_icons16/icon16_curves_data.dat
index ef891ae3fc4..ef891ae3fc4 100644
--- a/release/datafiles/blender_icons16/icon16_hair_data.dat
+++ b/release/datafiles/blender_icons16/icon16_curves_data.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_force_boid.dat b/release/datafiles/blender_icons16/icon16_force_boid.dat
index 71f89bd7c04..f719054d84a 100644
--- a/release/datafiles/blender_icons16/icon16_force_boid.dat
+++ b/release/datafiles/blender_icons16/icon16_force_boid.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_outliner_data_hair.dat b/release/datafiles/blender_icons16/icon16_outliner_data_curves.dat
index ab0568bf81f..ab0568bf81f 100644
--- a/release/datafiles/blender_icons16/icon16_outliner_data_hair.dat
+++ b/release/datafiles/blender_icons16/icon16_outliner_data_curves.dat
Binary files differ
diff --git a/release/datafiles/blender_icons16/icon16_outliner_ob_hair.dat b/release/datafiles/blender_icons16/icon16_outliner_ob_curves.dat
index b110c789c04..b110c789c04 100644
--- a/release/datafiles/blender_icons16/icon16_outliner_ob_hair.dat
+++ b/release/datafiles/blender_icons16/icon16_outliner_ob_curves.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_hair.dat b/release/datafiles/blender_icons32/icon32_curves.dat
index de7507384cc..de7507384cc 100644
--- a/release/datafiles/blender_icons32/icon32_hair.dat
+++ b/release/datafiles/blender_icons32/icon32_curves.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_hair_data.dat b/release/datafiles/blender_icons32/icon32_curves_data.dat
index 5b03446438d..5b03446438d 100644
--- a/release/datafiles/blender_icons32/icon32_hair_data.dat
+++ b/release/datafiles/blender_icons32/icon32_curves_data.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_force_boid.dat b/release/datafiles/blender_icons32/icon32_force_boid.dat
index 7fc7cb5ee8c..9043989024b 100644
--- a/release/datafiles/blender_icons32/icon32_force_boid.dat
+++ b/release/datafiles/blender_icons32/icon32_force_boid.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_outliner_data_hair.dat b/release/datafiles/blender_icons32/icon32_outliner_data_curves.dat
index 7c8d909d24e..7c8d909d24e 100644
--- a/release/datafiles/blender_icons32/icon32_outliner_data_hair.dat
+++ b/release/datafiles/blender_icons32/icon32_outliner_data_curves.dat
Binary files differ
diff --git a/release/datafiles/blender_icons32/icon32_outliner_ob_hair.dat b/release/datafiles/blender_icons32/icon32_outliner_ob_curves.dat
index 0cadeea0af6..0cadeea0af6 100644
--- a/release/datafiles/blender_icons32/icon32_outliner_ob_hair.dat
+++ b/release/datafiles/blender_icons32/icon32_outliner_ob_curves.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.sculpt_add.dat b/release/datafiles/icons/ops.curves.sculpt_add.dat
new file mode 100644
index 00000000000..b66f4da5b71
--- /dev/null
+++ b/release/datafiles/icons/ops.curves.sculpt_add.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.sculpt_comb.dat b/release/datafiles/icons/ops.curves.sculpt_comb.dat
new file mode 100644
index 00000000000..d6dd75a35d7
--- /dev/null
+++ b/release/datafiles/icons/ops.curves.sculpt_comb.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.sculpt_cut.dat b/release/datafiles/icons/ops.curves.sculpt_cut.dat
new file mode 100644
index 00000000000..e7ef86e2fbc
--- /dev/null
+++ b/release/datafiles/icons/ops.curves.sculpt_cut.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.sculpt_delete.dat b/release/datafiles/icons/ops.curves.sculpt_delete.dat
new file mode 100644
index 00000000000..896d472e017
--- /dev/null
+++ b/release/datafiles/icons/ops.curves.sculpt_delete.dat
Binary files differ
diff --git a/release/datafiles/icons/ops.curves.sculpt_grow.dat b/release/datafiles/icons/ops.curves.sculpt_grow.dat
new file mode 100644
index 00000000000..9b3453085e4
--- /dev/null
+++ b/release/datafiles/icons/ops.curves.sculpt_grow.dat
Binary files differ
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject bb62f10715a871d7069d2b2c74b2efc97c3c350
+Subproject 67f1fbca1482d9d9362a4001332e785c3fd5d23
diff --git a/release/scripts/modules/rna_manual_reference.py b/release/scripts/modules/rna_manual_reference.py
index 4b10c29346e..1cd9cf9c649 100644
--- a/release/scripts/modules/rna_manual_reference.py
+++ b/release/scripts/modules/rna_manual_reference.py
@@ -344,7 +344,6 @@ url_manual_mapping = (
("bpy.types.sequencerpreviewoverlay.show_metadata*", "editors/video_sequencer/preview/display/overlays.html#bpy-types-sequencerpreviewoverlay-show-metadata"),
("bpy.types.sequencertimelineoverlay.show_fcurves*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-fcurves"),
("bpy.types.spaceclipeditor.use_grayscale_preview*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-use-grayscale-preview"),
- ("bpy.types.spaceoutliner.use_filter_lib_override*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-lib-override"),
("bpy.types.spaceoutliner.use_filter_object_empty*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-empty"),
("bpy.types.spaceoutliner.use_filter_object_light*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-light"),
("bpy.types.spacesequenceeditor.proxy_render_size*", "video_editing/preview/sidebar.html#bpy-types-spacesequenceeditor-proxy-render-size"),
diff --git a/release/scripts/presets/keyconfig/Blender.py b/release/scripts/presets/keyconfig/Blender.py
index 74e0ddfdf62..7ce9a5650bd 100644
--- a/release/scripts/presets/keyconfig/Blender.py
+++ b/release/scripts/presets/keyconfig/Blender.py
@@ -85,6 +85,28 @@ class Prefs(bpy.types.KeyConfigPreferences):
),
update=update_fn,
)
+
+ # Experimental: only show with developer extras, see: T96544.
+ use_tweak_select_passthrough: BoolProperty(
+ name="Tweak Select: Mouse Select & Move",
+ description=(
+ "The tweak tool is activated immediately instead of placing the cursor. "
+ "This is an experimental preference and may be removed"
+ ),
+ default=False,
+ update=update_fn,
+ )
+ # Experimental: only show with developer extras, see: T96544.
+ use_tweak_tool_lmb_interaction: BoolProperty(
+ name="Tweak Tool: Left Mouse Select & Move",
+ description=(
+ "The tweak tool is activated immediately instead of placing the cursor. "
+ "This is an experimental preference and may be removed"
+ ),
+ default=False,
+ update=update_fn,
+ )
+
use_alt_click_leader: BoolProperty(
name="Alt Click Tool Prompt",
description=(
@@ -236,6 +258,7 @@ class Prefs(bpy.types.KeyConfigPreferences):
prefs = context.preferences
+ show_developer_ui = prefs.view.show_developer_ui
is_select_left = (self.select_mouse == 'LEFT')
use_mouse_emulate_3_button = (
prefs.inputs.use_mouse_emulate_3_button and
@@ -270,6 +293,13 @@ class Prefs(bpy.types.KeyConfigPreferences):
row = sub.row()
row.prop(self, "use_select_all_toggle")
+ if show_developer_ui:
+ row = sub.row()
+ row.prop(self, "use_tweak_select_passthrough")
+ if show_developer_ui and (not is_select_left):
+ row = sub.row()
+ row.prop(self, "use_tweak_tool_lmb_interaction")
+
# 3DView settings.
col = layout.column()
col.label(text="3D View")
@@ -301,6 +331,7 @@ def load():
kc = context.window_manager.keyconfigs.new(IDNAME)
kc_prefs = kc.preferences
+ show_developer_ui = prefs.view.show_developer_ui
is_select_left = (kc_prefs.select_mouse == 'LEFT')
use_mouse_emulate_3_button = (
prefs.inputs.use_mouse_emulate_3_button and
@@ -322,6 +353,11 @@ def load():
use_gizmo_drag=(is_select_left and kc_prefs.gizmo_action == 'DRAG'),
use_fallback_tool=True,
use_fallback_tool_rmb=(False if is_select_left else kc_prefs.rmb_action == 'FALLBACK_TOOL'),
+ use_tweak_select_passthrough=(show_developer_ui and kc_prefs.use_tweak_select_passthrough),
+ use_tweak_tool_lmb_interaction=(
+ False if is_select_left else
+ (show_developer_ui and kc_prefs.use_tweak_tool_lmb_interaction)
+ ),
use_alt_tool_or_cursor=(
(not use_mouse_emulate_3_button) and
(kc_prefs.use_alt_tool if is_select_left else kc_prefs.use_alt_cursor)
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 80794d9f23d..d307c3d0f0a 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -31,6 +31,8 @@ class Params:
"context_menu_event",
"cursor_set_event",
"cursor_tweak_event",
+ "use_tweak_select_passthrough",
+ "use_tweak_tool_lmb_interaction",
"use_mouse_emulate_3_button",
# User preferences:
@@ -102,6 +104,8 @@ class Params:
use_gizmo_drag=True,
use_fallback_tool=False,
use_fallback_tool_rmb=False,
+ use_tweak_select_passthrough=False,
+ use_tweak_tool_lmb_interaction=False,
use_v3d_tab_menu=False,
use_v3d_shade_ex_pie=False,
use_v3d_mmb_pan=False,
@@ -129,6 +133,7 @@ class Params:
self.tool_maybe_tweak_value = 'PRESS'
else:
self.tool_maybe_tweak_value = 'CLICK_DRAG'
+ self.use_tweak_tool_lmb_interaction = use_tweak_tool_lmb_interaction
self.context_menu_event = {"type": 'W', "value": 'PRESS'}
@@ -150,6 +155,7 @@ class Params:
self.action_mouse = 'RIGHTMOUSE'
self.tool_mouse = 'LEFTMOUSE'
self.tool_maybe_tweak_value = 'CLICK_DRAG'
+ self.use_tweak_tool_lmb_interaction = False
if self.legacy:
self.context_menu_event = {"type": 'W', "value": 'PRESS'}
@@ -185,6 +191,8 @@ class Params:
self.use_file_single_click = use_file_single_click
+ self.use_tweak_select_passthrough = use_tweak_select_passthrough
+
self.use_fallback_tool = use_fallback_tool
self.use_fallback_tool_rmb = use_fallback_tool_rmb
@@ -442,7 +450,7 @@ def _template_items_change_frame(params):
# Tool System Templates
-def _template_items_tool_select(params, operator, cursor_operator, fallback, *, extend):
+def _template_items_tool_select(params, operator, cursor_operator, fallback):
if params.select_mouse == 'LEFTMOUSE':
# By default use 'PRESS' for immediate select without quick delay.
# Fallback key-maps 'CLICK' since 'PRESS' events passes through (allowing either click or drag).
@@ -454,9 +462,22 @@ def _template_items_tool_select(params, operator, cursor_operator, fallback, *,
(operator, {"type": 'LEFTMOUSE', "value": 'CLICK' if fallback else 'PRESS'},
{"properties": [("deselect_all", True)]}),
(operator, {"type": 'LEFTMOUSE', "value": 'CLICK' if fallback else 'PRESS', "shift": True},
- {"properties": [(extend, True)]}),
+ {"properties": [("toggle", True)]}),
]
else:
+ # Experimental support for LMB interaction for the tweak tool.
+ if params.use_tweak_tool_lmb_interaction and not fallback:
+ return [
+ (operator, {"type": 'LEFTMOUSE', "value": 'PRESS'},
+ {"properties": [("deselect_all", True), ("select_passthrough", True)]}),
+ (operator, {"type": 'LEFTMOUSE', "value": 'CLICK'},
+ {"properties": [("deselect_all", True)]}),
+ (operator, {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
+ {"properties": [("deselect_all", False), ("toggle", True)]}),
+ ("transform.translate", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'},
+ {"properties": [("release_confirm", True)]}),
+ ]
+
# For right mouse, set the cursor.
return [
(cursor_operator, {"type": 'LEFTMOUSE', "value": 'PRESS'}, None),
@@ -1168,7 +1189,12 @@ def km_uv_editor(params):
items.extend([
# Selection modes.
*_template_items_uv_select_mode(params),
- *_template_uv_select(type=params.select_mouse, value=params.select_mouse_value_fallback, legacy=params.legacy),
+ *_template_uv_select(
+ type=params.select_mouse,
+ value=params.select_mouse_value_fallback,
+ select_passthrough=params.use_tweak_select_passthrough,
+ legacy=params.legacy,
+ ),
("uv.mark_seam", {"type": 'E', "value": 'PRESS', "ctrl": True}, None),
("uv.select_loop",
{"type": params.select_mouse, "value": params.select_mouse_value, "alt": True}, None),
@@ -1496,6 +1522,7 @@ def km_view3d(params):
type=params.select_mouse,
value=params.select_mouse_value_fallback,
legacy=params.legacy,
+ select_passthrough=params.use_tweak_select_passthrough,
),
op_tool_optional(
("view3d.select_box", {"type": 'B', "value": 'PRESS'}, None),
@@ -4660,7 +4687,7 @@ def _template_paint_radial_control(paint, rotation=False, secondary_rotation=Fal
return items
-def _template_view3d_select(*, type, value, legacy, exclude_mod=None):
+def _template_view3d_select(*, type, value, legacy, select_passthrough, exclude_mod=None):
# NOTE: `exclude_mod` is needed since we don't want this tool to exclude Control-RMB actions when this is used
# as a tool key-map with RMB-select and `use_fallback_tool_rmb` is enabled. See T92467.
return [(
@@ -4668,7 +4695,8 @@ def _template_view3d_select(*, type, value, legacy, exclude_mod=None):
{"type": type, "value": value, **{m: True for m in mods}},
{"properties": [(c, True) for c in props]},
) for props, mods in (
- (("deselect_all",) if not legacy else (), ()),
+ ((("deselect_all", "select_passthrough") if select_passthrough else
+ ("deselect_all",)) if not legacy else (), ()),
(("toggle",), ("shift",)),
(("center", "object"), ("ctrl",)),
(("enumerate",), ("alt",)),
@@ -4694,12 +4722,15 @@ def _template_view3d_gpencil_select(*, type, value, legacy, use_select_mouse=Tru
]
-def _template_uv_select(*, type, value, legacy):
+def _template_uv_select(*, type, value, select_passthrough, legacy):
return [
("uv.select", {"type": type, "value": value},
- {"properties": [("deselect_all", not legacy)]}),
+ {"properties": [
+ *((("deselect_all", True),) if not legacy else ()),
+ *((("select_passthrough", True),) if select_passthrough else ()),
+ ]}),
("uv.select", {"type": type, "value": value, "shift": True},
- {"properties": [("extend", True)]}),
+ {"properties": [("toggle", True)]}),
]
@@ -6289,9 +6320,13 @@ def km_image_editor_tool_uv_select(params, *, fallback):
{"space_type": 'IMAGE_EDITOR', "region_type": 'WINDOW'},
{"items": [
*([] if (fallback and (params.select_mouse == 'RIGHTMOUSE')) else _template_items_tool_select(
- params, "uv.select", "uv.cursor_set", fallback, extend="extend")),
+ params, "uv.select", "uv.cursor_set", fallback)),
*([] if (not params.use_fallback_tool_rmb) else _template_uv_select(
- type=params.select_mouse, value=params.select_mouse_value, legacy=params.legacy)),
+ type=params.select_mouse,
+ value=params.select_mouse_value,
+ select_passthrough=params.use_tweak_select_passthrough,
+ legacy=params.legacy,
+ )),
]},
)
@@ -6496,9 +6531,14 @@ def km_3d_view_tool_select(params, *, fallback):
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
*([] if (fallback and (params.select_mouse == 'RIGHTMOUSE')) else _template_items_tool_select(
- params, "view3d.select", "view3d.cursor3d", fallback, extend="toggle")),
+ params, "view3d.select", "view3d.cursor3d", fallback)),
*([] if (not params.use_fallback_tool_rmb) else _template_view3d_select(
- type=params.select_mouse, value=params.select_mouse_value, legacy=params.legacy, exclude_mod="ctrl")),
+ type=params.select_mouse,
+ value=params.select_mouse_value,
+ legacy=params.legacy,
+ select_passthrough=params.use_tweak_select_passthrough,
+ exclude_mod="ctrl",
+ )),
]},
)
@@ -7408,7 +7448,7 @@ def km_3d_view_tool_edit_gpencil_select(params, *, fallback):
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
*([] if (fallback and (params.select_mouse == 'RIGHTMOUSE')) else _template_items_tool_select(
- params, "gpencil.select", "view3d.cursor3d", fallback, extend="toggle")),
+ params, "gpencil.select", "view3d.cursor3d", fallback)),
*([] if (not params.use_fallback_tool_rmb) else _template_view3d_gpencil_select(
type=params.select_mouse, value=params.select_mouse_value, legacy=params.legacy)),
]},
@@ -7546,7 +7586,7 @@ def km_3d_view_tool_sculpt_gpencil_select(params):
return (
"3D View Tool: Sculpt Gpencil, Tweak",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
- {"items": _template_items_tool_select(params, "gpencil.select", "view3d.cursor3d", False, extend="toggle")},
+ {"items": _template_items_tool_select(params, "gpencil.select", "view3d.cursor3d", False)},
)
@@ -7586,7 +7626,7 @@ def km_sequencer_editor_tool_generic_select(params, *, fallback):
{"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
{"items": [
*([] if (fallback and (params.select_mouse == 'RIGHTMOUSE')) else _template_items_tool_select(
- params, "sequencer.select", "sequencer.cursor_set", fallback, extend="toggle")),
+ params, "sequencer.select", "sequencer.cursor_set", fallback)),
*([] if (not params.use_fallback_tool_rmb) else _template_sequencer_preview_select(
type=params.select_mouse, value=params.select_mouse_value, legacy=params.legacy)),
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 55ee91af7cd..6661031552e 100644
--- a/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
+++ b/release/scripts/presets/keyconfig/keymap_data/industry_compatible_data.py
@@ -564,9 +564,9 @@ def km_uv_editor(params):
{"properties": [("type", 'ISLAND')]}),
("uv.select", {"type": 'LEFTMOUSE', "value": 'CLICK'},
- {"properties": [("extend", False), ("deselect_all", True)]}),
+ {"properties": [("deselect_all", True)]}),
("uv.select", {"type": 'LEFTMOUSE', "value": 'CLICK', "shift": True},
- {"properties": [("extend", True), ("deselect_all", False)]}),
+ {"properties": [("toggle", True), ("deselect_all", False)]}),
("transform.translate", {"type": 'LEFTMOUSE', "value": 'CLICK_DRAG'}, None),
("uv.select_loop", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK', "shift": True},
diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index a7f401afad1..d6e5604fde0 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -2996,7 +2996,7 @@ class WM_MT_splash_quick_setup(Menu):
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_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index c1d6dcfd3f4..947a7e5c7a7 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -677,7 +677,7 @@ class GreasePencilSimplifyPanel:
rd = context.scene.render
- layout.active = rd.simplify_gpencil
+ layout.active = rd.use_simplify and rd.simplify_gpencil
col = layout.column()
col.prop(rd, "simplify_gpencil_onplay")
diff --git a/release/scripts/startup/bl_ui/properties_object.py b/release/scripts/startup/bl_ui/properties_object.py
index 5721e20f328..89f840306e1 100644
--- a/release/scripts/startup/bl_ui/properties_object.py
+++ b/release/scripts/startup/bl_ui/properties_object.py
@@ -193,7 +193,7 @@ class OBJECT_PT_display(ObjectButtonsPanel, Panel):
obj = context.object
obj_type = obj.type
- is_geometry = (obj_type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT', 'VOLUME', 'HAIR', 'POINTCLOUD'})
+ is_geometry = (obj_type in {'MESH', 'CURVE', 'SURFACE', 'META', 'FONT', 'VOLUME', 'CURVES', 'POINTCLOUD'})
has_bounds = (is_geometry or obj_type in {'LATTICE', 'ARMATURE'})
is_wire = (obj_type in {'CAMERA', 'EMPTY'})
is_empty_image = (obj_type == 'EMPTY' and obj.empty_display_type == 'IMAGE')
diff --git a/release/scripts/startup/bl_ui/properties_output.py b/release/scripts/startup/bl_ui/properties_output.py
index 34e86184097..312a580bf7d 100644
--- a/release/scripts/startup/bl_ui/properties_output.py
+++ b/release/scripts/startup/bl_ui/properties_output.py
@@ -296,6 +296,41 @@ class RENDER_PT_output_views(RenderOutputButtonsPanel, Panel):
layout.template_image_views(rd.image_settings)
+class RENDER_PT_output_color_management(RenderOutputButtonsPanel, Panel):
+ bl_label = "Color Management"
+ bl_options = {'DEFAULT_CLOSED'}
+ bl_parent_id = "RENDER_PT_output"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
+
+ def draw(self, context):
+ scene = context.scene
+ image_settings = scene.render.image_settings
+
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = False # No animation.
+
+ layout.row().prop(image_settings, "color_management", text=" ", expand=True)
+
+ flow = layout.grid_flow(row_major=True, columns=0, even_columns=False, even_rows=False, align=True)
+
+ if image_settings.color_management == 'OVERRIDE':
+ owner = image_settings
+ else:
+ owner = scene
+ flow.enabled = False
+
+ col = flow.column()
+
+ if image_settings.has_linear_colorspace:
+ if hasattr(owner, 'linear_colorspace_settings'):
+ col.prop(owner.linear_colorspace_settings, "name", text="Color Space")
+ else:
+ col.prop(owner.display_settings, "display_device")
+ col.separator()
+ col.template_colormanaged_view_settings(owner, "view_settings")
+
+
class RENDER_PT_encoding(RenderOutputButtonsPanel, Panel):
bl_label = "Encoding"
bl_parent_id = "RENDER_PT_output"
@@ -484,6 +519,7 @@ classes = (
RENDER_PT_stereoscopy,
RENDER_PT_output,
RENDER_PT_output_views,
+ RENDER_PT_output_color_management,
RENDER_PT_encoding,
RENDER_PT_encoding_video,
RENDER_PT_encoding_audio,
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index 6f9ef12c3b7..706e228c5d9 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -331,7 +331,8 @@ class GRAPH_MT_slider(Menu):
layout = self.layout
layout.operator("graph.breakdown", text="Breakdown")
- layout.operator("graph.blend_to_neighbor", text="Blend To Neighbor")
+ layout.operator("graph.blend_to_neighbor", text="Blend to Neighbor")
+ layout.operator("graph.blend_to_default", text="Blend to Default Value")
class GRAPH_MT_view_pie(Menu):
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index 7c88006a4d6..d7d905cb820 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -61,7 +61,7 @@ class NODE_HT_header(Header):
layout.separator_spacer()
types_that_support_material = {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META',
- 'GPENCIL', 'VOLUME', 'HAIR', 'POINTCLOUD'}
+ 'GPENCIL', 'VOLUME', 'CURVES', 'POINTCLOUD'}
# disable material slot buttons when pinned, cannot find correct slot within id_from (T36589)
# disable also when the selected object does not support materials
has_material_slots = not snode.pin and ob_type in types_that_support_material
diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py
index 9d3f20ce4a4..bbe165b9286 100644
--- a/release/scripts/startup/bl_ui/space_outliner.py
+++ b/release/scripts/startup/bl_ui/space_outliner.py
@@ -442,15 +442,6 @@ class OUTLINER_PT_filter(Panel):
row.label(icon='BLANK1')
row.prop(space, "use_filter_object_others", text="Others")
- if bpy.data.libraries:
- col.separator()
- row = col.row()
- row.label(icon='LIBRARY_DATA_OVERRIDE')
- row.prop(space, "use_filter_lib_override", text="Library Overrides")
- row = col.row()
- row.label(icon='LIBRARY_DATA_OVERRIDE')
- row.prop(space, "use_filter_lib_override_system", text="System Overrides")
-
classes = (
OUTLINER_HT_header,
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 09716c77917..f9642a2dbb6 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -386,8 +386,8 @@ class USERPREF_PT_edit_objects_duplicate_data(EditingPanel, CenterAlignMixIn, Pa
col.prop(edit, "use_duplicate_curve", text="Curve")
# col.prop(edit, "use_duplicate_fcurve", text="F-Curve") # Not implemented.
col.prop(edit, "use_duplicate_grease_pencil", text="Grease Pencil")
- if hasattr(edit, "use_duplicate_hair"):
- col.prop(edit, "use_duplicate_hair", text="Hair")
+ if hasattr(edit, "use_duplicate_curves"):
+ col.prop(edit, "use_duplicate_curves", text="Curves")
col = flow.column()
col.prop(edit, "use_duplicate_lattice", text="Lattice")
@@ -461,6 +461,7 @@ class USERPREF_PT_edit_weight_paint(EditingPanel, CenterAlignMixIn, Panel):
col.active = view.use_weight_color_range
col.template_color_ramp(view, "weight_color_range", expand=True)
+
class USERPREF_PT_edit_text_editor(EditingPanel, CenterAlignMixIn, Panel):
bl_label = "Text Editor"
bl_options = {'DEFAULT_CLOSED'}
@@ -685,10 +686,10 @@ class USERPREF_PT_viewport_display(ViewportPanel, CenterAlignMixIn, Panel):
prefs = context.preferences
view = prefs.view
- col = layout.column(heading="Show")
+ col = layout.column(heading="Text Info Overlay")
col.prop(view, "show_object_info", text="Object Info")
col.prop(view, "show_view_name", text="View Name")
- col.prop(view, "show_playback_fps", text="Playback FPS")
+ col.prop(view, "show_playback_fps", text="Playback Frame Rate (FPS)")
layout.separator()
@@ -2260,6 +2261,7 @@ class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
context, (
({"property": "use_sculpt_vertex_colors"}, "T71947"),
({"property": "use_sculpt_tools_tilt"}, "T82877"),
+ ({"property": "use_select_nearest_on_first_click"}, "T96752"),
({"property": "use_extended_asset_browser"}, ("project/view/130/", "Project Page")),
({"property": "use_override_templates"}, ("T73318", "Milestone 4")),
({"property": "use_named_attribute_nodes"}, ("T91742")),
@@ -2276,6 +2278,7 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
({"property": "use_new_curves_type"}, "T68981"),
({"property": "use_new_point_cloud_type"}, "T75717"),
({"property": "use_full_frame_compositor"}, "T88150"),
+ ({"property": "enable_eevee_next"}, "T93220"),
),
)
@@ -2295,7 +2298,6 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel):
({"property": "use_undo_legacy"}, "T60695"),
({"property": "override_auto_resync"}, "T83811"),
({"property": "use_cycles_debug"}, None),
- ({"property": "use_geometry_nodes_legacy"}, "T91274"),
({"property": "show_asset_debug_info"}, None),
({"property": "use_asset_indexing"}, None),
),
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 7c4ba575f00..f40d96e30a0 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -492,18 +492,30 @@ class _draw_tool_settings_context_mode:
header=True
)
- UnifiedPaintPanel.prop_unified(
- layout,
- context,
- brush,
- "strength",
- unified_name="use_unified_strength",
- header=True
- )
+ if brush.curves_sculpt_tool not in {'ADD', 'DELETE'}:
+ UnifiedPaintPanel.prop_unified(
+ layout,
+ context,
+ brush,
+ "strength",
+ unified_name="use_unified_strength",
+ header=True
+ )
- if brush.curves_sculpt_tool == "TEST3":
- layout.prop(tool_settings.curves_sculpt, "distance")
+ if brush.curves_sculpt_tool == 'COMB':
+ layout.prop(brush, "falloff_shape", expand=True)
+ layout.prop(brush, "curve_preset")
+ if brush.curves_sculpt_tool == 'ADD':
+ layout.prop(brush, "use_frontface")
+ layout.prop(brush, "falloff_shape", expand=True)
+ layout.prop(brush.curves_sculpt_settings, "add_amount")
+ layout.prop(tool_settings.curves_sculpt, "curve_length")
+ layout.prop(tool_settings.curves_sculpt, "interpolate_length")
+ layout.prop(tool_settings.curves_sculpt, "interpolate_shape")
+
+ if brush.curves_sculpt_tool == 'TEST1':
+ layout.prop(tool_settings.curves_sculpt, "distance")
class VIEW3D_HT_header(Header):
@@ -5285,6 +5297,8 @@ class VIEW3D_MT_pivot_pie(Menu):
pie.prop_enum(context.scene.tool_settings, "transform_pivot_point", value='ACTIVE_ELEMENT')
if (obj is None) or (mode in {'OBJECT', 'POSE', 'WEIGHT_PAINT'}):
pie.prop(context.scene.tool_settings, "use_transform_pivot_point_align")
+ if mode in {'EDIT_GPENCIL'}:
+ pie.prop(context.scene.tool_settings.gpencil_sculpt, "use_scale_thickness")
class VIEW3D_MT_orientations_pie(Menu):
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index f9d3c988a22..df07fbb3198 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -675,7 +675,7 @@ class VIEW3D_PT_tools_brush_stroke_smooth_stroke(Panel, View3DPaintPanel, Smooth
class VIEW3D_PT_tools_weight_gradient(Panel, View3DPaintPanel):
# 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_context = ".weightpaint" # dot on purpose (access from topbar)
bl_label = "Falloff"
bl_options = {'DEFAULT_CLOSED'}
# also dont draw as an extra panel in the sidebar (already included in the Brush settings)
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 705b98c4d11..e7c00f4915e 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -71,18 +71,6 @@ def curve_node_items(context):
space = context.space_data
if not space:
return
-
- if geometry_nodes_legacy_poll(context):
- yield NodeItem("GeometryNodeLegacyCurveEndpoints")
- yield NodeItem("GeometryNodeLegacyCurveReverse")
- yield NodeItem("GeometryNodeLegacyCurveSubdivide")
- yield NodeItem("GeometryNodeLegacyCurveToPoints")
- yield NodeItem("GeometryNodeLegacyMeshToCurve")
- yield NodeItem("GeometryNodeLegacyCurveSelectHandles")
- yield NodeItem("GeometryNodeLegacyCurveSetHandles")
- yield NodeItem("GeometryNodeLegacyCurveSplineType")
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
-
yield NodeItem("GeometryNodeCurveLength")
yield NodeItem("GeometryNodeCurveToMesh")
yield NodeItem("GeometryNodeCurveToPoints")
@@ -119,12 +107,6 @@ def mesh_node_items(context):
space = context.space_data
if not space:
return
-
- if geometry_nodes_legacy_poll(context):
- yield NodeItem("GeometryNodeLegacyEdgeSplit", poll=geometry_nodes_legacy_poll)
- yield NodeItem("GeometryNodeLegacySubdivisionSurface", poll=geometry_nodes_legacy_poll)
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
-
yield NodeItem("GeometryNodeDualMesh")
yield NodeItem("GeometryNodeExtrudeMesh")
yield NodeItem("GeometryNodeFlipFaces")
@@ -156,12 +138,6 @@ def geometry_node_items(context):
space = context.space_data
if not space:
return
-
- if geometry_nodes_legacy_poll(context):
- yield NodeItem("GeometryNodeLegacyDeleteGeometry", poll=geometry_nodes_legacy_poll)
- yield NodeItem("GeometryNodeLegacyRaycast", poll=geometry_nodes_legacy_poll)
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
-
yield NodeItem("GeometryNodeBoundBox")
yield NodeItem("GeometryNodeConvexHull")
yield NodeItem("GeometryNodeDeleteGeometry")
@@ -185,11 +161,6 @@ def geometry_input_node_items(context):
space = context.space_data
if not space:
return
-
- if geometry_nodes_legacy_poll(context):
- yield NodeItem("FunctionNodeLegacyRandomFloat")
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
-
yield NodeItem("FunctionNodeInputBool")
yield NodeItem("GeometryNodeCollectionInfo")
yield NodeItem("FunctionNodeInputColor")
@@ -217,12 +188,6 @@ def geometry_material_node_items(context):
space = context.space_data
if not space:
return
-
- if geometry_nodes_legacy_poll(context):
- yield NodeItem("GeometryNodeLegacyMaterialAssign")
- yield NodeItem("GeometryNodeLegacySelectByMaterial")
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
-
yield NodeItem("GeometryNodeReplaceMaterial")
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
yield NodeItem("GeometryNodeInputMaterialIndex")
@@ -238,17 +203,6 @@ def point_node_items(context):
space = context.space_data
if not space:
return
-
- if geometry_nodes_legacy_poll(context):
- yield NodeItem("GeometryNodeLegacyAlignRotationToVector", poll=geometry_nodes_legacy_poll)
- yield NodeItem("GeometryNodeLegacyPointDistribute", poll=geometry_nodes_legacy_poll)
- yield NodeItem("GeometryNodeLegacyPointInstance", poll=geometry_nodes_legacy_poll)
- yield NodeItem("GeometryNodeLegacyPointScale", poll=geometry_nodes_legacy_poll)
- yield NodeItem("GeometryNodeLegacyPointSeparate", poll=geometry_nodes_legacy_poll)
- yield NodeItem("GeometryNodeLegacyPointTranslate", poll=geometry_nodes_legacy_poll)
- yield NodeItem("GeometryNodeLegacyRotatePoints", poll=geometry_nodes_legacy_poll)
- yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
-
yield NodeItem("GeometryNodeDistributePointsOnFaces")
yield NodeItem("GeometryNodePointsToVertices")
yield NodeItem("GeometryNodePointsToVolume")
@@ -356,10 +310,6 @@ def object_eevee_cycles_shader_nodes_poll(context):
eevee_cycles_shader_nodes_poll(context))
-def geometry_nodes_legacy_poll(context):
- return context.preferences.experimental.use_geometry_nodes_legacy
-
-
def named_attribute_poll(context):
return context.preferences.experimental.use_named_attribute_nodes
@@ -666,25 +616,6 @@ texture_node_categories = [
geometry_node_categories = [
# Geometry Nodes
GeometryNodeCategory("GEO_ATTRIBUTE", "Attribute", items=[
- NodeItem("GeometryNodeLegacyAttributeRandomize", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeMath", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeClamp", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeCompare", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeConvert", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeCurveMap", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeFill", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeMix", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeProximity", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeColorRamp", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeVectorMath", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeVectorRotate", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeSampleTexture", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeCombineXYZ", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeSeparateXYZ", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeMapRange", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyAttributeTransfer", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeAttributeRemove", poll=geometry_nodes_legacy_poll),
-
NodeItem("GeometryNodeCaptureAttribute"),
NodeItem("GeometryNodeAttributeDomainSize"),
NodeItem("GeometryNodeAttributeStatistic"),
@@ -780,9 +711,6 @@ geometry_node_categories = [
NodeItem("ShaderNodeVectorRotate"),
]),
GeometryNodeCategory("GEO_VOLUME", "Volume", items=[
- NodeItem("GeometryNodeLegacyPointsToVolume", poll=geometry_nodes_legacy_poll),
- NodeItem("GeometryNodeLegacyVolumeToMesh", poll=geometry_nodes_legacy_poll),
-
NodeItem("GeometryNodeVolumeToMesh"),
]),
GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items),
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index dee163a9797..deff45d0350 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -19,6 +19,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_constraint_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curve_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curveprofile_types.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curves_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_customdata_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_defs.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_documentation.h
@@ -31,7 +32,6 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpu_types.h
- ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_curves_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_image_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_ipo_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_key_types.h
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 3817fe59f95..058b0f120f7 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -44,7 +44,7 @@ int BLF_load_mem_unique(const char *name, const unsigned char *mem, int mem_size
void BLF_unload(const char *name) ATTR_NONNULL();
void BLF_unload_id(int fontid);
-char *BLF_display_name_from_file(const char *filename);
+char *BLF_display_name_from_file(const char *filepath);
/**
* Check if font supports a particular glyph.
@@ -279,7 +279,7 @@ void BLF_dir_free(char **dirs, int count) ATTR_NONNULL();
*
* \note called from a thread, so it bypasses the normal BLF_* api (which isn't thread-safe).
*/
-void BLF_thumb_preview(const char *filename,
+void BLF_thumb_preview(const char *filepath,
const char **draw_str,
const char **i18n_draw_str,
unsigned char draw_str_lines,
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 043d6da7d73..2b5a2cdf606 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -129,7 +129,7 @@ bool BLF_has_glyph(int fontid, unsigned int unicode)
{
FontBLF *font = blf_get(fontid);
if (font) {
- return FT_Get_Char_Index(font->face, unicode) != 0;
+ return FT_Get_Char_Index(font->face, unicode) != FT_Err_Ok;
}
return false;
}
@@ -158,14 +158,14 @@ int BLF_load_unique(const char *name)
return -1;
}
- char *filename = blf_dir_search(name);
- if (!filename) {
+ char *filepath = blf_dir_search(name);
+ if (!filepath) {
printf("Can't find font: %s\n", name);
return -1;
}
- FontBLF *font = blf_font_new(name, filename);
- MEM_freeN(filename);
+ FontBLF *font = blf_font_new(name, filepath);
+ MEM_freeN(filepath);
if (!font) {
printf("Can't load font: %s\n", name);
@@ -869,9 +869,9 @@ void BLF_draw_buffer(int fontid, const char *str, const size_t str_len)
BLF_draw_buffer_ex(fontid, str, str_len, NULL);
}
-char *BLF_display_name_from_file(const char *filename)
+char *BLF_display_name_from_file(const char *filepath)
{
- FontBLF *font = blf_font_new("font_name", filename);
+ FontBLF *font = blf_font_new("font_name", filepath);
if (!font) {
return NULL;
}
diff --git a/source/blender/blenfont/intern/blf_dir.c b/source/blender/blenfont/intern/blf_dir.c
index 69b44ed9b01..8534a8c583f 100644
--- a/source/blender/blenfont/intern/blf_dir.c
+++ b/source/blender/blenfont/intern/blf_dir.c
@@ -132,12 +132,12 @@ char *blf_dir_search(const char *file)
return s;
}
-char *blf_dir_metrics_search(const char *filename)
+char *blf_dir_metrics_search(const char *filepath)
{
char *mfile;
char *s;
- mfile = BLI_strdup(filename);
+ mfile = BLI_strdup(filepath);
s = strrchr(mfile, '.');
if (s) {
if (BLI_strnlen(s, 4) < 4) {
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index c4bd22d1310..60ff5f6470f 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -1213,14 +1213,14 @@ static void blf_font_fill(FontBLF *font)
font->glyph_cache_mutex = &blf_glyph_cache_mutex;
}
-FontBLF *blf_font_new(const char *name, const char *filename)
+FontBLF *blf_font_new(const char *name, const char *filepath)
{
FontBLF *font;
FT_Error err;
char *mfile;
font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new");
- err = FT_New_Face(ft_lib, filename, 0, &font->face);
+ err = FT_New_Face(ft_lib, filepath, 0, &font->face);
if (err) {
if (ELEM(err, FT_Err_Unknown_File_Format, FT_Err_Unimplemented_Feature)) {
printf("Format of this font file is not supported\n");
@@ -1246,17 +1246,17 @@ FontBLF *blf_font_new(const char *name, const char *filename)
return NULL;
}
- mfile = blf_dir_metrics_search(filename);
+ mfile = blf_dir_metrics_search(filepath);
if (mfile) {
err = FT_Attach_File(font->face, mfile);
if (err) {
- fprintf(stderr, "FT_Attach_File failed to load '%s' with error %d\n", filename, (int)err);
+ fprintf(stderr, "FT_Attach_File failed to load '%s' with error %d\n", filepath, (int)err);
}
MEM_freeN(mfile);
}
font->name = BLI_strdup(name);
- font->filename = BLI_strdup(filename);
+ font->filepath = BLI_strdup(filepath);
blf_font_fill(font);
if (FT_HAS_KERNING(font->face)) {
@@ -1303,7 +1303,7 @@ FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int m
}
font->name = BLI_strdup(name);
- font->filename = NULL;
+ font->filepath = NULL;
blf_font_fill(font);
return font;
}
@@ -1317,8 +1317,8 @@ void blf_font_free(FontBLF *font)
}
FT_Done_Face(font->face);
- if (font->filename) {
- MEM_freeN(font->filename);
+ if (font->filepath) {
+ MEM_freeN(font->filepath);
}
if (font->name) {
MEM_freeN(font->name);
@@ -1340,7 +1340,7 @@ bool blf_font_size(FontBLF *font, float size, unsigned int dpi)
size = (float)ft_size / 64.0f;
if (font->size != size || font->dpi != dpi) {
- if (FT_Set_Char_Size(font->face, 0, ft_size, dpi, dpi) == 0) {
+ if (FT_Set_Char_Size(font->face, 0, ft_size, dpi, dpi) == FT_Err_Ok) {
font->size = size;
font->dpi = dpi;
}
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 4810e46b1d2..28531c5afc1 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -258,7 +258,7 @@ static FT_GlyphSlot blf_glyph_load(FontBLF *font, FT_UInt glyph_index)
}
}
- if (FT_Load_Glyph(font->face, glyph_index, load_flags) == 0) {
+ if (FT_Load_Glyph(font->face, glyph_index, load_flags) == FT_Err_Ok) {
return font->face->glyph;
}
return NULL;
@@ -280,7 +280,7 @@ static bool blf_glyph_render_bitmap(FontBLF *font, FT_GlyphSlot glyph)
/* Render the glyph curves to a bitmap. */
FT_Error err = FT_Render_Glyph(glyph, render_mode);
- if (err != 0) {
+ if (err != FT_Err_Ok) {
return false;
}
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 14e1a8f72d1..81a1460df4d 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -25,7 +25,7 @@ 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);
+char *blf_dir_metrics_search(const char *filepath);
/* int blf_dir_split(const char *str, char *file, int *size); */ /* UNUSED */
int blf_font_init(void);
@@ -36,7 +36,7 @@ bool blf_font_id_is_valid(int fontid);
void blf_draw_buffer__start(struct FontBLF *font);
void blf_draw_buffer__end(void);
-struct FontBLF *blf_font_new(const char *name, const char *filename);
+struct FontBLF *blf_font_new(const char *name, const char *filepath);
struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size);
void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, int mem_size);
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index 61b6edc4974..23dc2fda38c 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -147,8 +147,8 @@ typedef struct FontBLF {
/* # of times this font was loaded */
unsigned int reference_count;
- /* filename or NULL. */
- char *filename;
+ /** File-path or NULL. */
+ char *filepath;
/* aspect ratio or scale. */
float aspect[3];
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index 9d9a8a51d0f..0e265fb7553 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -29,7 +29,7 @@
#include "BLI_strict_flags.h"
-void BLF_thumb_preview(const char *filename,
+void BLF_thumb_preview(const char *filepath,
const char **draw_str,
const char **i18n_draw_str,
const unsigned char draw_str_lines,
@@ -49,9 +49,9 @@ void BLF_thumb_preview(const char *filename,
FontBLF *font;
/* Create a new blender font obj and fill it with default values */
- font = blf_font_new("thumb_font", filename);
+ font = blf_font_new("thumb_font", filepath);
if (!font) {
- printf("Info: Can't load font '%s', no preview possible\n", filename);
+ printf("Info: Can't load font '%s', no preview possible\n", filepath);
return;
}
@@ -73,7 +73,7 @@ void BLF_thumb_preview(const char *filename,
for (int i = 0; i < draw_str_lines; i++) {
const char *draw_str_i18n = i18n_draw_str[i] != NULL ? i18n_draw_str[i] : draw_str[i];
const size_t draw_str_i18n_len = strlen(draw_str_i18n);
- int draw_str_i18n_nbr = 0;
+ int draw_str_i18_count = 0;
CLAMP_MIN(font_size_curr, font_size_min);
if (!blf_font_size(font, (float)font_size_curr, dpi)) {
@@ -91,8 +91,8 @@ void BLF_thumb_preview(const char *filename,
* since many fonts will then show nothing but ugly 'missing char' in their preview).
* Does not handle all cases, but much better than nothing.
*/
- if (blf_font_count_missing_chars(font, draw_str_i18n, draw_str_i18n_len, &draw_str_i18n_nbr) >
- (draw_str_i18n_nbr / 2)) {
+ if (blf_font_count_missing_chars(font, draw_str_i18n, draw_str_i18n_len, &draw_str_i18_count) >
+ (draw_str_i18_count / 2)) {
blf_font_draw_buffer(font, draw_str[i], strlen(draw_str[i]), NULL);
}
else {
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index 500f386dcc0..8d449a124ec 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -4,15 +4,13 @@
#include <mutex>
-#include "FN_cpp_type.hh"
-#include "FN_generic_span.hh"
-#include "FN_generic_virtual_array.hh"
-
#include "BKE_anonymous_attribute.hh"
#include "BKE_attribute.h"
#include "BLI_color.hh"
#include "BLI_function_ref.hh"
+#include "BLI_generic_span.hh"
+#include "BLI_generic_virtual_array.hh"
#include "BLI_math_vec_types.hh"
/**
@@ -133,9 +131,9 @@ struct AttributeInitDefault : public AttributeInit {
* Note that this can be used to fill the new attribute with the default
*/
struct AttributeInitVArray : public AttributeInit {
- blender::fn::GVArray varray;
+ blender::GVArray varray;
- AttributeInitVArray(blender::fn::GVArray varray)
+ AttributeInitVArray(blender::GVArray varray)
: AttributeInit(Type::VArray), varray(std::move(varray))
{
}
@@ -166,12 +164,6 @@ using AttributeForeachCallback = blender::FunctionRef<bool(
namespace blender::bke {
-using fn::CPPType;
-using fn::GVArray;
-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,
@@ -239,7 +231,7 @@ class OutputAttribute {
GVMutableArray varray_;
AttributeDomain domain_ = ATTR_DOMAIN_AUTO;
SaveFn save_;
- std::unique_ptr<fn::GVMutableArray_GSpan> optional_span_varray_;
+ std::unique_ptr<GVMutableArray_GSpan> optional_span_varray_;
bool ignore_old_values_ = false;
bool save_has_been_called_ = false;
@@ -256,13 +248,13 @@ class OutputAttribute {
operator bool() const;
GVMutableArray &operator*();
- fn::GVMutableArray *operator->();
+ GVMutableArray *operator->();
GVMutableArray &varray();
AttributeDomain domain() const;
const CPPType &cpp_type() const;
CustomDataType custom_data_type() const;
- fn::GMutableSpan as_span();
+ GMutableSpan as_span();
template<typename T> MutableSpan<T> as_span();
void save();
@@ -376,27 +368,27 @@ class CustomDataAttributes {
void clear();
- std::optional<blender::fn::GSpan> get_for_read(const AttributeIDRef &attribute_id) const;
+ std::optional<blender::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;
+ blender::GVArray get_for_read(const AttributeIDRef &attribute_id,
+ const CustomDataType data_type,
+ const void *default_value) const;
template<typename T>
blender::VArray<T> get_for_read(const AttributeIDRef &attribute_id, const T &default_value) const
{
- const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
+ const blender::CPPType &cpp_type = blender::CPPType::get<T>();
const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
GVArray varray = this->get_for_read(attribute_id, type, &default_value);
return varray.typed<T>();
}
- std::optional<blender::fn::GMutableSpan> get_for_write(const AttributeIDRef &attribute_id);
+ std::optional<blender::GMutableSpan> get_for_write(const AttributeIDRef &attribute_id);
bool create(const AttributeIDRef &attribute_id, const CustomDataType data_type);
bool create_by_move(const AttributeIDRef &attribute_id,
const CustomDataType data_type,
@@ -516,7 +508,7 @@ inline GVMutableArray &OutputAttribute::operator*()
return varray_;
}
-inline fn::GVMutableArray *OutputAttribute::operator->()
+inline GVMutableArray *OutputAttribute::operator->()
{
return &varray_;
}
diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh
index 42bff89922b..9efa64d1474 100644
--- a/source/blender/blenkernel/BKE_attribute_math.hh
+++ b/source/blender/blenkernel/BKE_attribute_math.hh
@@ -4,78 +4,38 @@
#include "BLI_array.hh"
#include "BLI_color.hh"
+#include "BLI_cpp_type.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
-#include "DNA_customdata_types.h"
-
-#include "FN_cpp_type.hh"
+#include "BKE_customdata.h"
namespace blender::attribute_math {
-using fn::CPPType;
-
/**
- * Utility function that simplifies calling a templated function based on a custom data type.
+ * Utility function that simplifies calling a templated function based on a run-time data type.
*/
template<typename Func>
-inline void convert_to_static_type(const CustomDataType data_type, const Func &func)
+inline void convert_to_static_type(const CPPType &cpp_type, const Func &func)
{
- switch (data_type) {
- case CD_PROP_FLOAT:
- func(float());
- break;
- case CD_PROP_FLOAT2:
- func(float2());
- break;
- case CD_PROP_FLOAT3:
- func(float3());
- break;
- case CD_PROP_INT32:
- func(int());
- break;
- case CD_PROP_BOOL:
- func(bool());
- break;
- case CD_PROP_INT8:
- func(int8_t());
- break;
- case CD_PROP_COLOR:
- func(ColorGeometry4f());
- break;
- default:
- BLI_assert_unreachable();
- break;
- }
+ cpp_type.to_static_type_tag<float, float2, float3, int, bool, int8_t, ColorGeometry4f>(
+ [&](auto type_tag) {
+ using T = typename decltype(type_tag)::type;
+ if constexpr (std::is_same_v<T, void>) {
+ /* It's expected that the given cpp type is one of the supported ones. */
+ BLI_assert_unreachable();
+ }
+ else {
+ func(T());
+ }
+ });
}
template<typename Func>
-inline void convert_to_static_type(const fn::CPPType &cpp_type, const Func &func)
+inline void convert_to_static_type(const CustomDataType data_type, const Func &func)
{
- if (cpp_type.is<float>()) {
- func(float());
- }
- else if (cpp_type.is<float2>()) {
- func(float2());
- }
- else if (cpp_type.is<float3>()) {
- func(float3());
- }
- else if (cpp_type.is<int>()) {
- func(int());
- }
- else if (cpp_type.is<bool>()) {
- func(bool());
- }
- else if (cpp_type.is<int8_t>()) {
- func(int8_t());
- }
- else if (cpp_type.is<ColorGeometry4f>()) {
- func(ColorGeometry4f());
- }
- else {
- BLI_assert_unreachable();
- }
+ const CPPType &cpp_type = *bke::custom_data_type_to_cpp_type(data_type);
+ convert_to_static_type(cpp_type, func);
}
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 4b84c0cfe23..a98f4802991 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -52,6 +52,9 @@ bool BKE_brush_delete(struct Main *bmain, struct Brush *brush);
* Add grease pencil settings.
*/
void BKE_brush_init_gpencil_settings(struct Brush *brush);
+
+void BKE_brush_init_curves_sculpt_settings(struct Brush *brush);
+
struct Brush *BKE_brush_first_search(struct Main *bmain, eObjectMode ob_mode);
void BKE_brush_sculpt_reset(struct Brush *brush);
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 394d97223e3..42897c59043 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -274,7 +274,7 @@ bool BKE_nurb_valid_message(int pnts,
short flag,
short type,
bool is_surf,
- const char *dir,
+ int dir,
char *message_dst,
size_t maxncpy);
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 875cf48ed43..0f2ae8a02a6 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -12,6 +12,7 @@
#include <mutex>
#include "BLI_float4x4.hh"
+#include "BLI_generic_virtual_array.hh"
#include "BLI_index_mask.hh"
#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
@@ -21,10 +22,36 @@
#include "BKE_attribute_access.hh"
-#include "FN_generic_virtual_array.hh"
-
namespace blender::bke {
+template<typename T, BLI_ENABLE_IF(std::is_integral_v<T>)>
+constexpr IndexRange offsets_to_range(Span<T> offsets, int64_t index)
+{
+ BLI_assert(index >= 0);
+ BLI_assert(index < offsets.size());
+
+ const int offset = offsets[index];
+ const int offset_next = offsets[index + 1];
+ return {offset, offset_next - offset};
+}
+
+namespace curves::nurbs {
+
+struct BasisCache {
+ /**
+ * For each evaluated point, the weight for all control points that influences it.
+ * The vector's size is the evaluated point count multiplied by the spline's order.
+ */
+ Vector<float> weights;
+ /**
+ * For each evaluated point, an offset into the curve's control points for the start of #weights.
+ * In other words, the index of the first control point that influences this evaluated point.
+ */
+ Vector<int> start_indices;
+};
+
+} // namespace curves::nurbs
+
/**
* Contains derived data, caches, and other information not saved in files, besides a few pointers
* to arrays that are kept in the non-runtime struct to avoid dereferencing this whenever they are
@@ -32,6 +59,19 @@ namespace blender::bke {
*/
class CurvesGeometryRuntime {
public:
+ /**
+ * Cache of offsets into the evaluated array for each curve, accounting for all previous
+ * evaluated points, Bezier curve vector segments, different resolutions per spline, etc.
+ */
+ mutable Vector<int> evaluated_offsets_cache;
+ mutable Vector<int> bezier_evaluated_offsets;
+ mutable std::mutex offsets_cache_mutex;
+ mutable bool offsets_cache_dirty = true;
+
+ mutable Vector<curves::nurbs::BasisCache> nurbs_basis_cache;
+ mutable std::mutex nurbs_basis_cache_mutex;
+ mutable bool nurbs_basis_cache_dirty = true;
+
/** Cache of evaluated positions. */
mutable Vector<float3> evaluated_position_cache;
mutable std::mutex position_cache_mutex;
@@ -82,31 +122,104 @@ class CurvesGeometry : public ::CurvesGeometry {
* Accessors.
*/
- int points_size() const;
- int curves_size() const;
+ int points_num() const;
+ int curves_num() const;
IndexRange points_range() const;
IndexRange curves_range() const;
/**
- * The total number of points in the evaluated poly curve.
- * This can depend on the resolution attribute if it exists.
+ * The index of the first point in every curve. The size of this span is one larger than the
+ * number of curves. Consider using #points_for_curve rather than using the offsets directly.
*/
- int evaluated_points_size() const;
+ Span<int> offsets() const;
+ MutableSpan<int> offsets();
/**
* Access a range of indices of point data for a specific curve.
*/
- IndexRange range_for_curve(int index) const;
- IndexRange range_for_curves(IndexRange curves) const;
+ IndexRange points_for_curve(int index) const;
+ IndexRange points_for_curves(IndexRange curves) const;
/** The type (#CurveType) of each curve, or potentially a single if all are the same type. */
VArray<int8_t> curve_types() const;
/** Mutable access to curve types. Call #tag_topology_changed after changing any type. */
MutableSpan<int8_t> curve_types();
+ bool has_curve_with_type(const CurveType type) const;
+
MutableSpan<float3> positions();
Span<float3> positions() const;
+ /** Whether the curve loops around to connect to itself, on the curve domain. */
+ VArray<bool> cyclic() const;
+ /** Mutable access to curve cyclic values. Call #tag_topology_changed after changes. */
+ MutableSpan<bool> cyclic();
+
+ /**
+ * How many evaluated points to create for each segment when evaluating Bezier,
+ * Catmull Rom, and NURBS curves. On the curve domain.
+ */
+ VArray<int> resolution() const;
+ /** Mutable access to curve resolution. Call #tag_topology_changed after changes. */
+ MutableSpan<int> resolution();
+
+ /**
+ * Handle types for Bezier control points. Call #tag_topology_changed after changes.
+ */
+ VArray<int8_t> handle_types_left() const;
+ MutableSpan<int8_t> handle_types_left();
+ VArray<int8_t> handle_types_right() const;
+ MutableSpan<int8_t> handle_types_right();
+
+ /**
+ * The positions of Bezier curve handles. Though these are really control points for the Bezier
+ * segments, they are stored in separate arrays to better reflect user expectations. Note that
+ * values may be generated automatically based on the handle types. Call #tag_positions_changed
+ * after changes.
+ */
+ Span<float3> handle_positions_left() const;
+ MutableSpan<float3> handle_positions_left();
+ Span<float3> handle_positions_right() const;
+ MutableSpan<float3> handle_positions_right();
+
+ /**
+ * The order (degree plus one) of each NURBS curve, on the curve domain.
+ * Call #tag_topology_changed after changes.
+ */
+ VArray<int8_t> nurbs_orders() const;
+ MutableSpan<int8_t> nurbs_orders();
+
+ /**
+ * The automatic generation mode for each NURBS curve's knots vector, on the curve domain.
+ * Call #tag_topology_changed after changes.
+ */
+ VArray<int8_t> nurbs_knots_modes() const;
+ MutableSpan<int8_t> nurbs_knots_modes();
+
+ /**
+ * The weight for each control point for NURBS curves. Call #tag_positions_changed after changes.
+ */
+ Span<float> nurbs_weights() const;
+ MutableSpan<float> nurbs_weights();
+
+ /**
+ * The index of a triangle (#MLoopTri) that a curve is attached to.
+ * The index is -1, if the curve is not attached.
+ */
+ VArray<int> surface_triangle_indices() const;
+ MutableSpan<int> surface_triangle_indices();
+
+ /**
+ * Barycentric coordinates of the attachment point within a triangle.
+ * Only the first two coordinates are stored. The third coordinate can be derived because the sum
+ * of the three coordinates is 1.
+ *
+ * When the triangle index is -1, this coordinate should be ignored.
+ * The span can be empty, when all triangle indices are -1.
+ */
+ Span<float2> surface_triangle_coords() const;
+ MutableSpan<float2> surface_triangle_coords();
+
/**
* Calculate the largest and smallest position values, only including control points
* (rather than evaluated points). The existing values of `min` and `max` are taken into account.
@@ -115,25 +228,58 @@ class CurvesGeometry : public ::CurvesGeometry {
*/
bool bounds_min_max(float3 &min, float3 &max) const;
+ private:
/**
- * The index of the first point in every curve. The size of this span is one larger than the
- * number of curves. Consider using #range_for_curve rather than using the offsets directly.
+ * All of the curve indices for curves with a specific type.
*/
- Span<int> offsets() const;
- MutableSpan<int> offsets();
+ IndexMask indices_for_curve_type(CurveType type, Vector<int64_t> &r_indices) const;
- VArray<bool> cyclic() const;
- MutableSpan<bool> cyclic();
+ /* --------------------------------------------------------------------
+ * Evaluation.
+ */
+
+ public:
+ /**
+ * The total number of points in the evaluated poly curve.
+ * This can depend on the resolution attribute if it exists.
+ */
+ int evaluated_points_num() const;
+
+ /**
+ * Access a range of indices of point data for a specific curve.
+ * Call #evaluated_offsets() first to ensure that the evaluated offsets cache is current.
+ */
+ IndexRange evaluated_points_for_curve(int index) const;
+ IndexRange evaluated_points_for_curves(IndexRange curves) const;
+
+ /**
+ * The index of the first evaluated point for every curve. The size of this span is one larger
+ * than the number of curves. Consider using #evaluated_points_for_curve rather than using the
+ * offsets directly.
+ */
+ Span<int> evaluated_offsets() const;
+
+ /** Makes sure the data described by #evaluated_offsets if necessary. */
+ void ensure_evaluated_offsets() const;
+
+ Span<float3> evaluated_positions() const;
+
+ private:
+ /**
+ * Make sure the basis weights for NURBS curve's evaluated points are calculated.
+ */
+ void ensure_nurbs_basis_cache() const;
/* --------------------------------------------------------------------
* Operations.
*/
+ public:
/**
* Change the number of elements. New values for existing attributes should be properly
* initialized afterwards.
*/
- void resize(int point_size, int curve_size);
+ void resize(int points_num, int curves_num);
/** Call after deforming the position attribute. */
void tag_positions_changed();
@@ -152,20 +298,178 @@ class CurvesGeometry : public ::CurvesGeometry {
void remove_curves(IndexMask curves_to_delete);
+ /**
+ * Change the direction of selected curves (switch the start and end) without changing their
+ * shape.
+ */
+ void reverse_curves(IndexMask curves_to_reverse);
+
/* --------------------------------------------------------------------
* Attributes.
*/
- fn::GVArray adapt_domain(const fn::GVArray &varray,
- AttributeDomain from,
- AttributeDomain to) const;
+ GVArray adapt_domain(const GVArray &varray, AttributeDomain from, AttributeDomain to) const;
};
-Curves *curves_new_nomain(int point_size, int curves_size);
+namespace curves {
+
+/**
+ * The number of segments between control points, accounting for the last segment of cyclic curves,
+ * and the fact that curves with two points cannot be cyclic. The logic is simple, but this
+ * function should be used to make intentions clearer.
+ */
+inline int curve_segment_size(const int points_num, const bool cyclic)
+{
+ return (cyclic && points_num > 2) ? points_num : points_num - 1;
+}
+
+namespace bezier {
+
+/**
+ * Return true if the handles that make up a segment both have a vector type. Vector segments for
+ * Bezier curves have special behavior because they aren't divided into many evaluated points.
+ */
+bool segment_is_vector(Span<int8_t> handle_types_left,
+ Span<int8_t> handle_types_right,
+ int segment_index);
+
+/**
+ * Return true if the curve's last cylic segment has a vector type.
+ * This only makes a difference in the shape of cyclic curves.
+ */
+bool last_cylic_segment_is_vector(Span<int8_t> handle_types_left, Span<int8_t> handle_types_right);
+
+/**
+ * Calculate offsets into the curve's evaluated points for each control point. While most control
+ * point edges generate the number of edges specified by the resolution, vector segments only
+ * generate one edge.
+ *
+ * The size of the offsets array must be the same as the number of points. The value at each index
+ * is the evaluated point offset including the following segment.
+ */
+void calculate_evaluated_offsets(Span<int8_t> handle_types_left,
+ Span<int8_t> handle_types_right,
+ bool cyclic,
+ int resolution,
+ MutableSpan<int> evaluated_offsets);
+
+/**
+ * Evaluate a cubic Bezier segment, using the "forward differencing" method.
+ * A generic Bezier curve is made up by four points, but in many cases the first and last points
+ * are referred to as the control points, and the middle points are the corresponding handles.
+ */
+void evaluate_segment(const float3 &point_0,
+ const float3 &point_1,
+ const float3 &point_2,
+ const float3 &point_3,
+ MutableSpan<float3> result);
+
+/**
+ * Calculate all evaluated points for the Bezier curve.
+ *
+ * \param evaluated_offsets: The index in the evaluated points array for each control point,
+ * including the points from the corresponding segment. Used to vary the number of evaluated
+ * points per segment, i.e. to make vector segment only have one edge. This is expected to be
+ * calculated by #calculate_evaluated_offsets, and is the reason why this function doesn't need
+ * arguments like "cyclic" and "resolution".
+ */
+void calculate_evaluated_positions(Span<float3> positions,
+ Span<float3> handles_left,
+ Span<float3> handles_right,
+ Span<int> evaluated_offsets,
+ MutableSpan<float3> evaluated_positions);
+
+} // namespace bezier
+
+namespace catmull_rom {
+
+/**
+ * Calculate the number of evaluated points that #interpolate_to_evaluated is expected to produce.
+ * \param points_num: The number of points in the curve.
+ * \param resolution: The resolution for each segment.
+ */
+int calculate_evaluated_size(int points_num, bool cyclic, int resolution);
+
+/**
+ * Evaluate the Catmull Rom curve. The length of the #dst span should be calculated with
+ * #calculate_evaluated_size and is expected to divide evenly by the #src span's segment size.
+ */
+void interpolate_to_evaluated(GSpan src, bool cyclic, int resolution, GMutableSpan dst);
+
+} // namespace catmull_rom
+
+namespace nurbs {
+
+/**
+ * Checks the conditions that a NURBS curve needs to evaluate.
+ */
+bool check_valid_size_and_order(int points_num, int8_t order, bool cyclic, KnotsMode knots_mode);
+
+/**
+ * Calculate the standard evaluated size for a NURBS curve, using the standard that
+ * the resolution is multiplied by the number of segments between the control points.
+ *
+ * \note Though the number of evaluated points is rather arbitrary, it's useful to have a standard
+ * for predictability and so that cached basis weights of NURBS curves with these properties can be
+ * shared.
+ */
+int calculate_evaluated_size(
+ int points_num, int8_t order, bool cyclic, int resolution, KnotsMode knots_mode);
+
+/**
+ * Calculate the length of the knot vector for a NURBS curve with the given properties.
+ * The knots must be longer for a cyclic curve, for example, in order to provide weights for the
+ * last evaluated points that are also influenced by the first control points.
+ */
+int knots_size(int points_num, int8_t order, bool cyclic);
+
+/**
+ * Calculate the knots for a spline given its properties, based on built-in standards defined by
+ * #KnotsMode.
+ *
+ * \note Theoretically any sorted values can be used for NURBS knots, but calculating based
+ * on standard modes allows useful presets, automatic recalculation when the number of points
+ * changes, and is generally more intuitive than defining the knot vector manually.
+ */
+void calculate_knots(
+ int points_num, KnotsMode mode, int8_t order, bool cyclic, MutableSpan<float> knots);
+
+/**
+ * Based on the knots, the order, and other properties of a NURBS curve, calculate a cache that can
+ * be used to more simply interpolate attributes to the evaluated points later. The cache includes
+ * two pieces of information for every evaluated point: the first control point that influences it,
+ * and a weight for each control point.
+ */
+void calculate_basis_cache(int points_num,
+ int evaluated_size,
+ int8_t order,
+ bool cyclic,
+ Span<float> knots,
+ BasisCache &basis_cache);
+
+/**
+ * Using a "basis cache" generated by #BasisCache, interpolate attribute values to the evaluated
+ * points. The number of evaluated points is determined by the #basis_cache argument.
+ *
+ * \param control_weights: An optional span of control point weights, which must have the same size
+ * as the number of control points in the curve if provided. Using this argument gives a NURBS
+ * curve the "Rational" behavior that's part of its acronym; otherwise it is a NUBS.
+ */
+void interpolate_to_evaluated(const BasisCache &basis_cache,
+ int8_t order,
+ Span<float> control_weights,
+ GSpan src,
+ GMutableSpan dst);
+
+} // namespace nurbs
+
+} // namespace curves
+
+Curves *curves_new_nomain(int points_num, int curves_num);
/**
* Create a new curves data-block containing a single curve with the given length and type.
*/
-Curves *curves_new_nomain_single(int point_size, CurveType type);
+Curves *curves_new_nomain_single(int points_num, CurveType type);
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 940dc3c4f6c..6b805a4c29d 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -589,7 +589,7 @@ void CustomData_layers__print(struct CustomData *data);
/* External file storage */
void CustomData_external_add(
- struct CustomData *data, struct ID *id, int type, int totelem, const char *filename);
+ struct CustomData *data, struct ID *id, int type, int totelem, const char *filepath);
void CustomData_external_remove(struct CustomData *data, struct ID *id, int type, int totelem);
bool CustomData_external_test(struct CustomData *data, int type);
@@ -751,3 +751,12 @@ void CustomData_debug_info_from_layers(const struct CustomData *data,
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+# include "BLI_cpp_type.hh"
+
+namespace blender::bke {
+const CPPType *custom_data_type_to_cpp_type(const CustomDataType type);
+CustomDataType cpp_type_to_custom_data_type(const CPPType &type);
+} // namespace blender::bke
+#endif
diff --git a/source/blender/blenkernel/BKE_dynamicpaint.h b/source/blender/blenkernel/BKE_dynamicpaint.h
index 5a1c99774fd..109d3e6d977 100644
--- a/source/blender/blenkernel/BKE_dynamicpaint.h
+++ b/source/blender/blenkernel/BKE_dynamicpaint.h
@@ -129,7 +129,7 @@ int dynamicPaint_calculateFrame(struct DynamicPaintSurface *surface,
struct Object *cObject,
int frame);
void dynamicPaint_outputSurfaceImage(struct DynamicPaintSurface *surface,
- char *filename,
+ const char *filepath,
short output_layer);
/* PaintPoint state */
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 0e121068cbc..bd392057436 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -131,9 +131,9 @@ class GeometryComponent {
* interpolate from one domain to another.
* \return null if the interpolation is not implemented.
*/
- blender::fn::GVArray attribute_try_adapt_domain(const blender::fn::GVArray &varray,
- const AttributeDomain from_domain,
- const AttributeDomain to_domain) const
+ blender::GVArray attribute_try_adapt_domain(const blender::GVArray &varray,
+ const AttributeDomain from_domain,
+ const AttributeDomain to_domain) const
{
return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain);
}
@@ -177,17 +177,17 @@ class GeometryComponent {
* and converted to the data type. Returns null when the attribute does not exist or cannot be
* interpolated or converted.
*/
- blender::fn::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- AttributeDomain domain,
- const CustomDataType data_type) const;
+ blender::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
+ AttributeDomain domain,
+ const CustomDataType data_type) const;
/**
* Get a virtual array that refers to the data of an attribute, interpolated to the given domain.
* The data type is left unchanged. Returns null when the attribute does not exist or cannot be
* interpolated.
*/
- blender::fn::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- AttributeDomain domain) const;
+ blender::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
+ AttributeDomain domain) const;
/**
* Get a virtual array that refers to the data of an attribute converted to the given data type.
@@ -202,17 +202,17 @@ class GeometryComponent {
* and converted to the data type. If that is not possible, the returned virtual array will
* contain a default value. This never returns null.
*/
- blender::fn::GVArray attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
- AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value = nullptr) const;
+ blender::GVArray attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
+ AttributeDomain domain,
+ const CustomDataType data_type,
+ const void *default_value = nullptr) const;
/* Use instead of the method above when the type is known at compile time for type safety. */
template<typename T>
blender::VArray<T> attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id,
const AttributeDomain domain,
const T &default_value) const
{
- const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
+ const blender::CPPType &cpp_type = blender::CPPType::get<T>();
const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
return this->attribute_get_for_read(attribute_id, domain, type, &default_value)
.template typed<T>();
@@ -240,7 +240,7 @@ class GeometryComponent {
const AttributeDomain domain,
const T default_value)
{
- const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
+ const blender::CPPType &cpp_type = blender::CPPType::get<T>();
const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
return this->attribute_try_get_for_output(attribute_id, domain, data_type, &default_value);
}
@@ -260,7 +260,7 @@ class GeometryComponent {
blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output_only(
const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain)
{
- const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
+ const blender::CPPType &cpp_type = blender::CPPType::get<T>();
const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
return this->attribute_try_get_for_output_only(attribute_id, domain, data_type);
}
@@ -268,9 +268,9 @@ class GeometryComponent {
private:
virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const;
- virtual blender::fn::GVArray attribute_try_adapt_domain_impl(const blender::fn::GVArray &varray,
- AttributeDomain from_domain,
- AttributeDomain to_domain) const;
+ virtual blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
+ AttributeDomain from_domain,
+ AttributeDomain to_domain) const;
};
template<typename T>
@@ -568,9 +568,9 @@ class MeshComponent : public GeometryComponent {
private:
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
- blender::fn::GVArray attribute_try_adapt_domain_impl(const blender::fn::GVArray &varray,
- AttributeDomain from_domain,
- AttributeDomain to_domain) const final;
+ blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
+ AttributeDomain from_domain,
+ AttributeDomain to_domain) const final;
};
/**
@@ -672,9 +672,9 @@ class CurveComponentLegacy : public GeometryComponent {
private:
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
- blender::fn::GVArray attribute_try_adapt_domain_impl(const blender::fn::GVArray &varray,
- AttributeDomain from_domain,
- AttributeDomain to_domain) const final;
+ blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
+ AttributeDomain from_domain,
+ AttributeDomain to_domain) const final;
};
/**
@@ -729,9 +729,9 @@ class CurveComponent : public GeometryComponent {
private:
const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final;
- blender::fn::GVArray attribute_try_adapt_domain_impl(const blender::fn::GVArray &varray,
- AttributeDomain from_domain,
- AttributeDomain to_domain) const final;
+ blender::GVArray attribute_try_adapt_domain_impl(const blender::GVArray &varray,
+ AttributeDomain from_domain,
+ AttributeDomain to_domain) const final;
};
/**
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index e586bc4247d..60564d1282e 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -34,7 +34,8 @@ struct bGPDlayer_Mask;
struct bGPDstroke;
struct bGPdata;
-#define GPENCIL_SIMPLIFY(scene) (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE)
+#define GPENCIL_SIMPLIFY(scene) \
+ ((scene->r.mode & R_SIMPLIFY) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE))
#define GPENCIL_SIMPLIFY_ONPLAY(playing) \
(((playing == true) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ON_PLAY)) || \
((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ON_PLAY) == 0))
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index ea0202e3b5f..fba2512fa49 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -64,7 +64,7 @@ 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_imbuf_stamp_info(const struct RenderResult *rr, struct ImBuf *ibuf);
void BKE_stamp_info_from_imbuf(struct RenderResult *rr, struct ImBuf *ibuf);
void BKE_stamp_info_callback(void *data,
struct StampData *stamp_data,
@@ -82,15 +82,14 @@ void BKE_image_stamp_buf(struct Scene *scene,
int height,
int channels);
bool BKE_imbuf_alpha_test(struct ImBuf *ibuf);
-int BKE_imbuf_write_stamp(struct Scene *scene,
- struct RenderResult *rr,
+int BKE_imbuf_write_stamp(const struct Scene *scene,
+ const struct RenderResult *rr,
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_,
@@ -100,43 +99,6 @@ int BKE_imbuf_write_as(struct ImBuf *ibuf,
const char *name,
struct ImageFormatData *imf,
bool save_copy);
-void BKE_image_path_from_imformat(char *string,
- const char *base,
- const char *relbase,
- int frame,
- const struct ImageFormatData *im_format,
- bool use_ext,
- bool use_frames,
- const char *suffix);
-void BKE_image_path_from_imtype(char *string,
- const char *base,
- const char *relbase,
- int frame,
- char imtype,
- bool use_ext,
- bool use_frames,
- const char *suffix);
-int BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format);
-int BKE_image_path_ensure_ext_from_imtype(char *string, char imtype);
-char BKE_image_ftype_to_imtype(int ftype, const struct ImbFormatOptions *options);
-int BKE_image_imtype_to_ftype(char imtype, struct ImbFormatOptions *r_options);
-
-bool BKE_imtype_is_movie(char imtype);
-bool BKE_imtype_supports_zbuf(char imtype);
-bool BKE_imtype_supports_compress(char imtype);
-bool BKE_imtype_supports_quality(char imtype);
-bool BKE_imtype_requires_linear_float(char imtype);
-char BKE_imtype_valid_channels(char imtype, bool write_file);
-char BKE_imtype_valid_depths(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.
@@ -171,10 +133,6 @@ struct RenderResult;
#define IMA_SIGNAL_USER_NEW_IMAGE 6
#define IMA_SIGNAL_COLORMANAGE 7
-#define IMA_CHAN_FLAG_BW 1
-#define IMA_CHAN_FLAG_RGB 2
-#define IMA_CHAN_FLAG_ALPHA 4
-
/**
* Checks whether there's an image buffer for given image and user.
*/
diff --git a/source/blender/blenkernel/BKE_image_format.h b/source/blender/blenkernel/BKE_image_format.h
new file mode 100644
index 00000000000..633af54ea4f
--- /dev/null
+++ b/source/blender/blenkernel/BKE_image_format.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
+
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct BlendDataReader;
+struct BlendWriter;
+struct ImbFormatOptions;
+struct ImageFormatData;
+struct ImBuf;
+struct Scene;
+
+/* Init/Copy/Free */
+
+void BKE_image_format_init(struct ImageFormatData *imf, const bool render);
+void BKE_image_format_copy(struct ImageFormatData *imf_dst, const struct ImageFormatData *imf_src);
+void BKE_image_format_free(struct ImageFormatData *imf);
+
+void BKE_image_format_blend_read_data(struct BlendDataReader *reader, struct ImageFormatData *imf);
+void BKE_image_format_blend_write(struct BlendWriter *writer, struct ImageFormatData *imf);
+
+/* File Paths */
+
+void BKE_image_path_from_imformat(char *string,
+ const char *base,
+ const char *relbase,
+ int frame,
+ const struct ImageFormatData *im_format,
+ bool use_ext,
+ bool use_frames,
+ const char *suffix);
+void BKE_image_path_from_imtype(char *string,
+ const char *base,
+ const char *relbase,
+ int frame,
+ char imtype,
+ bool use_ext,
+ bool use_frames,
+ const char *suffix);
+int BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format);
+int BKE_image_path_ensure_ext_from_imtype(char *string, char imtype);
+
+/* File Types */
+
+#define IMA_CHAN_FLAG_BW 1
+#define IMA_CHAN_FLAG_RGB 2
+#define IMA_CHAN_FLAG_ALPHA 4
+
+char BKE_ftype_to_imtype(int ftype, const struct ImbFormatOptions *options);
+int BKE_imtype_to_ftype(char imtype, struct ImbFormatOptions *r_options);
+
+bool BKE_imtype_is_movie(char imtype);
+bool BKE_imtype_supports_zbuf(char imtype);
+bool BKE_imtype_supports_compress(char imtype);
+bool BKE_imtype_supports_quality(char imtype);
+bool BKE_imtype_requires_linear_float(char imtype);
+char BKE_imtype_valid_channels(char imtype, bool write_file);
+char BKE_imtype_valid_depths(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);
+
+/* Conversion between ImBuf settings. */
+
+void BKE_image_format_from_imbuf(struct ImageFormatData *im_format, const struct ImBuf *imbuf);
+void BKE_image_format_to_imbuf(struct ImBuf *ibuf, const struct ImageFormatData *imf);
+
+/* Color Management */
+
+void BKE_image_format_color_management_copy(struct ImageFormatData *imf,
+ const struct ImageFormatData *imf_src);
+void BKE_image_format_color_management_copy_from_scene(struct ImageFormatData *imf,
+ const struct Scene *scene);
+
+/* Image Output
+ *
+ * Initialize an image format that can be used for file writing, including
+ * color management settings from the scene. */
+
+void BKE_image_format_init_for_write(struct ImageFormatData *imf,
+ const struct Scene *scene_src,
+ const struct ImageFormatData *imf_src);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_image_partial_update.hh b/source/blender/blenkernel/BKE_image_partial_update.hh
index 8cbb8819551..393bf003caa 100644
--- a/source/blender/blenkernel/BKE_image_partial_update.hh
+++ b/source/blender/blenkernel/BKE_image_partial_update.hh
@@ -165,6 +165,7 @@ class ImageTileData : AbstractTileData {
* Can be nullptr when the file doesn't exist or when the tile hasn't been initialized.
*/
ImBuf *tile_buffer = nullptr;
+ void *tile_buffer_lock = nullptr;
ImageTileData(Image *image, ImageUser *image_user) : image(image)
{
@@ -177,14 +178,15 @@ class ImageTileData : AbstractTileData {
{
image_user.tile = new_tile_number;
tile = BKE_image_get_tile(image, new_tile_number);
- tile_buffer = BKE_image_acquire_ibuf(image, &image_user, NULL);
+ tile_buffer = BKE_image_acquire_ibuf(image, &image_user, &tile_buffer_lock);
}
void free_data() override
{
- BKE_image_release_ibuf(image, tile_buffer, nullptr);
+ BKE_image_release_ibuf(image, tile_buffer, tile_buffer_lock);
tile = nullptr;
tile_buffer = nullptr;
+ tile_buffer_lock = nullptr;
}
};
diff --git a/source/blender/blenkernel/BKE_image_save.h b/source/blender/blenkernel/BKE_image_save.h
index ea9ed7d2d26..052fc937af9 100644
--- a/source/blender/blenkernel/BKE_image_save.h
+++ b/source/blender/blenkernel/BKE_image_save.h
@@ -16,6 +16,9 @@ struct Image;
struct Main;
struct ReportList;
struct Scene;
+struct RenderResult;
+
+/* Image datablock saving. */
typedef struct ImageSaveOptions {
/* Context within which image is saved. */
@@ -36,12 +39,37 @@ typedef struct ImageSaveOptions {
void BKE_image_save_options_init(struct ImageSaveOptions *opts,
struct Main *bmain,
struct Scene *scene);
+void BKE_image_save_options_free(struct ImageSaveOptions *opts);
+
bool BKE_image_save(struct ReportList *reports,
struct Main *bmain,
struct Image *ima,
struct ImageUser *iuser,
struct ImageSaveOptions *opts);
+/* Render saving. */
+
+/**
+ * Save single or multi-layer OpenEXR files from the render result.
+ * Optionally saves only a specific view or layer.
+ */
+bool BKE_image_render_write_exr(struct ReportList *reports,
+ const struct RenderResult *rr,
+ const char *filepath,
+ const struct ImageFormatData *imf,
+ const bool save_as_render,
+ const char *view,
+ int layer);
+
+/**
+ * \param filepath_basis: May be used as-is, or used as a basis for multi-view images.
+ */
+bool BKE_image_render_write(struct ReportList *reports,
+ struct RenderResult *rr,
+ const struct Scene *scene,
+ const bool stamp,
+ const char *filepath_basis);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index da436b7d33f..bf9e7651e36 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -13,6 +13,7 @@ struct Lattice;
struct ListBase;
struct Main;
struct Mesh;
+struct MVert;
struct Object;
/* Kernel prototypes */
@@ -119,7 +120,8 @@ 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);
+void BKE_keyblock_convert_to_mesh(struct KeyBlock *kb, struct MVert *mvert, int totvert);
+
/**
* Computes normals (vertices, polygons and/or loops ones) of given mesh for given shape key.
*
diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h
index ba22ab3f1de..77a3223c064 100644
--- a/source/blender/blenkernel/BKE_layer.h
+++ b/source/blender/blenkernel/BKE_layer.h
@@ -301,10 +301,9 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter);
#define FOREACH_SELECTED_OBJECT_BEGIN(_view_layer, _v3d, _instance) \
{ \
- struct ObjectsVisibleIteratorData data_ = { \
- .view_layer = _view_layer, \
- .v3d = _v3d, \
- }; \
+ struct ObjectsVisibleIteratorData data_ = {NULL}; \
+ data_.view_layer = _view_layer; \
+ data_.v3d = _v3d; \
ITER_BEGIN (BKE_view_layer_selected_objects_iterator_begin, \
BKE_view_layer_selected_objects_iterator_next, \
BKE_view_layer_selected_objects_iterator_end, \
@@ -319,10 +318,9 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter);
#define FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN(_view_layer, _v3d, _instance) \
{ \
- struct ObjectsVisibleIteratorData data_ = { \
- .view_layer = _view_layer, \
- .v3d = _v3d, \
- }; \
+ struct ObjectsVisibleIteratorData data_ = {NULL}; \
+ data_.view_layer = _view_layer; \
+ data_.v3d = _v3d; \
ITER_BEGIN (BKE_view_layer_selected_editable_objects_iterator_begin, \
BKE_view_layer_selected_editable_objects_iterator_next, \
BKE_view_layer_selected_editable_objects_iterator_end, \
@@ -337,10 +335,9 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter);
#define FOREACH_VISIBLE_OBJECT_BEGIN(_view_layer, _v3d, _instance) \
{ \
- struct ObjectsVisibleIteratorData data_ = { \
- .view_layer = _view_layer, \
- .v3d = _v3d, \
- }; \
+ struct ObjectsVisibleIteratorData data_ = {NULL}; \
+ data_.view_layer = _view_layer; \
+ data_.v3d = _v3d; \
ITER_BEGIN (BKE_view_layer_visible_objects_iterator_begin, \
BKE_view_layer_visible_objects_iterator_next, \
BKE_view_layer_visible_objects_iterator_end, \
@@ -407,10 +404,9 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter);
#define FOREACH_VISIBLE_BASE_BEGIN(_view_layer, _v3d, _instance) \
{ \
- struct ObjectsVisibleIteratorData data_ = { \
- .view_layer = _view_layer, \
- .v3d = _v3d, \
- }; \
+ struct ObjectsVisibleIteratorData data_ = {NULL}; \
+ data_.view_layer = _view_layer; \
+ data_.v3d = _v3d; \
ITER_BEGIN (BKE_view_layer_visible_bases_iterator_begin, \
BKE_view_layer_visible_bases_iterator_next, \
BKE_view_layer_visible_bases_iterator_end, \
@@ -440,10 +436,9 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter);
IteratorBeginCb func_begin; \
IteratorCb func_next, func_end; \
void *data_in; \
- struct ObjectsVisibleIteratorData data_ = { \
- .view_layer = _view_layer, \
- .v3d = _v3d, \
- }; \
+ struct ObjectsVisibleIteratorData data_ = {NULL}; \
+ data_.view_layer = _view_layer; \
+ data_.v3d = _v3d; \
\
if (flag == SELECT) { \
func_begin = &BKE_view_layer_selected_objects_iterator_begin; \
diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h
index 926be9c7dbe..48cffcf8d2c 100644
--- a/source/blender/blenkernel/BKE_lib_query.h
+++ b/source/blender/blenkernel/BKE_lib_query.h
@@ -115,9 +115,19 @@ typedef int (*LibraryIDLinkCallback)(LibraryIDLinkCallbackData *cb_data);
/* Flags for the foreach function itself. */
enum {
IDWALK_NOP = 0,
+ /** The callback will never modify the ID pointers it processes. */
IDWALK_READONLY = (1 << 0),
- IDWALK_RECURSE = (1 << 1), /* Also implies IDWALK_READONLY. */
- IDWALK_INCLUDE_UI = (1 << 2), /* Include UI pointers (from WM and screens editors). */
+ /** Recurse into 'descendant' IDs.
+ * Each ID is only processed once. Order of ID processing is not guaranteed.
+ *
+ * Also implies IDWALK_READONLY, and excludes IDWALK_DO_INTERNAL_RUNTIME_POINTERS.
+ *
+ * NOTE: When enabled, embedded IDs are processed separately from their owner, as if they were
+ * regular IDs. Owner ID is not available then in the #LibraryForeachIDData callback data.
+ */
+ IDWALK_RECURSE = (1 << 1),
+ /** Include UI pointers (from WM and screens editors). */
+ IDWALK_INCLUDE_UI = (1 << 2),
/** Do not process ID pointers inside embedded IDs. Needed by depsgraph processing e.g. */
IDWALK_IGNORE_EMBEDDED_ID = (1 << 3),
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h
index fd7d39fc250..b66d53b2321 100644
--- a/source/blender/blenkernel/BKE_lib_remap.h
+++ b/source/blender/blenkernel/BKE_lib_remap.h
@@ -26,6 +26,7 @@ extern "C" {
struct ID;
struct IDRemapper;
+struct LinkNode;
/* BKE_libblock_free, delete are declared in BKE_lib_id.h for convenience. */
@@ -133,6 +134,15 @@ void BKE_libblock_relink_ex(struct Main *bmain,
void *old_idv,
void *new_idv,
short remap_flags) ATTR_NONNULL(1, 2);
+/**
+ * Same as #BKE_libblock_relink_ex, but applies all rules defined in \a id_remapper to \a ids (or
+ * does cleanup if `ID_REMAP_TYPE_CLEANUP` is specified as \a remap_type).
+ */
+void BKE_libblock_relink_multiple(struct Main *bmain,
+ struct LinkNode *ids,
+ const eIDRemapType remap_type,
+ struct IDRemapper *id_remapper,
+ const short remap_flags);
/**
* Remaps ID usages of given ID to their `id->newid` pointer if not None, and proceeds recursively
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 2373bb289cd..0ba9713b96d 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -472,6 +472,21 @@ void BKE_mesh_calc_normals_poly(const struct MVert *mvert,
float (*r_poly_normals)[3]);
/**
+ * Calculate face and vertex normals directly into result arrays.
+ *
+ * \note Usually #BKE_mesh_vertex_normals_ensure is the preferred way to access vertex normals,
+ * since they may already be calculated and cached on the mesh.
+ */
+void BKE_mesh_calc_normals_poly_and_vertex(const struct MVert *mvert,
+ int mvert_len,
+ const struct MLoop *mloop,
+ int mloop_len,
+ const struct MPoly *mpoly,
+ int mpoly_len,
+ float (*r_poly_normals)[3],
+ float (*r_vert_normals)[3]);
+
+/**
* Calculate vertex and face normals, storing the result in custom data layers on the mesh.
*
* \note It is usually preferable to calculate normals lazily with
diff --git a/source/blender/blenkernel/BKE_mesh_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh
index 9fe5bd3c531..a942f3bb7ed 100644
--- a/source/blender/blenkernel/BKE_mesh_sample.hh
+++ b/source/blender/blenkernel/BKE_mesh_sample.hh
@@ -6,8 +6,7 @@
* \ingroup bke
*/
-#include "FN_generic_virtual_array.hh"
-
+#include "BLI_generic_virtual_array.hh"
#include "BLI_math_vec_types.hh"
#include "BKE_attribute.h"
@@ -21,11 +20,6 @@ class OutputAttribute;
namespace blender::bke::mesh_surface_sample {
-using fn::CPPType;
-using fn::GMutableSpan;
-using fn::GSpan;
-using fn::GVArray;
-
void sample_point_attribute(const Mesh &mesh,
Span<int> looptri_indices,
Span<float3> bary_coords,
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 904f06f2734..fa199300780 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -99,6 +99,7 @@ typedef struct bNodeSocketTemplate {
* However, achieving this requires quite a few changes currently. */
#ifdef __cplusplus
namespace blender {
+class CPPType;
namespace nodes {
class NodeMultiFunctionBuilder;
class GeoNodeExecParams;
@@ -106,12 +107,11 @@ class NodeDeclarationBuilder;
class GatherLinkSearchOpParams;
} // namespace nodes
namespace fn {
-class CPPType;
class MFDataType;
} // namespace fn
} // namespace blender
-using CPPTypeHandle = blender::fn::CPPType;
+using CPPTypeHandle = blender::CPPType;
using NodeMultiFunctionBuildFunction = void (*)(blender::nodes::NodeMultiFunctionBuilder &builder);
using NodeGeometryExecFunction = void (*)(blender::nodes::GeoNodeExecParams params);
using NodeDeclareFunction = void (*)(blender::nodes::NodeDeclarationBuilder &builder);
@@ -1363,37 +1363,13 @@ struct TexResult;
* \{ */
#define GEO_NODE_TRIANGULATE 1000
-#define GEO_NODE_LEGACY_EDGE_SPLIT 1001
#define GEO_NODE_TRANSFORM 1002
#define GEO_NODE_MESH_BOOLEAN 1003
-#define GEO_NODE_LEGACY_POINT_DISTRIBUTE 1004
-#define GEO_NODE_LEGACY_POINT_INSTANCE 1005
-#define GEO_NODE_LEGACY_SUBDIVISION_SURFACE 1006
#define GEO_NODE_OBJECT_INFO 1007
-#define GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE 1008
-#define GEO_NODE_LEGACY_ATTRIBUTE_MATH 1009
#define GEO_NODE_JOIN_GEOMETRY 1010
-#define GEO_NODE_LEGACY_ATTRIBUTE_FILL 1011
-#define GEO_NODE_LEGACY_ATTRIBUTE_MIX 1012
-#define GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP 1013
-#define GEO_NODE_LEGACY_POINT_SEPARATE 1014
-#define GEO_NODE_LEGACY_ATTRIBUTE_COMPARE 1015
-#define GEO_NODE_LEGACY_POINT_ROTATE 1016
-#define GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_MATH 1017
-#define GEO_NODE_LEGACY_ALIGN_ROTATION_TO_VECTOR 1018
-#define GEO_NODE_LEGACY_POINT_TRANSLATE 1019
-#define GEO_NODE_LEGACY_POINT_SCALE 1020
-#define GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE 1021
-#define GEO_NODE_LEGACY_POINTS_TO_VOLUME 1022
#define GEO_NODE_COLLECTION_INFO 1023
#define GEO_NODE_IS_VIEWPORT 1024
-#define GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY 1025
-#define GEO_NODE_LEGACY_VOLUME_TO_MESH 1026
-#define GEO_NODE_LEGACY_ATTRIBUTE_COMBINE_XYZ 1027
-#define GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ 1028
#define GEO_NODE_SUBDIVIDE_MESH 1029
-#define GEO_NODE_LEGACY_ATTRIBUTE_REMOVE 1030
-#define GEO_NODE_LEGACY_ATTRIBUTE_CONVERT 1031
#define GEO_NODE_MESH_PRIMITIVE_CUBE 1032
#define GEO_NODE_MESH_PRIMITIVE_CIRCLE 1033
#define GEO_NODE_MESH_PRIMITIVE_UV_SPHERE 1034
@@ -1402,28 +1378,15 @@ struct TexResult;
#define GEO_NODE_MESH_PRIMITIVE_CONE 1037
#define GEO_NODE_MESH_PRIMITIVE_LINE 1038
#define GEO_NODE_MESH_PRIMITIVE_GRID 1039
-#define GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE 1040
-#define GEO_NODE_LEGACY_ATTRIBUTE_CLAMP 1041
#define GEO_NODE_BOUNDING_BOX 1042
#define GEO_NODE_SWITCH 1043
-#define GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER 1044
#define GEO_NODE_CURVE_TO_MESH 1045
-#define GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP 1046
#define GEO_NODE_RESAMPLE_CURVE 1047
-#define GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_ROTATE 1048
-#define GEO_NODE_LEGACY_MATERIAL_ASSIGN 1049
#define GEO_NODE_INPUT_MATERIAL 1050
#define GEO_NODE_REPLACE_MATERIAL 1051
-#define GEO_NODE_LEGACY_MESH_TO_CURVE 1052
-#define GEO_NODE_LEGACY_DELETE_GEOMETRY 1053
#define GEO_NODE_CURVE_LENGTH 1054
-#define GEO_NODE_LEGACY_SELECT_BY_MATERIAL 1055
#define GEO_NODE_CONVEX_HULL 1056
-#define GEO_NODE_LEGACY_CURVE_TO_POINTS 1057
-#define GEO_NODE_LEGACY_CURVE_REVERSE 1058
#define GEO_NODE_SEPARATE_COMPONENTS 1059
-#define GEO_NODE_LEGACY_CURVE_SUBDIVIDE 1060
-#define GEO_NODE_LEGACY_RAYCAST 1061
#define GEO_NODE_CURVE_PRIMITIVE_STAR 1062
#define GEO_NODE_CURVE_PRIMITIVE_SPIRAL 1063
#define GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER 1064
@@ -1431,12 +1394,8 @@ struct TexResult;
#define GEO_NODE_CURVE_PRIMITIVE_CIRCLE 1066
#define GEO_NODE_VIEWER 1067
#define GEO_NODE_CURVE_PRIMITIVE_LINE 1068
-#define GEO_NODE_LEGACY_CURVE_ENDPOINTS 1069
#define GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL 1070
#define GEO_NODE_TRIM_CURVE 1071
-#define GEO_NODE_LEGACY_CURVE_SET_HANDLES 1072
-#define GEO_NODE_LEGACY_CURVE_SPLINE_TYPE 1073
-#define GEO_NODE_LEGACY_CURVE_SELECT_HANDLES 1074
#define GEO_NODE_FILL_CURVE 1075
#define GEO_NODE_INPUT_POSITION 1076
#define GEO_NODE_SET_POSITION 1077
diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h
index 8433894b8c5..893aa2a5b1c 100644
--- a/source/blender/blenkernel/BKE_packedFile.h
+++ b/source/blender/blenkernel/BKE_packedFile.h
@@ -45,7 +45,7 @@ enum ePF_FileStatus {
struct PackedFile *BKE_packedfile_duplicate(const struct PackedFile *pf_src);
struct PackedFile *BKE_packedfile_new(struct ReportList *reports,
- const char *filename,
+ const char *filepath,
const char *basepath);
struct PackedFile *BKE_packedfile_new_from_memory(void *mem, int memlen);
@@ -102,7 +102,7 @@ int BKE_packedfile_unpack_all_libraries(struct Main *bmain, struct ReportList *r
int BKE_packedfile_write_to_file(struct ReportList *reports,
const char *ref_file_name,
- const char *filename,
+ const char *filepath,
struct PackedFile *pf,
bool guimode);
@@ -122,7 +122,7 @@ int BKE_packedfile_count_all(struct Main *bmain);
* - #PF_NOFILE: the original file doesn't exist.
*/
enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
- const char *filename,
+ const char *filepath_rel,
struct PackedFile *pf);
/* Read. */
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index d06b1d43b96..a6402a1e8a1 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -225,7 +225,7 @@ bool BKE_scene_remove_render_view(struct Scene *scene, struct SceneRenderView *s
/* 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);
+int get_render_child_particle_number(const struct RenderData *r, int child_num, bool for_render);
bool BKE_scene_use_shading_nodes_custom(struct Scene *scene);
bool BKE_scene_use_spherical_stereo(struct Scene *scene);
@@ -282,7 +282,7 @@ struct SceneRenderView *BKE_scene_multiview_render_view_findindex(const struct R
int view_id);
const char *BKE_scene_multiview_render_view_name_get(const struct RenderData *rd, int view_id);
int BKE_scene_multiview_view_id_get(const struct RenderData *rd, const char *viewname);
-void BKE_scene_multiview_filepath_get(struct SceneRenderView *srv,
+void BKE_scene_multiview_filepath_get(const struct SceneRenderView *srv,
const char *filepath,
char *r_filepath);
/**
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index 87f4ad6dc61..32330244c08 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -8,11 +8,10 @@
#include <mutex>
-#include "FN_generic_virtual_array.hh"
-
#include "DNA_curves_types.h"
#include "BLI_float4x4.hh"
+#include "BLI_generic_virtual_array.hh"
#include "BLI_math_vec_types.hh"
#include "BLI_vector.hh"
@@ -205,16 +204,16 @@ class Spline {
* 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,
+ void sample_with_index_factors(const blender::GVArray &src,
blender::Span<float> index_factors,
- blender::fn::GMutableSpan dst) const;
+ blender::GMutableSpan dst) const;
template<typename T>
void sample_with_index_factors(const blender::VArray<T> &src,
blender::Span<float> index_factors,
blender::MutableSpan<T> dst) const
{
this->sample_with_index_factors(
- blender::fn::GVArray(src), index_factors, blender::fn::GMutableSpan(dst));
+ blender::GVArray(src), index_factors, blender::GMutableSpan(dst));
}
template<typename T>
void sample_with_index_factors(blender::Span<T> src,
@@ -229,11 +228,11 @@ class Spline {
* evaluated points. For poly splines, the lifetime of the returned virtual array must not
* exceed the lifetime of the input data.
*/
- virtual blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const = 0;
- blender::fn::GVArray interpolate_to_evaluated(blender::fn::GSpan data) const;
+ virtual blender::GVArray interpolate_to_evaluated(const blender::GVArray &src) const = 0;
+ blender::GVArray interpolate_to_evaluated(blender::GSpan data) const;
template<typename T> blender::VArray<T> interpolate_to_evaluated(blender::Span<T> data) const
{
- return this->interpolate_to_evaluated(blender::fn::GSpan(data)).typed<T>();
+ return this->interpolate_to_evaluated(blender::GSpan(data)).typed<T>();
}
protected:
@@ -386,8 +385,7 @@ class BezierSpline final : public Spline {
*/
InterpolationData interpolation_data_from_index_factor(float index_factor) const;
- virtual blender::fn::GVArray interpolate_to_evaluated(
- const blender::fn::GVArray &src) const override;
+ virtual blender::GVArray interpolate_to_evaluated(const blender::GVArray &src) const override;
void evaluate_segment(int index,
int next_index,
@@ -541,7 +539,7 @@ class NURBSpline final : public Spline {
blender::Span<blender::float3> evaluated_positions() const final;
- blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const final;
+ blender::GVArray interpolate_to_evaluated(const blender::GVArray &src) const final;
protected:
void correct_end_tangents() const final;
@@ -599,7 +597,7 @@ class PolySpline final : public Spline {
* 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;
+ blender::GVArray interpolate_to_evaluated(const blender::GVArray &src) const final;
protected:
void correct_end_tangents() const final;
diff --git a/source/blender/blenkernel/BKE_subdiv_modifier.h b/source/blender/blenkernel/BKE_subdiv_modifier.h
index 40e8ee2f999..e9de7d1532e 100644
--- a/source/blender/blenkernel/BKE_subdiv_modifier.h
+++ b/source/blender/blenkernel/BKE_subdiv_modifier.h
@@ -13,6 +13,10 @@
extern "C" {
#endif
+/* Hardcoded for until GPU shaders are automatically generated, then we will have a more
+ * programmatic way of detecting this. */
+#define MAX_GPU_SUBDIV_SSBOS 12
+
struct Mesh;
struct Object;
struct Scene;
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 8cac196accc..29eb180a2ab 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -510,6 +510,7 @@ void BKE_tracking_refine_marker(struct MovieClip *clip,
struct AutoTrackContext *BKE_autotrack_context_new(struct MovieClip *clip,
struct MovieClipUser *user,
bool is_backwards);
+void BKE_autotrack_context_start(struct AutoTrackContext *context);
bool BKE_autotrack_context_step(struct AutoTrackContext *context);
void BKE_autotrack_context_sync(struct AutoTrackContext *context);
void BKE_autotrack_context_sync_user(struct AutoTrackContext *context, struct MovieClipUser *user);
diff --git a/source/blender/blenkernel/BKE_type_conversions.hh b/source/blender/blenkernel/BKE_type_conversions.hh
index e66982aa04c..5152989d137 100644
--- a/source/blender/blenkernel/BKE_type_conversions.hh
+++ b/source/blender/blenkernel/BKE_type_conversions.hh
@@ -6,8 +6,6 @@
namespace blender::bke {
-using fn::CPPType;
-
struct ConversionFunctions {
const fn::MultiFunction *multi_function;
void (*convert_single_to_initialized)(const void *src, void *dst);
@@ -58,11 +56,11 @@ class DataTypeConversions {
const void *from_value,
void *to_value) const;
- void convert_to_initialized_n(fn::GSpan from_span, fn::GMutableSpan to_span) const;
+ void convert_to_initialized_n(GSpan from_span, GMutableSpan to_span) const;
- fn::GVArray try_convert(fn::GVArray varray, const CPPType &to_type) const;
+ GVArray try_convert(GVArray varray, const CPPType &to_type) const;
- fn::GVMutableArray try_convert(fn::GVMutableArray varray, const CPPType &to_type) const;
+ GVMutableArray try_convert(GVMutableArray varray, const CPPType &to_type) const;
};
const DataTypeConversions &get_implicit_type_conversions();
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 2e32652647c..8f7ef035557 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -104,15 +104,18 @@ set(SRC
intern/crazyspace.c
intern/cryptomatte.cc
intern/curve.cc
- intern/curves.cc
- intern/curves_geometry.cc
intern/curve_bevel.c
+ intern/curve_bezier.cc
+ intern/curve_catmull_rom.cc
intern/curve_convert.c
intern/curve_decimate.c
intern/curve_deform.c
intern/curve_eval.cc
+ intern/curve_nurbs.cc
intern/curve_to_mesh_convert.cc
intern/curveprofile.cc
+ intern/curves.cc
+ intern/curves_geometry.cc
intern/customdata.cc
intern/customdata_file.c
intern/data_transfer.c
@@ -153,10 +156,11 @@ set(SRC
intern/idprop_utils.c
intern/idtype.c
intern/image.cc
- intern/image_partial_update.cc
+ intern/image_format.cc
intern/image_gen.c
intern/image_gpu.cc
- intern/image_save.c
+ intern/image_partial_update.cc
+ intern/image_save.cc
intern/ipo.c
intern/kelvinlet.c
intern/key.c
@@ -344,10 +348,10 @@ set(SRC
BKE_cryptomatte.h
BKE_cryptomatte.hh
BKE_curve.h
- BKE_curves.h
- BKE_curves.hh
BKE_curve_to_mesh.hh
BKE_curveprofile.h
+ BKE_curves.h
+ BKE_curves.hh
BKE_customdata.h
BKE_customdata_file.h
BKE_data_transfer.h
@@ -380,6 +384,7 @@ set(SRC
BKE_idprop.hh
BKE_idtype.h
BKE_image.h
+ BKE_image_format.h
BKE_image_partial_update.hh
BKE_image_save.h
BKE_ipo.h
@@ -602,6 +607,10 @@ if(WITH_IMAGE_HDR)
add_definitions(-DWITH_HDR)
endif()
+if(WITH_IMAGE_WEBP)
+ add_definitions(-DWITH_WEBP)
+endif()
+
if(WITH_CODEC_AVI)
list(APPEND INC
../io/avi
@@ -815,6 +824,7 @@ if(WITH_GTESTS)
intern/fcurve_test.cc
intern/idprop_serialize_test.cc
intern/image_partial_update_test.cc
+ intern/image_test.cc
intern/lattice_deform_test.cc
intern/layer_test.cc
intern/lib_id_remapper_test.cc
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index b0393ed723d..8d3649fef08 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -1022,16 +1022,16 @@ void BKE_appdir_app_templates(ListBase *templates)
continue;
}
- struct direntry *dir;
- uint totfile = BLI_filelist_dir_contents(subdir, &dir);
- for (int f = 0; f < totfile; f++) {
- if (!FILENAME_IS_CURRPAR(dir[f].relname) && S_ISDIR(dir[f].type)) {
- char *template = BLI_strdup(dir[f].relname);
+ struct direntry *dirs;
+ const uint dir_num = BLI_filelist_dir_contents(subdir, &dirs);
+ for (int f = 0; f < dir_num; f++) {
+ if (!FILENAME_IS_CURRPAR(dirs[f].relname) && S_ISDIR(dirs[f].type)) {
+ char *template = BLI_strdup(dirs[f].relname);
BLI_addtail(templates, BLI_genericNodeN(template));
}
}
- BLI_filelist_free(dir, totfile);
+ BLI_filelist_free(dirs, dir_num);
}
}
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 5c2d77f20a8..0a6ef8f0f01 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -2164,8 +2164,8 @@ void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float r_m
const float y = nor[1];
const float z = nor[2];
- float theta = 1.0f + y; /* remapping Y from [-1,+1] to [0,2]. */
- const float theta_alt = x * x + z * z; /* squared distance from origin in x,z plane. */
+ float theta = 1.0f + y; /* Remapping Y from [-1,+1] to [0,2]. */
+ const float theta_alt = x * x + z * z; /* Squared distance from origin in x,z plane. */
float rMatrix[3][3], bMatrix[3][3];
BLI_ASSERT_UNIT_V3(nor);
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 2f07ee55d79..8fbab8dde25 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -28,14 +28,14 @@
static CLG_LogRef LOG = {"bke.attribute_access"};
using blender::float3;
+using blender::GMutableSpan;
+using blender::GSpan;
+using blender::GVArrayImpl_For_GSpan;
using blender::Set;
using blender::StringRef;
using blender::StringRefNull;
using blender::bke::AttributeIDRef;
using blender::bke::OutputAttribute;
-using blender::fn::GMutableSpan;
-using blender::fn::GSpan;
-using blender::fn::GVArrayImpl_For_GSpan;
namespace blender::bke {
@@ -54,55 +54,6 @@ std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_i
return stream;
}
-const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType type)
-{
- switch (type) {
- case CD_PROP_FLOAT:
- return &CPPType::get<float>();
- case CD_PROP_FLOAT2:
- return &CPPType::get<float2>();
- case CD_PROP_FLOAT3:
- return &CPPType::get<float3>();
- case CD_PROP_INT32:
- return &CPPType::get<int>();
- case CD_PROP_COLOR:
- return &CPPType::get<ColorGeometry4f>();
- case CD_PROP_BOOL:
- return &CPPType::get<bool>();
- case CD_PROP_INT8:
- return &CPPType::get<int8_t>();
- default:
- return nullptr;
- }
- return nullptr;
-}
-
-CustomDataType cpp_type_to_custom_data_type(const blender::fn::CPPType &type)
-{
- if (type.is<float>()) {
- return CD_PROP_FLOAT;
- }
- if (type.is<float2>()) {
- return CD_PROP_FLOAT2;
- }
- if (type.is<float3>()) {
- return CD_PROP_FLOAT3;
- }
- if (type.is<int>()) {
- return CD_PROP_INT32;
- }
- if (type.is<ColorGeometry4f>()) {
- return CD_PROP_COLOR;
- }
- if (type.is<bool>()) {
- return CD_PROP_BOOL;
- }
- if (type.is<int8_t>()) {
- return CD_PROP_INT8;
- }
- return static_cast<CustomDataType>(-1);
-}
-
static int attribute_data_type_complexity(const CustomDataType data_type)
{
switch (data_type) {
@@ -191,14 +142,14 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
return highest_priority_domain;
}
-fn::GMutableSpan OutputAttribute::as_span()
+GMutableSpan OutputAttribute::as_span()
{
if (!optional_span_varray_) {
const bool materialize_old_values = !ignore_old_values_;
- optional_span_varray_ = std::make_unique<fn::GVMutableArray_GSpan>(varray_,
- materialize_old_values);
+ optional_span_varray_ = std::make_unique<GVMutableArray_GSpan>(varray_,
+ materialize_old_values);
}
- fn::GVMutableArray_GSpan &span_varray = *optional_span_varray_;
+ GVMutableArray_GSpan &span_varray = *optional_span_varray_;
return span_varray;
}
@@ -917,8 +868,8 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
return {};
}
-blender::fn::GVArray GeometryComponent::attribute_try_adapt_domain_impl(
- const blender::fn::GVArray &varray,
+blender::GVArray GeometryComponent::attribute_try_adapt_domain_impl(
+ const blender::GVArray &varray,
const AttributeDomain from_domain,
const AttributeDomain to_domain) const
{
@@ -1101,15 +1052,15 @@ std::optional<AttributeMetaData> GeometryComponent::attribute_get_meta_data(
return result;
}
-static blender::fn::GVArray try_adapt_data_type(blender::fn::GVArray varray,
- const blender::fn::CPPType &to_type)
+static blender::GVArray try_adapt_data_type(blender::GVArray varray,
+ const blender::CPPType &to_type)
{
const blender::bke::DataTypeConversions &conversions =
blender::bke::get_implicit_type_conversions();
return conversions.try_convert(std::move(varray), to_type);
}
-blender::fn::GVArray GeometryComponent::attribute_try_get_for_read(
+blender::GVArray GeometryComponent::attribute_try_get_for_read(
const AttributeIDRef &attribute_id,
const AttributeDomain domain,
const CustomDataType data_type) const
@@ -1119,7 +1070,7 @@ blender::fn::GVArray GeometryComponent::attribute_try_get_for_read(
return {};
}
- blender::fn::GVArray varray = std::move(attribute.varray);
+ blender::GVArray varray = std::move(attribute.varray);
if (!ELEM(domain, ATTR_DOMAIN_AUTO, attribute.domain)) {
varray = this->attribute_try_adapt_domain(std::move(varray), attribute.domain, domain);
if (!varray) {
@@ -1127,7 +1078,7 @@ blender::fn::GVArray GeometryComponent::attribute_try_get_for_read(
}
}
- const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
+ const blender::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
if (varray.type() != *cpp_type) {
varray = try_adapt_data_type(std::move(varray), *cpp_type);
@@ -1139,8 +1090,8 @@ blender::fn::GVArray GeometryComponent::attribute_try_get_for_read(
return varray;
}
-blender::fn::GVArray GeometryComponent::attribute_try_get_for_read(
- const AttributeIDRef &attribute_id, const AttributeDomain domain) const
+blender::GVArray GeometryComponent::attribute_try_get_for_read(const AttributeIDRef &attribute_id,
+ const AttributeDomain domain) const
{
if (!this->attribute_domain_supported(domain)) {
return {};
@@ -1165,7 +1116,7 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
if (!attribute) {
return {};
}
- const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
+ const blender::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(type != nullptr);
if (attribute.varray.type() == *type) {
return attribute;
@@ -1175,24 +1126,24 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
return {conversions.try_convert(std::move(attribute.varray), *type), attribute.domain};
}
-blender::fn::GVArray GeometryComponent::attribute_get_for_read(const AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value) const
+blender::GVArray GeometryComponent::attribute_get_for_read(const AttributeIDRef &attribute_id,
+ const AttributeDomain domain,
+ const CustomDataType data_type,
+ const void *default_value) const
{
- blender::fn::GVArray varray = this->attribute_try_get_for_read(attribute_id, domain, data_type);
+ blender::GVArray varray = this->attribute_try_get_for_read(attribute_id, domain, data_type);
if (varray) {
return varray;
}
- const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
+ const blender::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
if (default_value == nullptr) {
default_value = type->default_value();
}
const int domain_size = this->attribute_domain_size(domain);
- return blender::fn::GVArray::ForSingle(*type, domain_size, default_value);
+ return blender::GVArray::ForSingle(*type, domain_size, default_value);
}
-class GVMutableAttribute_For_OutputAttribute : public blender::fn::GVArrayImpl_For_GSpan {
+class GVMutableAttribute_For_OutputAttribute : public blender::GVArrayImpl_For_GSpan {
public:
GeometryComponent *component;
std::string attribute_name;
@@ -1201,7 +1152,7 @@ class GVMutableAttribute_For_OutputAttribute : public blender::fn::GVArrayImpl_F
GVMutableAttribute_For_OutputAttribute(GMutableSpan data,
GeometryComponent &component,
const AttributeIDRef &attribute_id)
- : blender::fn::GVArrayImpl_For_GSpan(data), component(&component)
+ : blender::GVArrayImpl_For_GSpan(data), component(&component)
{
if (attribute_id.is_named()) {
this->attribute_name = attribute_id.name();
diff --git a/source/blender/blenkernel/intern/bpath_test.cc b/source/blender/blenkernel/intern/bpath_test.cc
index ec1737276e1..a614f9b3954 100644
--- a/source/blender/blenkernel/intern/bpath_test.cc
+++ b/source/blender/blenkernel/intern/bpath_test.cc
@@ -77,7 +77,7 @@ class BPathTest : public testing::Test {
TEST_F(BPathTest, rebase_on_relative)
{
- // Test on relative paths, should be modified.
+ /* Test on relative paths, should be modified. */
Text *text = reinterpret_cast<Text *>(bmain->texts.first);
text->filepath = BLI_strdup(TEXT_PATH_RELATIVE);
@@ -92,7 +92,7 @@ TEST_F(BPathTest, rebase_on_relative)
TEST_F(BPathTest, rebase_on_absolute)
{
- // Test on absolute paths, should not be modified.
+ /* Test on absolute paths, should not be modified. */
Text *text = reinterpret_cast<Text *>(bmain->texts.first);
text->filepath = BLI_strdup(TEXT_PATH_ABSOLUTE);
@@ -115,9 +115,9 @@ TEST_F(BPathTest, convert_to_relative)
BKE_bpath_relative_convert(bmain, BASE_DIR, nullptr);
- // Already relative path should not be modified.
+ /* Already relative path should not be modified. */
EXPECT_STREQ(text->filepath, TEXT_PATH_RELATIVE);
- // Absolute path should be modified.
+ /* Absolute path should be modified. */
EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE_MADE_RELATIVE);
}
@@ -131,9 +131,9 @@ TEST_F(BPathTest, convert_to_absolute)
BKE_bpath_absolute_convert(bmain, BASE_DIR, nullptr);
- // Relative path should be modified.
+ /* Relative path should be modified. */
EXPECT_STREQ(text->filepath, TEXT_PATH_RELATIVE_MADE_ABSOLUTE);
- // Already absolute path should not be modified.
+ /* Already absolute path should not be modified. */
EXPECT_STREQ(movie_clip->filepath, MOVIECLIP_PATH_ABSOLUTE);
}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 6ee6ff7f41d..ff07d061a20 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -94,6 +94,9 @@ static void brush_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
brush_dst->gpencil_settings->curve_rand_value = BKE_curvemapping_copy(
brush_src->gpencil_settings->curve_rand_value);
}
+ if (brush_src->curves_sculpt_settings != NULL) {
+ brush_dst->curves_sculpt_settings = MEM_dupallocN(brush_src->curves_sculpt_settings);
+ }
/* enable fake user by default */
id_fake_user_set(&brush_dst->id);
@@ -121,6 +124,9 @@ static void brush_free_data(ID *id)
MEM_SAFE_FREE(brush->gpencil_settings);
}
+ if (brush->curves_sculpt_settings != NULL) {
+ MEM_freeN(brush->curves_sculpt_settings);
+ }
MEM_SAFE_FREE(brush->gradient);
@@ -236,6 +242,9 @@ static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_addres
BKE_curvemapping_blend_write(writer, brush->gpencil_settings->curve_rand_value);
}
}
+ if (brush->curves_sculpt_settings) {
+ BLO_write_struct(writer, BrushCurvesSculptSettings, brush->curves_sculpt_settings);
+ }
if (brush->gradient) {
BLO_write_struct(writer, ColorBand, brush->gradient);
}
@@ -308,6 +317,8 @@ static void brush_blend_read_data(BlendDataReader *reader, ID *id)
}
}
+ BLO_read_data_address(reader, &brush->curves_sculpt_settings);
+
brush->preview = NULL;
brush->icon_imbuf = NULL;
}
@@ -489,6 +500,10 @@ Brush *BKE_brush_add(Main *bmain, const char *name, const eObjectMode ob_mode)
brush->ob_mode = ob_mode;
+ if (ob_mode == OB_MODE_SCULPT_CURVES) {
+ BKE_brush_init_curves_sculpt_settings(brush);
+ }
+
return brush;
}
@@ -1537,6 +1552,14 @@ void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool
}
}
+void BKE_brush_init_curves_sculpt_settings(Brush *brush)
+{
+ if (brush->curves_sculpt_settings == NULL) {
+ brush->curves_sculpt_settings = MEM_callocN(sizeof(BrushCurvesSculptSettings), __func__);
+ }
+ brush->curves_sculpt_settings->add_amount = 1;
+}
+
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)
{
Brush *brush;
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index af776e9dbb0..891145b47c9 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -129,7 +129,7 @@ static void collection_free_data(ID *id)
{
Collection *collection = (Collection *)id;
- /* No animdata here. */
+ /* No animation-data here. */
BKE_previewimg_free(&collection->preview);
BLI_freelistN(&collection->gobject);
diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc
index 0b619c1a969..02710982564 100644
--- a/source/blender/blenkernel/intern/curve.cc
+++ b/source/blender/blenkernel/intern/curve.cc
@@ -62,6 +62,14 @@ using blender::IndexRange;
/* local */
// static CLG_LogRef LOG = {"bke.curve"};
+enum class NURBSValidationStatus {
+ Valid,
+ AtLeastTwoPointsRequired,
+ MorePointsThanOrderRequired,
+ MoreRowsForBezierRequired,
+ MorePointsForBezierRequired
+};
+
static void curve_init_data(ID *id)
{
Curve *curve = (Curve *)id;
@@ -4700,56 +4708,94 @@ void BKE_curve_nurbs_key_vert_tilts_apply(ListBase *lb, const float *key)
}
}
-bool BKE_nurb_valid_message(const int pnts,
- const short order,
- const short flag,
- const short type,
- const bool is_surf,
- const char *dir,
- char *message_dst,
- const size_t maxncpy)
+static NURBSValidationStatus nurb_check_valid(const int pnts,
+ const short order,
+ const short flag,
+ const short type,
+ const bool is_surf,
+ int *r_points_needed)
{
- const char *msg_template = "";
- uint16_t points_needed = 0;
-
if (pnts <= 1) {
- msg_template = TIP_("At least two points required.");
+ return NURBSValidationStatus::AtLeastTwoPointsRequired;
}
- else if (type == CU_NURBS) {
+ if (type == CU_NURBS) {
if (pnts < order) {
- msg_template = TIP_("Must have more control points than Order");
+ return NURBSValidationStatus::MorePointsThanOrderRequired;
}
- else if (flag & CU_NURB_BEZIER) {
+ if (flag & CU_NURB_BEZIER) {
+ int points_needed = 0;
if (flag & CU_NURB_CYCLIC) {
- const uint16_t remainder = pnts % (order - 1);
+ const int remainder = pnts % (order - 1);
points_needed = remainder > 0 ? order - 1 - remainder : 0;
}
else if (((flag & CU_NURB_ENDPOINT) == 0) && pnts <= order) {
points_needed = order + 1 - pnts;
}
if (points_needed) {
- msg_template = is_surf ? TIP_("%d more %s row(s) needed for Bezier") :
- TIP_("%d more point(s) needed for Bezier");
+ *r_points_needed = points_needed;
+ return is_surf ? NURBSValidationStatus::MoreRowsForBezierRequired :
+ NURBSValidationStatus::MorePointsForBezierRequired;
}
}
}
+ return NURBSValidationStatus::Valid;
+}
+
+bool BKE_nurb_valid_message(const int pnts,
+ const short order,
+ const short flag,
+ const short type,
+ const bool is_surf,
+ const int dir,
+ char *message_dst,
+ const size_t maxncpy)
+{
+ int points_needed;
+ NURBSValidationStatus status = nurb_check_valid(
+ pnts, order, flag, type, is_surf, &points_needed);
- if (message_dst) {
- BLI_snprintf(message_dst, maxncpy, msg_template, points_needed, dir);
+ const char *msg_template = nullptr;
+ switch (status) {
+ case NURBSValidationStatus::Valid:
+ message_dst[0] = 0;
+ return false;
+ case NURBSValidationStatus::AtLeastTwoPointsRequired:
+ if (dir == 1) {
+ /* Exception made for curves as their pntsv == 1. */
+ message_dst[0] = 0;
+ return false;
+ }
+ msg_template = TIP_("At least two points required.");
+ break;
+ case NURBSValidationStatus::MorePointsThanOrderRequired:
+ msg_template = TIP_("Must have more control points than Order");
+ break;
+ case NURBSValidationStatus::MoreRowsForBezierRequired:
+ msg_template = TIP_("%d more %s row(s) needed for Bezier");
+ break;
+ case NURBSValidationStatus::MorePointsForBezierRequired:
+ msg_template = TIP_("%d more point(s) needed for Bezier");
+ break;
}
- return msg_template[0];
+
+ BLI_snprintf(message_dst, maxncpy, msg_template, points_needed, dir == 0 ? "U" : "V");
+ return true;
}
bool BKE_nurb_check_valid_u(const Nurb *nu)
{
- return !BKE_nurb_valid_message(
- nu->pntsu, nu->orderu, nu->flagu, nu->type, nu->pntsv > 1, "U", nullptr, 0);
+ int points_needed;
+ return NURBSValidationStatus::Valid ==
+ nurb_check_valid(
+ nu->pntsu, nu->orderu, nu->flagu, nu->type, nu->pntsv > 1, &points_needed);
}
bool BKE_nurb_check_valid_v(const Nurb *nu)
{
- return !BKE_nurb_valid_message(
- nu->pntsv, nu->orderv, nu->flagv, nu->type, nu->pntsv > 1, "V", nullptr, 0);
+ int points_needed;
+ return NURBSValidationStatus::Valid ==
+ nurb_check_valid(
+ nu->pntsv, nu->orderv, nu->flagv, nu->type, nu->pntsv > 1, &points_needed);
}
bool BKE_nurb_check_valid_uv(const Nurb *nu)
diff --git a/source/blender/blenkernel/intern/curve_bezier.cc b/source/blender/blenkernel/intern/curve_bezier.cc
new file mode 100644
index 00000000000..c02555dcf6a
--- /dev/null
+++ b/source/blender/blenkernel/intern/curve_bezier.cc
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <algorithm>
+
+#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
+
+namespace blender::bke::curves::bezier {
+
+bool segment_is_vector(const Span<int8_t> handle_types_left,
+ const Span<int8_t> handle_types_right,
+ const int segment_index)
+{
+ BLI_assert(handle_types_left.index_range().drop_back(1).contains(segment_index));
+ return handle_types_right[segment_index] == BEZIER_HANDLE_VECTOR &&
+ handle_types_left[segment_index + 1] == BEZIER_HANDLE_VECTOR;
+}
+
+bool last_cylic_segment_is_vector(const Span<int8_t> handle_types_left,
+ const Span<int8_t> handle_types_right)
+{
+ return handle_types_right.last() == BEZIER_HANDLE_VECTOR &&
+ handle_types_left.first() == BEZIER_HANDLE_VECTOR;
+}
+
+void calculate_evaluated_offsets(const Span<int8_t> handle_types_left,
+ const Span<int8_t> handle_types_right,
+ const bool cyclic,
+ const int resolution,
+ MutableSpan<int> evaluated_offsets)
+{
+ const int size = handle_types_left.size();
+ BLI_assert(evaluated_offsets.size() == size);
+
+ if (size == 1) {
+ evaluated_offsets.first() = 1;
+ return;
+ }
+
+ int offset = 0;
+
+ for (const int i : IndexRange(size - 1)) {
+ offset += segment_is_vector(handle_types_left, handle_types_right, i) ? 1 : resolution;
+ evaluated_offsets[i] = offset;
+ }
+
+ if (cyclic) {
+ offset += last_cylic_segment_is_vector(handle_types_left, handle_types_right) ? 1 : resolution;
+ }
+ else {
+ offset++;
+ }
+
+ evaluated_offsets.last() = offset;
+}
+
+void evaluate_segment(const float3 &point_0,
+ const float3 &point_1,
+ const float3 &point_2,
+ const float3 &point_3,
+ MutableSpan<float3> result)
+{
+ BLI_assert(result.size() > 0);
+ const float inv_len = 1.0f / static_cast<float>(result.size());
+ const float inv_len_squared = inv_len * inv_len;
+ const float inv_len_cubed = inv_len_squared * inv_len;
+
+ const float3 rt1 = 3.0f * (point_1 - point_0) * inv_len;
+ const float3 rt2 = 3.0f * (point_0 - 2.0f * point_1 + point_2) * inv_len_squared;
+ const float3 rt3 = (point_3 - point_0 + 3.0f * (point_1 - point_2)) * inv_len_cubed;
+
+ float3 q0 = point_0;
+ float3 q1 = rt1 + rt2 + rt3;
+ float3 q2 = 2.0f * rt2 + 6.0f * rt3;
+ float3 q3 = 6.0f * rt3;
+ for (const int i : result.index_range()) {
+ result[i] = q0;
+ q0 += q1;
+ q1 += q2;
+ q2 += q3;
+ }
+}
+
+void calculate_evaluated_positions(const Span<float3> positions,
+ const Span<float3> handles_left,
+ const Span<float3> handles_right,
+ const Span<int> evaluated_offsets,
+ MutableSpan<float3> evaluated_positions)
+{
+ BLI_assert(evaluated_offsets.last() == evaluated_positions.size());
+ BLI_assert(evaluated_offsets.size() == positions.size());
+
+ /* Evaluate the first segment. */
+ evaluate_segment(positions.first(),
+ handles_right.first(),
+ handles_left[1],
+ positions[1],
+ evaluated_positions.take_front(evaluated_offsets.first()));
+
+ /* Give each task fewer segments as the resolution gets larger. */
+ const int grain_size = std::max<int>(evaluated_positions.size() / positions.size() * 32, 1);
+ threading::parallel_for(
+ positions.index_range().drop_back(1).drop_front(1), grain_size, [&](IndexRange range) {
+ for (const int i : range) {
+ const IndexRange evaluated_range = offsets_to_range(evaluated_offsets, i - 1);
+ if (evaluated_range.size() == 1) {
+ evaluated_positions[evaluated_range.first()] = positions[i];
+ }
+ else {
+ evaluate_segment(positions[i],
+ handles_right[i],
+ handles_left[i + 1],
+ positions[i + 1],
+ evaluated_positions.slice(evaluated_range));
+ }
+ }
+ });
+
+ /* Evaluate the final cyclic segment if necessary. */
+ const IndexRange last_segment_points = offsets_to_range(evaluated_offsets, positions.size() - 2);
+ if (last_segment_points.size() == 1) {
+ evaluated_positions.last() = positions.last();
+ }
+ else {
+ evaluate_segment(positions.last(),
+ handles_right.last(),
+ handles_left.first(),
+ positions.first(),
+ evaluated_positions.slice(last_segment_points));
+ }
+}
+
+/** \} */
+
+} // namespace blender::bke::curves::bezier
diff --git a/source/blender/blenkernel/intern/curve_catmull_rom.cc b/source/blender/blenkernel/intern/curve_catmull_rom.cc
new file mode 100644
index 00000000000..ea3672dd56b
--- /dev/null
+++ b/source/blender/blenkernel/intern/curve_catmull_rom.cc
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
+
+namespace blender::bke::curves::catmull_rom {
+
+int calculate_evaluated_size(const int points_num, const bool cyclic, const int resolution)
+{
+ const int eval_size = resolution * curve_segment_size(points_num, cyclic);
+ /* If the curve isn't cyclic, one last point is added to the final point. */
+ return (cyclic && points_num > 2) ? eval_size : eval_size + 1;
+}
+
+/* Adapted from Cycles #catmull_rom_basis_eval function. */
+template<typename T>
+static T calculate_basis(const T &a, const T &b, const T &c, const T &d, const float parameter)
+{
+ const float t = parameter;
+ const float s = 1.0f - parameter;
+ const float n0 = -t * s * s;
+ const float n1 = 2.0f + t * t * (3.0f * t - 5.0f);
+ const float n2 = 2.0f + s * s * (3.0f * s - 5.0f);
+ const float n3 = -s * t * t;
+ return 0.5f * (a * n0 + b * n1 + c * n2 + d * n3);
+}
+
+template<typename T>
+static void evaluate_segment(const T &a, const T &b, const T &c, const T &d, MutableSpan<T> dst)
+{
+ const float step = 1.0f / dst.size();
+ dst.first() = b;
+ for (const int i : dst.index_range().drop_front(1)) {
+ dst[i] = calculate_basis<T>(a, b, c, d, i * step);
+ }
+}
+
+template<typename T>
+static void interpolate_to_evaluated(const Span<T> src,
+ const bool cyclic,
+ const int resolution,
+ MutableSpan<T> dst)
+
+{
+ BLI_assert(dst.size() == calculate_evaluated_size(src.size(), cyclic, resolution));
+
+ /* - First deal with one and two point curves need special attention.
+ * - Then evaluate the first and last segment(s) whose control points need to wrap around
+ * to the other side of the source array.
+ * - Finally evaluate all of the segments in the middle in parallel. */
+
+ if (src.size() == 1) {
+ dst.first() = src.first();
+ return;
+ }
+ if (src.size() == 2) {
+ evaluate_segment(src.first(), src.first(), src.last(), src.last(), dst);
+ dst.last() = src.last();
+ return;
+ }
+
+ if (cyclic) {
+ /* The first segment. */
+ evaluate_segment(src.last(), src[0], src[1], src[2], dst.take_front(resolution));
+ /* The second-to-last segment. */
+ evaluate_segment(src.last(2),
+ src.last(1),
+ src.last(),
+ src.first(),
+ dst.take_back(resolution * 2).drop_back(resolution));
+ /* The last segment. */
+ evaluate_segment(src.last(1), src.last(), src[0], src[1], dst.take_back(resolution));
+ }
+ else {
+ /* The first segment. */
+ evaluate_segment(src[0], src[0], src[1], src[2], dst.take_front(resolution));
+ /* The last segment. */
+ evaluate_segment(
+ src.last(2), src.last(1), src.last(), src.last(), dst.drop_back(1).take_back(resolution));
+ /* The final point of the last segment. */
+ dst.last() = src.last();
+ }
+
+ /* Evaluate every segment that isn't the first or last. */
+ const int grain_size = std::max(512 / resolution, 1);
+ const IndexRange inner_range = src.index_range().drop_back(2).drop_front(1);
+ threading::parallel_for(inner_range, grain_size, [&](IndexRange range) {
+ for (const int i : range) {
+ const IndexRange segment_range(resolution * i, resolution);
+ evaluate_segment(src[i - 1], src[i], src[i + 1], src[i + 2], dst.slice(segment_range));
+ }
+ });
+}
+
+void interpolate_to_evaluated(const GSpan src,
+ const bool cyclic,
+ const int resolution,
+ GMutableSpan dst)
+{
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ /* TODO: Use DefaultMixer or other generic mixing in the basis evaluation function to simplify
+ * supporting more types. */
+ if constexpr (is_same_any_v<T, float, float2, float3, float4, int8_t, int, int64_t>) {
+ interpolate_to_evaluated(src.typed<T>(), cyclic, resolution, dst.typed<T>());
+ }
+ });
+}
+
+} // namespace blender::bke::curves::catmull_rom
diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index 191a510947e..2cf83b57881 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -20,6 +20,8 @@
using blender::Array;
using blender::float3;
using blender::float4x4;
+using blender::GVArray;
+using blender::GVArray_GSpan;
using blender::IndexRange;
using blender::Map;
using blender::MutableSpan;
@@ -32,8 +34,6 @@ using blender::bke::AttributeIDRef;
using blender::bke::OutputAttribute;
using blender::bke::OutputAttribute_Typed;
using blender::bke::ReadAttributeLookup;
-using blender::fn::GVArray;
-using blender::fn::GVArray_GSpan;
blender::Span<SplinePtr> CurveEval::splines() const
{
@@ -398,7 +398,7 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves)
VArray<int8_t> curve_types = geometry.curve_types();
std::unique_ptr<CurveEval> curve_eval = std::make_unique<CurveEval>();
for (const int curve_index : curve_types.index_range()) {
- const IndexRange point_range = geometry.range_for_curve(curve_index);
+ const IndexRange point_range = geometry.points_for_curve(curve_index);
std::unique_ptr<Spline> spline;
switch (curve_types[curve_index]) {
@@ -489,7 +489,7 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
const Spline &spline = *curve_eval.splines()[curve_index];
curve_types[curve_index] = curve_eval.splines()[curve_index]->type();
- const IndexRange point_range = geometry.range_for_curve(curve_index);
+ const IndexRange point_range = geometry.points_for_curve(curve_index);
switch (spline.type()) {
case CURVE_TYPE_POLY:
diff --git a/source/blender/blenkernel/intern/curve_nurbs.cc b/source/blender/blenkernel/intern/curve_nurbs.cc
new file mode 100644
index 00000000000..0114c0b45f4
--- /dev/null
+++ b/source/blender/blenkernel/intern/curve_nurbs.cc
@@ -0,0 +1,251 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BKE_attribute_math.hh"
+
+#include "BKE_curves.hh"
+
+namespace blender::bke::curves::nurbs {
+
+bool check_valid_size_and_order(const int points_num,
+ const int8_t order,
+ const bool cyclic,
+ const KnotsMode knots_mode)
+{
+ if (points_num < order) {
+ return false;
+ }
+
+ if (ELEM(knots_mode, NURBS_KNOT_MODE_BEZIER, NURBS_KNOT_MODE_ENDPOINT_BEZIER)) {
+ if (knots_mode == NURBS_KNOT_MODE_BEZIER && points_num <= order) {
+ return false;
+ }
+ return (!cyclic || points_num % (order - 1) == 0);
+ }
+
+ return true;
+}
+
+int calculate_evaluated_size(const int points_num,
+ const int8_t order,
+ const bool cyclic,
+ const int resolution,
+ const KnotsMode knots_mode)
+{
+ if (!check_valid_size_and_order(points_num, order, cyclic, knots_mode)) {
+ return 0;
+ }
+ return resolution * curve_segment_size(points_num, cyclic);
+}
+
+int knots_size(const int points_num, const int8_t order, const bool cyclic)
+{
+ if (cyclic) {
+ return points_num + order * 2 - 1;
+ }
+ return points_num + order;
+}
+
+void calculate_knots(const int points_num,
+ const KnotsMode mode,
+ const int8_t order,
+ const bool cyclic,
+ MutableSpan<float> knots)
+{
+ BLI_assert(knots.size() == knots_size(points_num, order, cyclic));
+ UNUSED_VARS_NDEBUG(points_num);
+
+ const bool is_bezier = ELEM(mode, NURBS_KNOT_MODE_BEZIER, NURBS_KNOT_MODE_ENDPOINT_BEZIER);
+ const bool is_end_point = ELEM(mode, NURBS_KNOT_MODE_ENDPOINT, NURBS_KNOT_MODE_ENDPOINT_BEZIER);
+ /* Inner knots are always repeated once except on Bezier case. */
+ const int repeat_inner = is_bezier ? order - 1 : 1;
+ /* How many times to repeat 0.0 at the beginning of knot. */
+ const int head = is_end_point ? (order - (cyclic ? 1 : 0)) :
+ (is_bezier ? min_ii(2, repeat_inner) : 1);
+ /* Number of knots replicating widths of the starting knots.
+ * Covers both Cyclic and EndPoint cases. */
+ const int tail = cyclic ? 2 * order - 1 : (is_end_point ? order : 0);
+
+ int r = head;
+ float current = 0.0f;
+
+ const int offset = is_end_point && cyclic ? 1 : 0;
+ if (offset) {
+ knots[0] = current;
+ current += 1.0f;
+ }
+
+ for (const int i : IndexRange(offset, knots.size() - offset - tail)) {
+ knots[i] = current;
+ r--;
+ if (r == 0) {
+ current += 1.0;
+ r = repeat_inner;
+ }
+ }
+
+ const int tail_index = knots.size() - tail;
+ for (const int i : IndexRange(tail)) {
+ knots[tail_index + i] = current + (knots[i] - knots[0]);
+ }
+}
+
+static void calculate_basis_for_point(const float parameter,
+ const int points_num,
+ const int degree,
+ const Span<float> knots,
+ MutableSpan<float> r_weights,
+ int &r_start_index)
+{
+ const int order = degree + 1;
+
+ int start = 0;
+ int end = 0;
+ for (const int i : IndexRange(points_num + degree)) {
+ const bool knots_equal = knots[i] == knots[i + 1];
+ if (knots_equal || parameter < knots[i] || parameter > knots[i + 1]) {
+ continue;
+ }
+
+ start = std::max(i - degree, 0);
+ end = i;
+ break;
+ }
+
+ Array<float, 12> buffer(order * 2, 0.0f);
+
+ buffer[end - start] = 1.0f;
+
+ for (const int i_order : IndexRange(2, degree)) {
+ if (end + i_order >= knots.size()) {
+ end = points_num + degree - i_order;
+ }
+ for (const int i : IndexRange(end - start + 1)) {
+ const int knot_index = start + i;
+
+ float new_basis = 0.0f;
+ if (buffer[i] != 0.0f) {
+ new_basis += ((parameter - knots[knot_index]) * buffer[i]) /
+ (knots[knot_index + i_order - 1] - knots[knot_index]);
+ }
+
+ if (buffer[i + 1] != 0.0f) {
+ new_basis += ((knots[knot_index + i_order] - parameter) * buffer[i + 1]) /
+ (knots[knot_index + i_order] - knots[knot_index + 1]);
+ }
+
+ buffer[i] = new_basis;
+ }
+ }
+
+ buffer.as_mutable_span().drop_front(end - start + 1).fill(0.0f);
+ r_weights.copy_from(buffer.as_span().take_front(order));
+ r_start_index = start;
+}
+
+void calculate_basis_cache(const int points_num,
+ const int evaluated_size,
+ const int8_t order,
+ const bool cyclic,
+ const Span<float> knots,
+ BasisCache &basis_cache)
+{
+ BLI_assert(points_num > 0);
+
+ const int8_t degree = order - 1;
+
+ basis_cache.weights.resize(evaluated_size * order);
+ basis_cache.start_indices.resize(evaluated_size);
+
+ if (evaluated_size == 0) {
+ return;
+ }
+
+ MutableSpan<float> basis_weights(basis_cache.weights);
+ MutableSpan<int> basis_start_indices(basis_cache.start_indices);
+
+ const int last_control_point_index = cyclic ? points_num + degree : points_num;
+ const int evaluated_segment_size = curve_segment_size(evaluated_size, cyclic);
+
+ const float start = knots[degree];
+ const float end = knots[last_control_point_index];
+ const float step = (end - start) / evaluated_segment_size;
+ for (const int i : IndexRange(evaluated_size)) {
+ /* Clamp parameter due to floating point inaccuracy. */
+ const float parameter = std::clamp(start + step * i, knots[0], knots[points_num + degree]);
+
+ MutableSpan<float> point_weights = basis_weights.slice(i * order, order);
+
+ calculate_basis_for_point(
+ parameter, last_control_point_index, degree, knots, point_weights, basis_start_indices[i]);
+ }
+}
+
+template<typename T>
+static void interpolate_to_evaluated(const BasisCache &basis_cache,
+ const int8_t order,
+ const Span<T> src,
+ MutableSpan<T> dst)
+{
+ attribute_math::DefaultMixer<T> mixer{dst};
+
+ for (const int i : dst.index_range()) {
+ Span<float> point_weights = basis_cache.weights.as_span().slice(i * order, order);
+
+ for (const int j : point_weights.index_range()) {
+ const int point_index = (basis_cache.start_indices[i] + j) % src.size();
+ mixer.mix_in(i, src[point_index], point_weights[j]);
+ }
+ }
+
+ mixer.finalize();
+}
+
+template<typename T>
+static void interpolate_to_evaluated_rational(const BasisCache &basis_cache,
+ const int8_t order,
+ const Span<float> control_weights,
+ const Span<T> src,
+ MutableSpan<T> dst)
+{
+ attribute_math::DefaultMixer<T> mixer{dst};
+
+ for (const int i : dst.index_range()) {
+ Span<float> point_weights = basis_cache.weights.as_span().slice(i * order, order);
+
+ for (const int j : point_weights.index_range()) {
+ const int point_index = (basis_cache.start_indices[i] + j) % src.size();
+ const float weight = point_weights[j] * control_weights[point_index];
+ mixer.mix_in(i, src[point_index], weight);
+ }
+ }
+
+ mixer.finalize();
+}
+
+void interpolate_to_evaluated(const BasisCache &basis_cache,
+ const int8_t order,
+ const Span<float> control_weights,
+ const GSpan src,
+ GMutableSpan dst)
+{
+ BLI_assert(dst.size() == basis_cache.start_indices.size());
+
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
+ if (control_weights.is_empty()) {
+ interpolate_to_evaluated(basis_cache, order, src.typed<T>(), dst.typed<T>());
+ }
+ else {
+ interpolate_to_evaluated_rational(
+ basis_cache, order, control_weights, src.typed<T>(), dst.typed<T>());
+ }
+ }
+ });
+}
+
+} // namespace blender::bke::curves::nurbs
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index 5d80ef47908..9b22a4c9726 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -16,9 +16,6 @@
#include "BKE_curve_to_mesh.hh"
-using blender::fn::GMutableSpan;
-using blender::fn::GSpan;
-
namespace blender::bke {
/** Information about the creation of one curve spline and profile spline combination. */
diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc
index 838f7f28e93..82db1176759 100644
--- a/source/blender/blenkernel/intern/curves.cc
+++ b/source/blender/blenkernel/intern/curves.cc
@@ -366,19 +366,19 @@ void BKE_curves_batch_cache_free(Curves *curves)
namespace blender::bke {
-Curves *curves_new_nomain(const int point_size, const int curves_size)
+Curves *curves_new_nomain(const int points_num, const int curves_num)
{
Curves *curves = static_cast<Curves *>(BKE_id_new_nomain(ID_CV, nullptr));
CurvesGeometry &geometry = CurvesGeometry::wrap(curves->geometry);
- geometry.resize(point_size, curves_size);
+ geometry.resize(points_num, curves_num);
return curves;
}
-Curves *curves_new_nomain_single(const int point_size, const CurveType type)
+Curves *curves_new_nomain_single(const int points_num, const CurveType type)
{
- Curves *curves = curves_new_nomain(point_size, 1);
+ Curves *curves = curves_new_nomain(points_num, 1);
CurvesGeometry &geometry = CurvesGeometry::wrap(curves->geometry);
- geometry.offsets().last() = point_size;
+ geometry.offsets().last() = points_num;
geometry.curve_types().first() = type;
return curves;
}
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index dd91e788e5a..5bb6a97fa49 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -4,9 +4,13 @@
* \ingroup bke
*/
+#include <mutex>
+#include <utility>
+
#include "MEM_guardedalloc.h"
#include "BLI_bounds.hh"
+#include "BLI_index_mask_ops.hh"
#include "DNA_curves_types.h"
@@ -19,6 +23,16 @@ static const std::string ATTR_POSITION = "position";
static const std::string ATTR_RADIUS = "radius";
static const std::string ATTR_CURVE_TYPE = "curve_type";
static const std::string ATTR_CYCLIC = "cyclic";
+static const std::string ATTR_RESOLUTION = "resolution";
+static const std::string ATTR_HANDLE_TYPE_LEFT = "handle_type_left";
+static const std::string ATTR_HANDLE_TYPE_RIGHT = "handle_type_right";
+static const std::string ATTR_HANDLE_POSITION_LEFT = "handle_left";
+static const std::string ATTR_HANDLE_POSITION_RIGHT = "handle_right";
+static const std::string ATTR_NURBS_ORDER = "nurbs_order";
+static const std::string ATTR_NURBS_WEIGHT = "nurbs_weight";
+static const std::string ATTR_NURBS_KNOTS_MODE = "knots_mode";
+static const std::string ATTR_SURFACE_TRIANGLE_INDEX = "surface_triangle_index";
+static const std::string ATTR_SURFACE_TRIANGLE_COORDINATE = "surface_triangle_coordinate";
/* -------------------------------------------------------------------- */
/** \name Constructors/Destructor
@@ -135,30 +149,24 @@ CurvesGeometry::~CurvesGeometry()
/** \name Accessors
* \{ */
-int CurvesGeometry::points_size() const
+int CurvesGeometry::points_num() const
{
return this->point_size;
}
-int CurvesGeometry::curves_size() const
+int CurvesGeometry::curves_num() const
{
return this->curve_size;
}
IndexRange CurvesGeometry::points_range() const
{
- return IndexRange(this->points_size());
+ return IndexRange(this->points_num());
}
IndexRange CurvesGeometry::curves_range() const
{
- return IndexRange(this->curves_size());
-}
-
-int CurvesGeometry::evaluated_points_size() const
-{
- /* TODO: Implement when there are evaluated points. */
- return 0;
+ return IndexRange(this->curves_num());
}
-IndexRange CurvesGeometry::range_for_curve(const int index) const
+IndexRange CurvesGeometry::points_for_curve(const int index) const
{
BLI_assert(this->curve_size > 0);
BLI_assert(this->curve_offsets != nullptr);
@@ -167,7 +175,7 @@ IndexRange CurvesGeometry::range_for_curve(const int index) const
return {offset, offset_next - offset};
}
-IndexRange CurvesGeometry::range_for_curves(const IndexRange curves) const
+IndexRange CurvesGeometry::points_for_curves(const IndexRange curves) const
{
BLI_assert(this->curve_size > 0);
BLI_assert(this->curve_offsets != nullptr);
@@ -178,7 +186,7 @@ IndexRange CurvesGeometry::range_for_curves(const IndexRange curves) const
static int domain_size(const CurvesGeometry &curves, const AttributeDomain domain)
{
- return domain == ATTR_DOMAIN_POINT ? curves.points_size() : curves.curves_size();
+ return domain == ATTR_DOMAIN_POINT ? curves.points_num() : curves.curves_num();
}
static CustomData &domain_custom_data(CurvesGeometry &curves, const AttributeDomain domain)
@@ -210,6 +218,22 @@ static VArray<T> get_varray_attribute(const CurvesGeometry &curves,
}
template<typename T>
+static Span<T> get_span_attribute(const CurvesGeometry &curves,
+ const AttributeDomain domain,
+ const StringRefNull name)
+{
+ const int size = domain_size(curves, domain);
+ const CustomData &custom_data = domain_custom_data(curves, domain);
+ const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
+
+ T *data = (T *)CustomData_get_layer_named(&custom_data, type, name.c_str());
+ if (data == nullptr) {
+ return {};
+ }
+ return {data, size};
+}
+
+template<typename T>
static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves,
const AttributeDomain domain,
const StringRefNull name)
@@ -239,6 +263,20 @@ MutableSpan<int8_t> CurvesGeometry::curve_types()
return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_CURVE_TYPE);
}
+bool CurvesGeometry::has_curve_with_type(const CurveType type) const
+{
+ const VArray<int8_t> curve_types = this->curve_types();
+ if (curve_types.is_single()) {
+ return curve_types.get_internal_single() == type;
+ }
+ if (curve_types.is_span()) {
+ return curve_types.get_internal_span().contains(type);
+ }
+ /* The curves types array should be a single value or a span. */
+ BLI_assert_unreachable();
+ return false;
+}
+
MutableSpan<float3> CurvesGeometry::positions()
{
this->position = (float(*)[3])CustomData_duplicate_referenced_layer_named(
@@ -269,16 +307,370 @@ MutableSpan<bool> CurvesGeometry::cyclic()
return get_mutable_attribute<bool>(*this, ATTR_DOMAIN_CURVE, ATTR_CYCLIC);
}
-void CurvesGeometry::resize(const int point_size, const int curve_size)
+VArray<int> CurvesGeometry::resolution() const
+{
+ return get_varray_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_RESOLUTION, 12);
+}
+
+MutableSpan<int> CurvesGeometry::resolution()
+{
+ return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_RESOLUTION);
+}
+
+VArray<int8_t> CurvesGeometry::handle_types_left() const
+{
+ return get_varray_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_LEFT, 0);
+}
+MutableSpan<int8_t> CurvesGeometry::handle_types_left()
+{
+ return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_LEFT);
+}
+
+VArray<int8_t> CurvesGeometry::handle_types_right() const
+{
+ return get_varray_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_RIGHT, 0);
+}
+MutableSpan<int8_t> CurvesGeometry::handle_types_right()
+{
+ return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_RIGHT);
+}
+
+Span<float3> CurvesGeometry::handle_positions_left() const
+{
+ return get_span_attribute<float3>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_POSITION_LEFT);
+}
+MutableSpan<float3> CurvesGeometry::handle_positions_left()
+{
+ return get_mutable_attribute<float3>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_POSITION_LEFT);
+}
+
+Span<float3> CurvesGeometry::handle_positions_right() const
+{
+ return get_span_attribute<float3>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_POSITION_RIGHT);
+}
+MutableSpan<float3> CurvesGeometry::handle_positions_right()
+{
+ return get_mutable_attribute<float3>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_POSITION_RIGHT);
+}
+
+VArray<int8_t> CurvesGeometry::nurbs_orders() const
+{
+ return get_varray_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_ORDER, 4);
+}
+MutableSpan<int8_t> CurvesGeometry::nurbs_orders()
+{
+ return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_ORDER);
+}
+
+Span<float> CurvesGeometry::nurbs_weights() const
+{
+ return get_span_attribute<float>(*this, ATTR_DOMAIN_POINT, ATTR_NURBS_WEIGHT);
+}
+MutableSpan<float> CurvesGeometry::nurbs_weights()
+{
+ return get_mutable_attribute<float>(*this, ATTR_DOMAIN_POINT, ATTR_NURBS_WEIGHT);
+}
+
+VArray<int8_t> CurvesGeometry::nurbs_knots_modes() const
+{
+ return get_varray_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_KNOTS_MODE, 0);
+}
+MutableSpan<int8_t> CurvesGeometry::nurbs_knots_modes()
+{
+ return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_KNOTS_MODE);
+}
+
+VArray<int> CurvesGeometry::surface_triangle_indices() const
+{
+ return get_varray_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX, -1);
+}
+
+MutableSpan<int> CurvesGeometry::surface_triangle_indices()
+{
+ return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX);
+}
+
+Span<float2> CurvesGeometry::surface_triangle_coords() const
+{
+ return get_span_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_COORDINATE);
+}
+
+MutableSpan<float2> CurvesGeometry::surface_triangle_coords()
+{
+ return get_mutable_attribute<float2>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_COORDINATE);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Evaluation
+ * \{ */
+
+template<typename SizeFn> void build_offsets(MutableSpan<int> offsets, const SizeFn &size_fn)
+{
+ int offset = 0;
+ for (const int i : offsets.drop_back(1).index_range()) {
+ offsets[i] = offset;
+ offset += size_fn(i);
+ }
+ offsets.last() = offset;
+}
+
+static void calculate_evaluated_offsets(const CurvesGeometry &curves,
+ MutableSpan<int> offsets,
+ MutableSpan<int> bezier_evaluated_offsets)
+{
+ VArray<int8_t> types = curves.curve_types();
+ VArray<int> resolution = curves.resolution();
+ VArray<bool> cyclic = curves.cyclic();
+
+ VArray_Span<int8_t> handle_types_left{curves.handle_types_left()};
+ VArray_Span<int8_t> handle_types_right{curves.handle_types_right()};
+
+ VArray<int8_t> nurbs_orders = curves.nurbs_orders();
+ VArray<int8_t> nurbs_knots_modes = curves.nurbs_knots_modes();
+
+ build_offsets(offsets, [&](const int curve_index) -> int {
+ const IndexRange points = curves.points_for_curve(curve_index);
+ switch (types[curve_index]) {
+ case CURVE_TYPE_CATMULL_ROM:
+ return curves::catmull_rom::calculate_evaluated_size(
+ points.size(), cyclic[curve_index], resolution[curve_index]);
+ case CURVE_TYPE_POLY:
+ return points.size();
+ case CURVE_TYPE_BEZIER:
+ curves::bezier::calculate_evaluated_offsets(handle_types_left.slice(points),
+ handle_types_right.slice(points),
+ cyclic[curve_index],
+ resolution[curve_index],
+ bezier_evaluated_offsets.slice(points));
+ return bezier_evaluated_offsets[points.last()];
+ case CURVE_TYPE_NURBS:
+ return curves::nurbs::calculate_evaluated_size(points.size(),
+ nurbs_orders[curve_index],
+ cyclic[curve_index],
+ resolution[curve_index],
+ KnotsMode(nurbs_knots_modes[curve_index]));
+ }
+ BLI_assert_unreachable();
+ return 0;
+ });
+}
+
+int CurvesGeometry::evaluated_points_num() const
+{
+ /* This could avoid calculating offsets in the future in simple circumstances. */
+ return this->evaluated_offsets().last();
+}
+
+IndexRange CurvesGeometry::evaluated_points_for_curve(int index) const
+{
+ BLI_assert(!this->runtime->offsets_cache_dirty);
+ return offsets_to_range(this->runtime->evaluated_offsets_cache.as_span(), index);
+}
+
+IndexRange CurvesGeometry::evaluated_points_for_curves(const IndexRange curves) const
+{
+ BLI_assert(!this->runtime->offsets_cache_dirty);
+ BLI_assert(this->curve_size > 0);
+ const int offset = this->runtime->evaluated_offsets_cache[curves.start()];
+ const int offset_next = this->runtime->evaluated_offsets_cache[curves.one_after_last()];
+ return {offset, offset_next - offset};
+}
+
+void CurvesGeometry::ensure_evaluated_offsets() const
{
- if (point_size != this->point_size) {
- CustomData_realloc(&this->point_data, point_size);
- this->point_size = point_size;
+ if (!this->runtime->offsets_cache_dirty) {
+ return;
}
- if (curve_size != this->curve_size) {
- CustomData_realloc(&this->curve_data, curve_size);
- this->curve_size = curve_size;
- this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curve_size + 1));
+
+ /* A double checked lock. */
+ std::scoped_lock lock{this->runtime->offsets_cache_mutex};
+ if (!this->runtime->offsets_cache_dirty) {
+ return;
+ }
+
+ threading::isolate_task([&]() {
+ this->runtime->evaluated_offsets_cache.resize(this->curves_num() + 1);
+
+ if (this->has_curve_with_type(CURVE_TYPE_BEZIER)) {
+ this->runtime->bezier_evaluated_offsets.resize(this->points_num());
+ }
+ else {
+ this->runtime->bezier_evaluated_offsets.clear_and_make_inline();
+ }
+
+ calculate_evaluated_offsets(
+ *this, this->runtime->evaluated_offsets_cache, this->runtime->bezier_evaluated_offsets);
+ });
+
+ this->runtime->offsets_cache_dirty = false;
+}
+
+Span<int> CurvesGeometry::evaluated_offsets() const
+{
+ this->ensure_evaluated_offsets();
+ return this->runtime->evaluated_offsets_cache;
+}
+
+IndexMask CurvesGeometry::indices_for_curve_type(const CurveType type,
+ Vector<int64_t> &r_indices) const
+{
+
+ VArray<int8_t> types = this->curve_types();
+ if (types.is_single()) {
+ if (types.get_internal_single() == type) {
+ return IndexMask(types.size());
+ }
+ return {};
+ }
+ Span<int8_t> types_span = types.get_internal_span();
+ return index_mask_ops::find_indices_based_on_predicate(
+ IndexMask(types.size()), 1024, r_indices, [&](const int index) {
+ return types_span[index] == type;
+ });
+}
+
+void CurvesGeometry::ensure_nurbs_basis_cache() const
+{
+ if (!this->runtime->nurbs_basis_cache_dirty) {
+ return;
+ }
+
+ /* A double checked lock. */
+ std::scoped_lock lock{this->runtime->nurbs_basis_cache_mutex};
+ if (!this->runtime->nurbs_basis_cache_dirty) {
+ return;
+ }
+
+ threading::isolate_task([&]() {
+ Vector<int64_t> nurbs_indices;
+ const IndexMask nurbs_mask = this->indices_for_curve_type(CURVE_TYPE_NURBS, nurbs_indices);
+ if (nurbs_mask.is_empty()) {
+ return;
+ }
+
+ this->runtime->nurbs_basis_cache.resize(this->curves_num());
+ MutableSpan<curves::nurbs::BasisCache> basis_caches(this->runtime->nurbs_basis_cache);
+
+ VArray<bool> cyclic = this->cyclic();
+ VArray<int8_t> orders = this->nurbs_orders();
+ VArray<int8_t> knots_modes = this->nurbs_knots_modes();
+
+ threading::parallel_for(nurbs_mask.index_range(), 64, [&](const IndexRange range) {
+ for (const int curve_index : nurbs_mask.slice(range)) {
+ const IndexRange points = this->points_for_curve(curve_index);
+ const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
+
+ const int8_t order = orders[curve_index];
+ const bool is_cyclic = cyclic[curve_index];
+ const KnotsMode mode = KnotsMode(knots_modes[curve_index]);
+
+ const int knots_size = curves::nurbs::knots_size(points.size(), order, is_cyclic);
+ Array<float> knots(knots_size);
+ curves::nurbs::calculate_knots(points.size(), mode, order, is_cyclic, knots);
+ curves::nurbs::calculate_basis_cache(points.size(),
+ evaluated_points.size(),
+ order,
+ is_cyclic,
+ knots,
+ basis_caches[curve_index]);
+ }
+ });
+ });
+
+ this->runtime->nurbs_basis_cache_dirty = false;
+}
+
+Span<float3> CurvesGeometry::evaluated_positions() const
+{
+ if (!this->runtime->position_cache_dirty) {
+ return this->runtime->evaluated_position_cache;
+ }
+
+ /* A double checked lock. */
+ std::scoped_lock lock{this->runtime->position_cache_mutex};
+ if (!this->runtime->position_cache_dirty) {
+ return this->runtime->evaluated_position_cache;
+ }
+
+ threading::isolate_task([&]() {
+ this->runtime->evaluated_position_cache.resize(this->evaluated_points_num());
+ MutableSpan<float3> evaluated_positions = this->runtime->evaluated_position_cache;
+
+ VArray<int8_t> types = this->curve_types();
+ VArray<bool> cyclic = this->cyclic();
+ VArray<int> resolution = this->resolution();
+ Span<float3> positions = this->positions();
+
+ Span<float3> handle_positions_left = this->handle_positions_left();
+ Span<float3> handle_positions_right = this->handle_positions_right();
+ Span<int> bezier_evaluated_offsets = this->runtime->bezier_evaluated_offsets;
+
+ VArray<int8_t> nurbs_orders = this->nurbs_orders();
+ Span<float> nurbs_weights = this->nurbs_weights();
+
+ this->ensure_nurbs_basis_cache();
+
+ threading::parallel_for(this->curves_range(), 128, [&](IndexRange curves_range) {
+ for (const int curve_index : curves_range) {
+ const IndexRange points = this->points_for_curve(curve_index);
+ const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
+
+ switch (types[curve_index]) {
+ case CURVE_TYPE_CATMULL_ROM:
+ curves::catmull_rom::interpolate_to_evaluated(
+ positions.slice(points),
+ cyclic[curve_index],
+ resolution[curve_index],
+ evaluated_positions.slice(evaluated_points));
+ break;
+ case CURVE_TYPE_POLY:
+ evaluated_positions.slice(evaluated_points).copy_from(positions.slice(points));
+ break;
+ case CURVE_TYPE_BEZIER:
+ curves::bezier::calculate_evaluated_positions(
+ positions.slice(points),
+ handle_positions_left.slice(points),
+ handle_positions_right.slice(points),
+ bezier_evaluated_offsets.slice(points),
+ evaluated_positions.slice(evaluated_points));
+ break;
+ case CURVE_TYPE_NURBS: {
+ curves::nurbs::interpolate_to_evaluated(this->runtime->nurbs_basis_cache[curve_index],
+ nurbs_orders[curve_index],
+ nurbs_weights.slice(points),
+ positions.slice(points),
+ evaluated_positions.slice(evaluated_points));
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+ });
+ });
+
+ return this->runtime->evaluated_position_cache;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operations
+ * \{ */
+
+void CurvesGeometry::resize(const int points_num, const int curves_num)
+{
+ if (points_num != this->point_size) {
+ CustomData_realloc(&this->point_data, points_num);
+ this->point_size = points_num;
+ }
+ if (curves_num != this->curve_size) {
+ CustomData_realloc(&this->curve_data, curves_num);
+ this->curve_size = curves_num;
+ this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curves_num + 1));
}
this->tag_topology_changed();
this->update_customdata_pointers();
@@ -295,15 +687,16 @@ void CurvesGeometry::tag_topology_changed()
this->runtime->position_cache_dirty = true;
this->runtime->tangent_cache_dirty = true;
this->runtime->normal_cache_dirty = true;
+ this->runtime->offsets_cache_dirty = true;
+ this->runtime->nurbs_basis_cache_dirty = true;
}
void CurvesGeometry::tag_normals_changed()
{
this->runtime->normal_cache_dirty = true;
}
-void CurvesGeometry::translate(const float3 &translation)
+static void translate_positions(MutableSpan<float3> positions, const float3 &translation)
{
- MutableSpan<float3> positions = this->positions();
threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position += translation;
@@ -311,9 +704,8 @@ void CurvesGeometry::translate(const float3 &translation)
});
}
-void CurvesGeometry::transform(const float4x4 &matrix)
+static void transform_positions(MutableSpan<float3> positions, const float4x4 &matrix)
{
- MutableSpan<float3> positions = this->positions();
threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position = matrix * position;
@@ -321,11 +713,37 @@ void CurvesGeometry::transform(const float4x4 &matrix)
});
}
+void CurvesGeometry::translate(const float3 &translation)
+{
+ /* Use `as_const` because the non-const functions can add the handle attributes. */
+ translate_positions(this->positions(), translation);
+ if (!std::as_const(*this).handle_positions_left().is_empty()) {
+ translate_positions(this->handle_positions_left(), translation);
+ }
+ if (!std::as_const(*this).handle_positions_right().is_empty()) {
+ translate_positions(this->handle_positions_right(), translation);
+ }
+ this->tag_positions_changed();
+}
+
+void CurvesGeometry::transform(const float4x4 &matrix)
+{
+ /* Use `as_const` because the non-const functions can add the handle attributes. */
+ transform_positions(this->positions(), matrix);
+ if (!std::as_const(*this).handle_positions_left().is_empty()) {
+ transform_positions(this->handle_positions_left(), matrix);
+ }
+ if (!std::as_const(*this).handle_positions_right().is_empty()) {
+ transform_positions(this->handle_positions_right(), matrix);
+ }
+ this->tag_positions_changed();
+}
+
static std::optional<bounds::MinMaxResult<float3>> curves_bounds(const CurvesGeometry &curves)
{
Span<float3> positions = curves.positions();
if (curves.radius) {
- Span<float> radii{curves.radius, curves.points_size()};
+ Span<float> radii{curves.radius, curves.points_num()};
return bounds::min_max_with_radii(positions, radii);
}
return bounds::min_max(positions);
@@ -382,7 +800,7 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves,
new_curve_ranges.append(IndexRange(new_tot_curves, curve_range.size()));
new_tot_curves += curve_range.size();
- const IndexRange old_point_range = curves.range_for_curves(curve_range);
+ const IndexRange old_point_range = curves.points_for_curves(curve_range);
old_point_ranges.append(old_point_range);
new_point_ranges.append(IndexRange(new_tot_points, old_point_range.size()));
new_tot_points += old_point_range.size();
@@ -480,6 +898,106 @@ void CurvesGeometry::remove_curves(const IndexMask curves_to_delete)
*this = copy_with_removed_curves(*this, curves_to_delete);
}
+template<typename T>
+static void reverse_curve_point_data(const CurvesGeometry &curves,
+ const IndexMask curve_selection,
+ MutableSpan<T> data)
+{
+ threading::parallel_for(curve_selection.index_range(), 256, [&](IndexRange range) {
+ for (const int curve_i : curve_selection.slice(range)) {
+ data.slice(curves.points_for_curve(curve_i)).reverse();
+ }
+ });
+}
+
+template<typename T>
+static void reverse_swap_curve_point_data(const CurvesGeometry &curves,
+ const IndexMask curve_selection,
+ MutableSpan<T> data_a,
+ MutableSpan<T> data_b)
+{
+ threading::parallel_for(curve_selection.index_range(), 256, [&](IndexRange range) {
+ for (const int curve_i : curve_selection.slice(range)) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ MutableSpan<T> a = data_a.slice(points);
+ MutableSpan<T> b = data_b.slice(points);
+ for (const int i : IndexRange(points.size() / 2)) {
+ const int end_index = points.size() - 1 - i;
+ std::swap(a[end_index], b[i]);
+ std::swap(b[end_index], a[i]);
+ }
+ }
+ });
+}
+
+static bool layer_matches_name_and_type(const CustomDataLayer &layer,
+ const StringRef name,
+ const CustomDataType type)
+{
+ if (layer.type != type) {
+ return false;
+ }
+ return layer.name == name;
+}
+
+void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse)
+{
+ CustomData_duplicate_referenced_layers(&this->point_data, this->points_num());
+
+ /* Collect the Bezier handle attributes while iterating through the point custom data layers;
+ * they need special treatment later. */
+ MutableSpan<float3> positions_left;
+ MutableSpan<float3> positions_right;
+ MutableSpan<int8_t> types_left;
+ MutableSpan<int8_t> types_right;
+
+ for (const int layer_i : IndexRange(this->point_data.totlayer)) {
+ CustomDataLayer &layer = this->point_data.layers[layer_i];
+
+ if (positions_left.is_empty() &&
+ layer_matches_name_and_type(layer, ATTR_HANDLE_POSITION_LEFT, CD_PROP_FLOAT3)) {
+ positions_left = {static_cast<float3 *>(layer.data), this->points_num()};
+ continue;
+ }
+ if (positions_right.is_empty() &&
+ layer_matches_name_and_type(layer, ATTR_HANDLE_POSITION_RIGHT, CD_PROP_FLOAT3)) {
+ positions_right = {static_cast<float3 *>(layer.data), this->points_num()};
+ continue;
+ }
+ if (types_left.is_empty() &&
+ layer_matches_name_and_type(layer, ATTR_HANDLE_TYPE_LEFT, CD_PROP_INT8)) {
+ types_left = {static_cast<int8_t *>(layer.data), this->points_num()};
+ continue;
+ }
+ if (types_right.is_empty() &&
+ layer_matches_name_and_type(layer, ATTR_HANDLE_TYPE_RIGHT, CD_PROP_INT8)) {
+ types_right = {static_cast<int8_t *>(layer.data), this->points_num()};
+ continue;
+ }
+
+ const CustomDataType data_type = static_cast<CustomDataType>(layer.type);
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ reverse_curve_point_data<T>(
+ *this, curves_to_reverse, {static_cast<T *>(layer.data), this->points_num()});
+ });
+ }
+
+ /* In order to maintain the shape of Bezier curves, handle attributes must reverse, but also the
+ * values for the left and right must swap. Use a utility to swap and reverse at the same time,
+ * to avoid loading the attribute twice. Generally we can expect the right layer to exist when
+ * the left does, but there's no need to count on it, so check for both attributes. */
+
+ if (!positions_left.is_empty() && !positions_right.is_empty()) {
+ reverse_swap_curve_point_data(*this, curves_to_reverse, positions_left, positions_right);
+ }
+ if (!types_left.is_empty() && !types_right.is_empty()) {
+ reverse_swap_curve_point_data(*this, curves_to_reverse, types_left, types_right);
+ }
+
+ this->tag_topology_changed();
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -499,8 +1017,8 @@ static void adapt_curve_domain_point_to_curve_impl(const CurvesGeometry &curves,
MutableSpan<T> r_values)
{
attribute_math::DefaultMixer<T> mixer(r_values);
- for (const int i_curve : IndexRange(curves.curves_size())) {
- for (const int i_point : curves.range_for_curve(i_curve)) {
+ for (const int i_curve : IndexRange(curves.curves_num())) {
+ for (const int i_point : curves.points_for_curve(i_curve)) {
mixer.mix_in(i_curve, old_values[i_point]);
}
}
@@ -520,8 +1038,8 @@ void adapt_curve_domain_point_to_curve_impl(const CurvesGeometry &curves,
MutableSpan<bool> r_values)
{
r_values.fill(true);
- for (const int i_curve : IndexRange(curves.curves_size())) {
- for (const int i_point : curves.range_for_curve(i_curve)) {
+ for (const int i_curve : IndexRange(curves.curves_num())) {
+ for (const int i_point : curves.points_for_curve(i_curve)) {
if (!old_values[i_point]) {
r_values[i_curve] = false;
break;
@@ -537,7 +1055,7 @@ static GVArray adapt_curve_domain_point_to_curve(const CurvesGeometry &curves,
attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
- Array<T> values(curves.curves_size());
+ Array<T> values(curves.curves_num());
adapt_curve_domain_point_to_curve_impl<T>(curves, varray.typed<T>(), values);
new_varray = VArray<T>::ForContainer(std::move(values));
}
@@ -557,8 +1075,8 @@ static void adapt_curve_domain_curve_to_point_impl(const CurvesGeometry &curves,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
- for (const int i_curve : IndexRange(curves.curves_size())) {
- r_values.slice(curves.range_for_curve(i_curve)).fill(old_values[i_curve]);
+ for (const int i_curve : IndexRange(curves.curves_num())) {
+ r_values.slice(curves.points_for_curve(i_curve)).fill(old_values[i_curve]);
}
}
@@ -568,16 +1086,16 @@ static GVArray adapt_curve_domain_curve_to_point(const CurvesGeometry &curves,
GVArray new_varray;
attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
- Array<T> values(curves.points_size());
+ Array<T> values(curves.points_num());
adapt_curve_domain_curve_to_point_impl<T>(curves, varray.typed<T>(), values);
new_varray = VArray<T>::ForContainer(std::move(values));
});
return new_varray;
}
-fn::GVArray CurvesGeometry::adapt_domain(const fn::GVArray &varray,
- const AttributeDomain from,
- const AttributeDomain to) const
+GVArray CurvesGeometry::adapt_domain(const GVArray &varray,
+ const AttributeDomain from,
+ const AttributeDomain to) const
{
if (!varray) {
return {};
diff --git a/source/blender/blenkernel/intern/curves_geometry_test.cc b/source/blender/blenkernel/intern/curves_geometry_test.cc
index 3a43c0c8102..bc99785de1c 100644
--- a/source/blender/blenkernel/intern/curves_geometry_test.cc
+++ b/source/blender/blenkernel/intern/curves_geometry_test.cc
@@ -46,7 +46,7 @@ TEST(curves_geometry, Move)
CurvesGeometry other = std::move(curves);
/* The old curves should be empty, and the offsets are expected to be null. */
- EXPECT_EQ(curves.points_size(), 0); /* NOLINT: bugprone-use-after-move */
+ EXPECT_EQ(curves.points_num(), 0); /* NOLINT: bugprone-use-after-move */
EXPECT_EQ(curves.curve_offsets, nullptr); /* NOLINT: bugprone-use-after-move */
/* Just a basic check that the new curves work okay. */
@@ -63,4 +63,324 @@ TEST(curves_geometry, Move)
EXPECT_EQ(second_other.offsets().data(), offsets_data);
}
+TEST(curves_geometry, CatmullRomEvaluation)
+{
+ CurvesGeometry curves(4, 1);
+ curves.curve_types().fill(CURVE_TYPE_CATMULL_ROM);
+ curves.resolution().fill(12);
+ curves.offsets().last() = 4;
+ curves.cyclic().fill(false);
+
+ MutableSpan<float3> positions = curves.positions();
+ positions[0] = {1, 1, 0};
+ positions[1] = {0, 1, 0};
+ positions[2] = {0, 0, 0};
+ positions[3] = {-1, 0, 0};
+
+ Span<float3> evaluated_positions = curves.evaluated_positions();
+ static const Array<float3> result_1{{
+ {1, 1, 0},
+ {0.948495, 1.00318, 0},
+ {0.87963, 1.01157, 0},
+ {0.796875, 1.02344, 0},
+ {0.703704, 1.03704, 0},
+ {0.603588, 1.05064, 0},
+ {0.5, 1.0625, 0},
+ {0.396412, 1.07089, 0},
+ {0.296296, 1.07407, 0},
+ {0.203125, 1.07031, 0},
+ {0.12037, 1.05787, 0},
+ {0.0515046, 1.03501, 0},
+ {0, 1, 0},
+ {-0.0318287, 0.948495, 0},
+ {-0.0462963, 0.87963, 0},
+ {-0.046875, 0.796875, 0},
+ {-0.037037, 0.703704, 0},
+ {-0.0202546, 0.603588, 0},
+ {0, 0.5, 0},
+ {0.0202546, 0.396412, 0},
+ {0.037037, 0.296296, 0},
+ {0.046875, 0.203125, 0},
+ {0.0462963, 0.12037, 0},
+ {0.0318287, 0.0515046, 0},
+ {0, 0, 0},
+ {-0.0515046, -0.0350116, 0},
+ {-0.12037, -0.0578704, 0},
+ {-0.203125, -0.0703125, 0},
+ {-0.296296, -0.0740741, 0},
+ {-0.396412, -0.0708912, 0},
+ {-0.5, -0.0625, 0},
+ {-0.603588, -0.0506366, 0},
+ {-0.703704, -0.037037, 0},
+ {-0.796875, -0.0234375, 0},
+ {-0.87963, -0.0115741, 0},
+ {-0.948495, -0.00318287, 0},
+ {-1, 0, 0},
+ }};
+ for (const int i : evaluated_positions.index_range()) {
+ EXPECT_V3_NEAR(evaluated_positions[i], result_1[i], 1e-5f);
+ }
+
+ /* Changing the positions shouldn't cause the evaluated positions array to be reallocated. */
+ curves.tag_positions_changed();
+ curves.evaluated_positions();
+ EXPECT_EQ(curves.evaluated_positions().data(), evaluated_positions.data());
+
+ /* Call recalculation (which shouldn't happen because low-level accessors don't tag caches). */
+ EXPECT_EQ(evaluated_positions[12].x, 0.0f);
+ EXPECT_EQ(evaluated_positions[12].y, 1.0f);
+
+ positions[0] = {1, 0, 0};
+ positions[1] = {1, 1, 0};
+ positions[2] = {0, 1, 0};
+ positions[3] = {0, 0, 0};
+ curves.cyclic().fill(true);
+
+ /* Tag topology changed because the new cyclic value is different. */
+ curves.tag_topology_changed();
+
+ /* Retrieve the data again since the size should be larger than last time (one more segment). */
+ evaluated_positions = curves.evaluated_positions();
+ static const Array<float3> result_2{{
+ {1, 0, 0},
+ {1.03819, 0.0515046, 0},
+ {1.06944, 0.12037, 0},
+ {1.09375, 0.203125, 0},
+ {1.11111, 0.296296, 0},
+ {1.12153, 0.396412, 0},
+ {1.125, 0.5, 0},
+ {1.12153, 0.603588, 0},
+ {1.11111, 0.703704, 0},
+ {1.09375, 0.796875, 0},
+ {1.06944, 0.87963, 0},
+ {1.03819, 0.948495, 0},
+ {1, 1, 0},
+ {0.948495, 1.03819, 0},
+ {0.87963, 1.06944, 0},
+ {0.796875, 1.09375, 0},
+ {0.703704, 1.11111, 0},
+ {0.603588, 1.12153, 0},
+ {0.5, 1.125, 0},
+ {0.396412, 1.12153, 0},
+ {0.296296, 1.11111, 0},
+ {0.203125, 1.09375, 0},
+ {0.12037, 1.06944, 0},
+ {0.0515046, 1.03819, 0},
+ {0, 1, 0},
+ {-0.0381944, 0.948495, 0},
+ {-0.0694444, 0.87963, 0},
+ {-0.09375, 0.796875, 0},
+ {-0.111111, 0.703704, 0},
+ {-0.121528, 0.603588, 0},
+ {-0.125, 0.5, 0},
+ {-0.121528, 0.396412, 0},
+ {-0.111111, 0.296296, 0},
+ {-0.09375, 0.203125, 0},
+ {-0.0694444, 0.12037, 0},
+ {-0.0381944, 0.0515046, 0},
+ {0, 0, 0},
+ {0.0515046, -0.0381944, 0},
+ {0.12037, -0.0694444, 0},
+ {0.203125, -0.09375, 0},
+ {0.296296, -0.111111, 0},
+ {0.396412, -0.121528, 0},
+ {0.5, -0.125, 0},
+ {0.603588, -0.121528, 0},
+ {0.703704, -0.111111, 0},
+ {0.796875, -0.09375, 0},
+ {0.87963, -0.0694444, 0},
+ {0.948495, -0.0381944, 0},
+ }};
+ for (const int i : evaluated_positions.index_range()) {
+ EXPECT_V3_NEAR(evaluated_positions[i], result_2[i], 1e-5f);
+ }
+}
+
+TEST(curves_geometry, CatmullRomTwoPointCyclic)
+{
+ CurvesGeometry curves(2, 1);
+ curves.curve_types().fill(CURVE_TYPE_CATMULL_ROM);
+ curves.resolution().fill(12);
+ curves.offsets().last() = 2;
+ curves.cyclic().fill(true);
+
+ /* The cyclic value should be ignored when there are only two control points. There should
+ * be 12 evaluated points for the single segment and an extra for the last point. */
+ EXPECT_EQ(curves.evaluated_points_num(), 13);
+}
+
+TEST(curves_geometry, BezierPositionEvaluation)
+{
+ CurvesGeometry curves(2, 1);
+ curves.curve_types().fill(CURVE_TYPE_BEZIER);
+ curves.resolution().fill(12);
+ curves.offsets().last() = 2;
+
+ MutableSpan<float3> handles_left = curves.handle_positions_left();
+ MutableSpan<float3> handles_right = curves.handle_positions_right();
+ MutableSpan<float3> positions = curves.positions();
+ positions.first() = {-1, 0, 0};
+ positions.last() = {1, 0, 0};
+ handles_right.first() = {-0.5f, 0.5f, 0.0f};
+ handles_left.last() = {0, 0, 0};
+
+ /* Dangling handles shouldn't be used in a non-cyclic curve. */
+ handles_left.first() = {100, 100, 100};
+ handles_right.last() = {100, 100, 100};
+
+ Span<float3> evaluated_positions = curves.evaluated_positions();
+ static const Array<float3> result_1{{
+ {-1, 0, 0},
+ {-0.874711, 0.105035, 0},
+ {-0.747685, 0.173611, 0},
+ {-0.617188, 0.210937, 0},
+ {-0.481481, 0.222222, 0},
+ {-0.338831, 0.212674, 0},
+ {-0.1875, 0.1875, 0},
+ {-0.0257524, 0.15191, 0},
+ {0.148148, 0.111111, 0},
+ {0.335937, 0.0703125, 0},
+ {0.539352, 0.0347222, 0},
+ {0.760127, 0.00954859, 0},
+ {1, 0, 0},
+ }};
+ for (const int i : evaluated_positions.index_range()) {
+ EXPECT_V3_NEAR(evaluated_positions[i], result_1[i], 1e-5f);
+ }
+
+ curves.resize(4, 2);
+ curves.curve_types().fill(CURVE_TYPE_BEZIER);
+ curves.resolution().fill(9);
+ curves.offsets().last() = 4;
+ handles_left = curves.handle_positions_left();
+ handles_right = curves.handle_positions_right();
+ positions = curves.positions();
+ positions[2] = {-1, 1, 0};
+ positions[3] = {1, 1, 0};
+ handles_right[2] = {-0.5f, 1.5f, 0.0f};
+ handles_left[3] = {0, 1, 0};
+
+ /* Dangling handles shouldn't be used in a non-cyclic curve. */
+ handles_left[2] = {-100, -100, -100};
+ handles_right[3] = {-100, -100, -100};
+
+ evaluated_positions = curves.evaluated_positions();
+ EXPECT_EQ(evaluated_positions.size(), 20);
+ static const Array<float3> result_2{{
+ {-1, 0, 0},
+ {-0.832647, 0.131687, 0},
+ {-0.66118, 0.201646, 0},
+ {-0.481481, 0.222222, 0},
+ {-0.289438, 0.205761, 0},
+ {-0.0809327, 0.164609, 0},
+ {0.148148, 0.111111, 0},
+ {0.40192, 0.0576133, 0},
+ {0.684499, 0.016461, 0},
+ {1, 0, 0},
+ {-1, 1, 0},
+ {-0.832647, 1.13169, 0},
+ {-0.66118, 1.20165, 0},
+ {-0.481481, 1.22222, 0},
+ {-0.289438, 1.20576, 0},
+ {-0.0809327, 1.16461, 0},
+ {0.148148, 1.11111, 0},
+ {0.40192, 1.05761, 0},
+ {0.684499, 1.01646, 0},
+ {1, 1, 0},
+ }};
+ for (const int i : evaluated_positions.index_range()) {
+ EXPECT_V3_NEAR(evaluated_positions[i], result_2[i], 1e-5f);
+ }
+}
+
+TEST(curves_geometry, NURBSEvaluation)
+{
+ CurvesGeometry curves(4, 1);
+ curves.curve_types().fill(CURVE_TYPE_NURBS);
+ curves.resolution().fill(10);
+ curves.offsets().last() = 4;
+
+ MutableSpan<float3> positions = curves.positions();
+ positions[0] = {1, 1, 0};
+ positions[1] = {0, 1, 0};
+ positions[2] = {0, 0, 0};
+ positions[3] = {-1, 0, 0};
+
+ Span<float3> evaluated_positions = curves.evaluated_positions();
+ static const Array<float3> result_1{{
+ {0.166667, 0.833333, 0}, {0.150006, 0.815511, 0}, {0.134453, 0.796582, 0},
+ {0.119924, 0.776627, 0}, {0.106339, 0.75573, 0}, {0.0936146, 0.733972, 0},
+ {0.0816693, 0.711434, 0}, {0.0704211, 0.6882, 0}, {0.0597879, 0.66435, 0},
+ {0.0496877, 0.639968, 0}, {0.0400385, 0.615134, 0}, {0.0307584, 0.589931, 0},
+ {0.0217653, 0.564442, 0}, {0.0129772, 0.538747, 0}, {0.00431208, 0.512929, 0},
+ {-0.00431208, 0.487071, 0}, {-0.0129772, 0.461253, 0}, {-0.0217653, 0.435558, 0},
+ {-0.0307584, 0.410069, 0}, {-0.0400385, 0.384866, 0}, {-0.0496877, 0.360032, 0},
+ {-0.0597878, 0.33565, 0}, {-0.0704211, 0.3118, 0}, {-0.0816693, 0.288566, 0},
+ {-0.0936146, 0.266028, 0}, {-0.106339, 0.24427, 0}, {-0.119924, 0.223373, 0},
+ {-0.134453, 0.203418, 0}, {-0.150006, 0.184489, 0}, {-0.166667, 0.166667, 0},
+ }};
+ for (const int i : evaluated_positions.index_range()) {
+ EXPECT_V3_NEAR(evaluated_positions[i], result_1[i], 1e-5f);
+ }
+
+ /* Test a cyclic curve. */
+ curves.cyclic().fill(true);
+ curves.tag_topology_changed();
+ evaluated_positions = curves.evaluated_positions();
+ static const Array<float3> result_2{{
+ {0.166667, 0.833333, 0}, {0.121333, 0.778667, 0},
+ {0.084, 0.716, 0}, {0.0526667, 0.647333, 0},
+ {0.0253333, 0.574667, 0}, {0, 0.5, 0},
+ {-0.0253333, 0.425333, 0}, {-0.0526667, 0.352667, 0},
+ {-0.084, 0.284, 0}, {-0.121333, 0.221333, 0},
+ {-0.166667, 0.166667, 0}, {-0.221, 0.121667, 0},
+ {-0.281333, 0.0866667, 0}, {-0.343667, 0.0616666, 0},
+ {-0.404, 0.0466667, 0}, {-0.458333, 0.0416667, 0},
+ {-0.502667, 0.0466667, 0}, {-0.533, 0.0616666, 0},
+ {-0.545333, 0.0866667, 0}, {-0.535667, 0.121667, 0},
+ {-0.5, 0.166667, 0}, {-0.436, 0.221334, 0},
+ {-0.348, 0.284, 0}, {-0.242, 0.352667, 0},
+ {-0.124, 0.425333, 0}, {0, 0.5, 0},
+ {0.124, 0.574667, 0}, {0.242, 0.647333, 0},
+ {0.348, 0.716, 0}, {0.436, 0.778667, 0},
+ {0.5, 0.833333, 0}, {0.535667, 0.878334, 0},
+ {0.545333, 0.913333, 0}, {0.533, 0.938333, 0},
+ {0.502667, 0.953333, 0}, {0.458333, 0.958333, 0},
+ {0.404, 0.953333, 0}, {0.343667, 0.938333, 0},
+ {0.281333, 0.913333, 0}, {0.221, 0.878333, 0},
+ }};
+ for (const int i : evaluated_positions.index_range()) {
+ EXPECT_V3_NEAR(evaluated_positions[i], result_2[i], 1e-5f);
+ }
+
+ /* Test a circular cyclic curve with weights. */
+ positions[0] = {1, 0, 0};
+ positions[1] = {1, 1, 0};
+ positions[2] = {0, 1, 0};
+ positions[3] = {0, 0, 0};
+ curves.nurbs_weights().fill(1.0f);
+ curves.nurbs_weights()[0] = 4.0f;
+ curves.tag_positions_changed();
+ static const Array<float3> result_3{{
+ {0.888889, 0.555556, 0}, {0.837792, 0.643703, 0}, {0.773885, 0.727176, 0},
+ {0.698961, 0.800967, 0}, {0.616125, 0.860409, 0}, {0.529412, 0.901961, 0},
+ {0.443152, 0.923773, 0}, {0.361289, 0.925835, 0}, {0.286853, 0.909695, 0},
+ {0.221722, 0.877894, 0}, {0.166667, 0.833333, 0}, {0.122106, 0.778278, 0},
+ {0.0903055, 0.713148, 0}, {0.0741654, 0.638711, 0}, {0.0762274, 0.556847, 0},
+ {0.0980392, 0.470588, 0}, {0.139591, 0.383875, 0}, {0.199032, 0.301039, 0},
+ {0.272824, 0.226114, 0}, {0.356297, 0.162208, 0}, {0.444444, 0.111111, 0},
+ {0.531911, 0.0731388, 0}, {0.612554, 0.0468976, 0}, {0.683378, 0.0301622, 0},
+ {0.74391, 0.0207962, 0}, {0.794872, 0.017094, 0}, {0.837411, 0.017839, 0},
+ {0.872706, 0.0222583, 0}, {0.901798, 0.0299677, 0}, {0.925515, 0.0409445, 0},
+ {0.944444, 0.0555556, 0}, {0.959056, 0.0744855, 0}, {0.970032, 0.0982019, 0},
+ {0.977742, 0.127294, 0}, {0.982161, 0.162589, 0}, {0.982906, 0.205128, 0},
+ {0.979204, 0.256091, 0}, {0.969838, 0.316622, 0}, {0.953102, 0.387446, 0},
+ {0.926861, 0.468089, 0},
+ }};
+ evaluated_positions = curves.evaluated_positions();
+ for (const int i : evaluated_positions.index_range()) {
+ EXPECT_V3_NEAR(evaluated_positions[i], result_3[i], 1e-5f);
+ }
+}
+
} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index b348e18a6a8..bf6f05300f8 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -18,9 +18,11 @@
#include "DNA_meshdata_types.h"
#include "BLI_bitmap.h"
+#include "BLI_color.hh"
#include "BLI_endian_switch.h"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
+#include "BLI_math_vector.hh"
#include "BLI_mempool.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
@@ -60,6 +62,10 @@ BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)nullptr)->typemap) == CD_NUMTYPES, "
static CLG_LogRef LOG = {"bke.customdata"};
+/* -------------------------------------------------------------------- */
+/** \name Mesh Mask Utilities
+ * \{ */
+
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst,
const CustomData_MeshMasks *mask_src)
{
@@ -80,7 +86,12 @@ bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref,
((mask_required->lmask & mask_ref->lmask) == mask_required->lmask));
}
-/********************* Layer type information **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Layer Type Information
+ * \{ */
+
struct LayerTypeInfo {
int size; /* the memory size of one element of this layer's data */
@@ -162,6 +173,12 @@ struct LayerTypeInfo {
int (*layers_max)();
};
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#MDeformVert, #CD_MDEFORMVERT)
+ * \{ */
+
static void layerCopy_mdeformvert(const void *source, void *dest, int count)
{
int i, size = sizeof(MDeformVert);
@@ -313,6 +330,12 @@ static void layerInterp_mdeformvert(const void **sources,
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#vec3f, #CD_NORMAL)
+ * \{ */
+
static void layerInterp_normal(const void **sources,
const float *weights,
const float *UNUSED(sub_weights),
@@ -369,6 +392,12 @@ static void layerCopyValue_normal(const void *source,
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#MTFace, #CD_MTFACE)
+ * \{ */
+
static void layerCopy_tface(const void *source, void *dest, int count)
{
const MTFace *source_tf = (const MTFace *)source;
@@ -434,6 +463,12 @@ static int layerMaxNum_tface()
return MAX_MTFACE;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#MFloatProperty, #CD_PROP_FLOAT)
+ * \{ */
+
static void layerCopy_propFloat(const void *source, void *dest, int count)
{
memcpy(dest, source, sizeof(MFloatProperty) * count);
@@ -471,16 +506,34 @@ static bool layerValidate_propFloat(void *data, const uint totitems, const bool
return has_errors;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#MIntProperty, #CD_PROP_INT32)
+ * \{ */
+
static void layerCopy_propInt(const void *source, void *dest, int count)
{
memcpy(dest, source, sizeof(MIntProperty) * count);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#MStringProperty, #CD_PROP_STRING)
+ * \{ */
+
static void layerCopy_propString(const void *source, void *dest, int count)
{
memcpy(dest, source, sizeof(MStringProperty) * count);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#OrigSpaceFace, #CD_ORIGSPACE)
+ * \{ */
+
static void layerCopy_origspace_face(const void *source, void *dest, int count)
{
const OrigSpaceFace *source_tf = (const OrigSpaceFace *)source;
@@ -539,6 +592,12 @@ static void layerDefault_origspace_face(void *data, int count)
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#MDisps, #CD_MDISPS)
+ * \{ */
+
static void layerSwap_mdisps(void *data, const int *ci)
{
MDisps *s = static_cast<MDisps *>(data);
@@ -651,6 +710,13 @@ static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int
return size;
}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (`float`, #CD_PAINT_MASK)
+ * \{ */
+
static void layerInterp_paint_mask(const void **sources,
const float *weights,
const float *UNUSED(sub_weights),
@@ -666,6 +732,12 @@ static void layerInterp_paint_mask(const void **sources,
*(float *)dest = mask;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#GridPaintMask, #CD_GRID_PAINT_MASK)
+ * \{ */
+
static void layerCopy_grid_paint_mask(const void *source, void *dest, int count)
{
const GridPaintMask *s = static_cast<const GridPaintMask *>(source);
@@ -1177,6 +1249,12 @@ static void layerInterp_shapekey(const void **sources,
copy_v3_v3((float *)dest, co);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#MVertSkin, #CD_MVERT_SKIN)
+ * \{ */
+
static void layerDefault_mvert_skin(void *data, int count)
{
MVertSkin *vs = static_cast<MVertSkin *>(data);
@@ -1214,6 +1292,12 @@ static void layerInterp_mvert_skin(const void **sources,
vs_dst->flag &= ~MVERT_SKIN_ROOT;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (`short[4][3]`, #CD_TESSLOOPNORMAL)
+ * \{ */
+
static void layerSwap_flnor(void *data, const int *corner_indices)
{
short(*flnors)[4][3] = static_cast<short(*)[4][3]>(data);
@@ -1227,6 +1311,12 @@ static void layerSwap_flnor(void *data, const int *corner_indices)
memcpy(flnors, nors, sizeof(nors));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (`int`, #CD_FACEMAP)
+ * \{ */
+
static void layerDefault_fmap(void *data, int count)
{
int *fmap_num = (int *)data;
@@ -1235,6 +1325,12 @@ static void layerDefault_fmap(void *data, int count)
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#MPropCol, #CD_PROP_COLOR)
+ * \{ */
+
static void layerCopyValue_propcol(const void *source,
void *dest,
const int mixmode,
@@ -1358,6 +1454,12 @@ static int layerMaxNum_propcol()
return MAX_MCOL;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#vec3f, #CD_PROP_FLOAT3)
+ * \{ */
+
static void layerInterp_propfloat3(const void **sources,
const float *weights,
const float *UNUSED(sub_weights),
@@ -1405,6 +1507,12 @@ static bool layerValidate_propfloat3(void *data, const uint totitems, const bool
return has_errors;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (#vec2f, #CD_PROP_FLOAT2)
+ * \{ */
+
static void layerInterp_propfloat2(const void **sources,
const float *weights,
const float *UNUSED(sub_weights),
@@ -1450,6 +1558,12 @@ static bool layerValidate_propfloat2(void *data, const uint totitems, const bool
return has_errors;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for (`bool`, #CD_PROP_BOOL)
+ * \{ */
+
static void layerInterp_propbool(const void **sources,
const float *weights,
const float *UNUSED(sub_weights),
@@ -2051,7 +2165,12 @@ void customData_mask_layers__print(const CustomData_MeshMasks *mask)
}
}
-/********************* CustomData functions *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name CustomData Functions
+ * \{ */
+
static void customData_update_offsets(CustomData *data);
static CustomDataLayer *customData_add_layer__internal(CustomData *data,
@@ -4468,14 +4587,18 @@ void CustomData_layers__print(CustomData *data)
printf("}\n");
}
-/****************************** External Files *******************************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name External Files
+ * \{ */
-static void customdata_external_filename(char filename[FILE_MAX],
+static void customdata_external_filename(char filepath[FILE_MAX],
ID *id,
CustomDataExternal *external)
{
- BLI_strncpy(filename, external->filename, FILE_MAX);
- BLI_path_abs(filename, ID_BLEND_PATH_FROM_GLOBAL(id));
+ BLI_strncpy(filepath, external->filepath, FILE_MAX);
+ BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(id));
}
void CustomData_external_reload(CustomData *data, ID *UNUSED(id), CustomDataMask mask, int totelem)
@@ -4500,7 +4623,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
{
CustomDataExternal *external = data->external;
CustomDataLayer *layer;
- char filename[FILE_MAX];
+ char filepath[FILE_MAX];
int update = 0;
if (!external) {
@@ -4526,12 +4649,12 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int
return;
}
- customdata_external_filename(filename, id, external);
+ customdata_external_filename(filepath, id, external);
CDataFile *cdf = cdf_create(CDF_TYPE_MESH);
- if (!cdf_read_open(cdf, filename)) {
+ if (!cdf_read_open(cdf, filepath)) {
cdf_free(cdf);
- CLOG_ERROR(&LOG, "Failed to read %s layer from %s.", layerType_getName(layer->type), filename);
+ CLOG_ERROR(&LOG, "Failed to read %s layer from %s.", layerType_getName(layer->type), filepath);
return;
}
@@ -4574,7 +4697,7 @@ void CustomData_external_write(
{
CustomDataExternal *external = data->external;
int update = 0;
- char filename[FILE_MAX];
+ char filepath[FILE_MAX];
if (!external) {
return;
@@ -4599,7 +4722,7 @@ void CustomData_external_write(
/* make sure data is read before we try to write */
CustomData_external_read(data, id, mask, totelem);
- customdata_external_filename(filename, id, external);
+ customdata_external_filename(filepath, id, external);
CDataFile *cdf = cdf_create(CDF_TYPE_MESH);
@@ -4619,8 +4742,8 @@ void CustomData_external_write(
}
}
- if (!cdf_write_open(cdf, filename)) {
- CLOG_ERROR(&LOG, "Failed to open %s for writing.", filename);
+ if (!cdf_write_open(cdf, filepath)) {
+ CLOG_ERROR(&LOG, "Failed to open %s for writing.", filepath);
cdf_free(cdf);
return;
}
@@ -4648,7 +4771,7 @@ void CustomData_external_write(
}
if (i != data->totlayer) {
- CLOG_ERROR(&LOG, "Failed to write data to %s.", filename);
+ CLOG_ERROR(&LOG, "Failed to write data to %s.", filepath);
cdf_write_close(cdf);
cdf_free(cdf);
return;
@@ -4673,7 +4796,7 @@ void CustomData_external_write(
}
void CustomData_external_add(
- CustomData *data, ID *UNUSED(id), int type, int UNUSED(totelem), const char *filename)
+ CustomData *data, ID *UNUSED(id), int type, int UNUSED(totelem), const char *filepath)
{
CustomDataExternal *external = data->external;
@@ -4692,7 +4815,7 @@ void CustomData_external_add(
external = MEM_cnew<CustomDataExternal>(__func__);
data->external = external;
}
- BLI_strncpy(external->filename, filename, sizeof(external->filename));
+ BLI_strncpy(external->filepath, filepath, sizeof(external->filepath));
layer->flag |= CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY;
}
@@ -4732,7 +4855,12 @@ bool CustomData_external_test(CustomData *data, int type)
return (layer->flag & CD_FLAG_EXTERNAL) != 0;
}
-/* ********** Mesh-to-mesh data transfer ********** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mesh-to-Mesh Data Transfer
+ * \{ */
+
static void copy_bit_flag(void *dst, const void *src, const size_t data_size, const uint64_t flag)
{
#define COPY_BIT_FLAG(_type, _dst, _src, _f) \
@@ -5011,6 +5139,12 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap,
MEM_SAFE_FREE(tmp_data_src);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom Data IO
+ * \{ */
+
static void write_mdisps(BlendWriter *writer, int count, MDisps *mdlist, int external)
{
if (mdlist) {
@@ -5205,6 +5339,12 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
CustomData_update_typemap(data);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom Data Debugging
+ * \{ */
+
#ifndef NDEBUG
void CustomData_debug_info_from_layers(const CustomData *data, const char *indent, DynStr *dynstr)
@@ -5234,3 +5374,66 @@ void CustomData_debug_info_from_layers(const CustomData *data, const char *inden
}
#endif /* NDEBUG */
+
+/** \} */
+
+namespace blender::bke {
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom Data C++ API
+ * \{ */
+
+const blender::CPPType *custom_data_type_to_cpp_type(const CustomDataType type)
+{
+ switch (type) {
+ case CD_PROP_FLOAT:
+ return &CPPType::get<float>();
+ case CD_PROP_FLOAT2:
+ return &CPPType::get<float2>();
+ case CD_PROP_FLOAT3:
+ return &CPPType::get<float3>();
+ case CD_PROP_INT32:
+ return &CPPType::get<int>();
+ case CD_PROP_COLOR:
+ return &CPPType::get<ColorGeometry4f>();
+ case CD_PROP_BOOL:
+ return &CPPType::get<bool>();
+ case CD_PROP_INT8:
+ return &CPPType::get<int8_t>();
+ default:
+ return nullptr;
+ }
+ return nullptr;
+}
+
+CustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
+{
+ if (type.is<float>()) {
+ return CD_PROP_FLOAT;
+ }
+ if (type.is<float2>()) {
+ return CD_PROP_FLOAT2;
+ }
+ if (type.is<float3>()) {
+ return CD_PROP_FLOAT3;
+ }
+ if (type.is<int>()) {
+ return CD_PROP_INT32;
+ }
+ if (type.is<ColorGeometry4f>()) {
+ return CD_PROP_COLOR;
+ }
+ if (type.is<bool>()) {
+ return CD_PROP_BOOL;
+ }
+ if (type.is<int8_t>()) {
+ return CD_PROP_INT8;
+ }
+ return static_cast<CustomDataType>(-1);
+}
+
+/** \} */
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index ce07e501897..0f5814c0a23 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -44,6 +44,7 @@
#include "BKE_dynamicpaint.h"
#include "BKE_effect.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_material.h"
@@ -3265,7 +3266,7 @@ static void dynamic_paint_output_surface_image_wetmap_cb(
}
void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface,
- char *filename,
+ const char *filepath,
short output_layer)
{
ImBuf *ibuf = NULL;
@@ -3285,7 +3286,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface,
format = R_IMF_IMTYPE_PNG;
}
#endif
- BLI_strncpy(output_file, filename, sizeof(output_file));
+ BLI_strncpy(output_file, filepath, sizeof(output_file));
BKE_image_path_ensure_ext_from_imtype(output_file, format);
/* Validate output file path */
@@ -5244,7 +5245,6 @@ static void dynamic_paint_effect_shrink_cb(void *__restrict userdata,
PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index];
const PaintPoint *prevPoint = data->prevPoint;
const float eff_scale = data->eff_scale;
- float totalAlpha = 0.0f;
const int *n_index = sData->adj_data->n_index;
const int *n_target = sData->adj_data->n_target;
@@ -5257,8 +5257,6 @@ static void dynamic_paint_effect_shrink_cb(void *__restrict userdata,
const PaintPoint *pPoint_prev = &prevPoint[n_target[n_idx]];
float a_factor, ea_factor, w_factor;
- totalAlpha += pPoint_prev->e_color[3];
-
/* Check if neighboring point has lower alpha,
* if so, decrease this point's alpha as well. */
if (pPoint->color[3] <= 0.0f && pPoint->e_color[3] <= 0.0f && pPoint->wetness <= 0.0f) {
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index ca9d758c692..81e73b6cf2c 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -1754,7 +1754,7 @@ static void update_distances(int index,
/* Count ray mesh misses (i.e. no face hit) and cases where the ray direction matches the face
* normal direction. From this information it can be derived whether a cell is inside or
* outside the mesh. */
- int miss_cnt = 0, dir_cnt = 0;
+ int miss_count = 0, dir_count = 0;
for (int i = 0; i < ARRAY_SIZE(ray_dirs); i++) {
BVHTreeRayHit hit_tree = {0};
@@ -1773,14 +1773,14 @@ static void update_distances(int index,
/* Ray did not hit mesh.
* Current point definitely not inside mesh. Inside mesh as all rays have to hit. */
if (hit_tree.index == -1) {
- miss_cnt++;
+ miss_count++;
/* Skip this ray since nothing was hit. */
continue;
}
/* Ray and normal are pointing in opposite directions. */
if (dot_v3v3(ray_dirs[i], hit_tree.no) <= 0) {
- dir_cnt++;
+ dir_count++;
}
if (hit_tree.dist < min_dist) {
@@ -1790,7 +1790,7 @@ static void update_distances(int index,
/* Point lies inside mesh. Use negative sign for distance value.
* This "if statement" has 2 conditions that can be true for points outside mesh. */
- if (!(miss_cnt > 0 || dir_cnt == ARRAY_SIZE(ray_dirs))) {
+ if (!(miss_count > 0 || dir_count == ARRAY_SIZE(ray_dirs))) {
min_dist = (-1.0f) * fabsf(min_dist);
}
diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc
index 0926d65b306..f409389e463 100644
--- a/source/blender/blenkernel/intern/geometry_component_curve.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curve.cc
@@ -14,10 +14,10 @@
#include "attribute_access_intern.hh"
-using blender::fn::GMutableSpan;
-using blender::fn::GSpan;
-using blender::fn::GVArray;
-using blender::fn::GVArray_GSpan;
+using blender::GMutableSpan;
+using blender::GSpan;
+using blender::GVArray;
+using blender::GVArray_GSpan;
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc
index 86cbea9a9bb..27689d70c77 100644
--- a/source/blender/blenkernel/intern/geometry_component_curves.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curves.cc
@@ -15,7 +15,7 @@
#include "attribute_access_intern.hh"
-using blender::fn::GVArray;
+using blender::GVArray;
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
@@ -236,10 +236,10 @@ int CurveComponent::attribute_domain_size(const AttributeDomain domain) const
const blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap(
curves_->geometry);
if (domain == ATTR_DOMAIN_POINT) {
- return geometry.points_size();
+ return geometry.points_num();
}
if (domain == ATTR_DOMAIN_CURVE) {
- return geometry.curves_size();
+ return geometry.curves_num();
}
return 0;
}
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 0cb2b0e812b..0dc6f486d28 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -20,18 +20,18 @@
#include "attribute_access_intern.hh"
-#include "FN_cpp_type_make.hh"
+#include "BLI_cpp_type_make.hh"
using blender::float4x4;
+using blender::GSpan;
using blender::IndexMask;
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)
+BLI_CPP_TYPE_MAKE(InstanceReference, InstanceReference, CPPTypeFlags::None)
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
@@ -164,7 +164,7 @@ void InstancesComponent::remove_instances(const IndexMask mask)
GSpan src = *src_attributes.get_for_read(id);
dst_attributes.create(id, meta_data.data_type);
- fn::GMutableSpan dst = *dst_attributes.get_for_write(id);
+ GMutableSpan dst = *dst_attributes.get_for_write(id);
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index cbd7ec9155a..2bfe984462c 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -260,7 +260,7 @@ static GVArray adapt_mesh_domain_point_to_corner(const Mesh &mesh, const GVArray
attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
new_varray = VArray<T>::ForFunc(mesh.totloop,
- [mesh, varray = varray.typed<T>()](const int64_t loop_index) {
+ [&mesh, varray = varray.typed<T>()](const int64_t loop_index) {
const int vertex_index = mesh.mloop[loop_index].v;
return varray[vertex_index];
});
@@ -276,7 +276,7 @@ static GVArray adapt_mesh_domain_corner_to_face(const Mesh &mesh, const GVArray
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
if constexpr (std::is_same_v<T, bool>) {
new_varray = VArray<T>::ForFunc(
- mesh.totpoly, [mesh, varray = varray.typed<bool>()](const int face_index) {
+ mesh.totpoly, [&mesh, varray = varray.typed<bool>()](const int face_index) {
/* A face is selected if all of its corners were selected. */
const MPoly &poly = mesh.mpoly[face_index];
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
@@ -289,7 +289,7 @@ static GVArray adapt_mesh_domain_corner_to_face(const Mesh &mesh, const GVArray
}
else {
new_varray = VArray<T>::ForFunc(
- mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) {
+ mesh.totpoly, [&mesh, varray = varray.typed<T>()](const int face_index) {
T return_value;
attribute_math::DefaultMixer<T> mixer({&return_value, 1});
const MPoly &poly = mesh.mpoly[face_index];
@@ -530,7 +530,7 @@ static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray &
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
if constexpr (std::is_same_v<T, bool>) {
new_varray = VArray<T>::ForFunc(
- mesh.totpoly, [mesh, varray = varray.typed<bool>()](const int face_index) {
+ mesh.totpoly, [&mesh, varray = varray.typed<bool>()](const int face_index) {
/* A face is selected if all of its vertices were selected. */
const MPoly &poly = mesh.mpoly[face_index];
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
@@ -544,7 +544,7 @@ static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray &
}
else {
new_varray = VArray<T>::ForFunc(
- mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) {
+ mesh.totpoly, [&mesh, varray = varray.typed<T>()](const int face_index) {
T return_value;
attribute_math::DefaultMixer<T> mixer({&return_value, 1});
const MPoly &poly = mesh.mpoly[face_index];
@@ -571,14 +571,14 @@ static GVArray adapt_mesh_domain_point_to_edge(const Mesh &mesh, const GVArray &
if constexpr (std::is_same_v<T, bool>) {
/* An edge is selected if both of its vertices were selected. */
new_varray = VArray<bool>::ForFunc(
- mesh.totedge, [mesh, varray = varray.typed<bool>()](const int edge_index) {
+ mesh.totedge, [&mesh, varray = varray.typed<bool>()](const int edge_index) {
const MEdge &edge = mesh.medge[edge_index];
return varray[edge.v1] && varray[edge.v2];
});
}
else {
new_varray = VArray<T>::ForFunc(
- mesh.totedge, [mesh, varray = varray.typed<T>()](const int edge_index) {
+ mesh.totedge, [&mesh, varray = varray.typed<T>()](const int edge_index) {
T return_value;
attribute_math::DefaultMixer<T> mixer({&return_value, 1});
const MEdge &edge = mesh.medge[edge_index];
@@ -713,7 +713,7 @@ static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &v
if constexpr (std::is_same_v<T, bool>) {
/* A face is selected if all of its edges are selected. */
new_varray = VArray<bool>::ForFunc(
- mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) {
+ mesh.totpoly, [&mesh, varray = varray.typed<T>()](const int face_index) {
const MPoly &poly = mesh.mpoly[face_index];
for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
const MLoop &loop = mesh.mloop[loop_index];
@@ -726,7 +726,7 @@ static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &v
}
else {
new_varray = VArray<T>::ForFunc(
- mesh.totpoly, [mesh, varray = varray.typed<T>()](const int face_index) {
+ mesh.totpoly, [&mesh, varray = varray.typed<T>()](const int face_index) {
T return_value;
attribute_math::DefaultMixer<T> mixer({&return_value, 1});
const MPoly &poly = mesh.mpoly[face_index];
@@ -746,8 +746,8 @@ static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &v
} // namespace blender::bke
-blender::fn::GVArray MeshComponent::attribute_try_adapt_domain_impl(
- const blender::fn::GVArray &varray,
+blender::GVArray MeshComponent::attribute_try_adapt_domain_impl(
+ const blender::GVArray &varray,
const AttributeDomain from_domain,
const AttributeDomain to_domain) const
{
@@ -944,20 +944,71 @@ class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl<float> {
if (dverts_ == nullptr) {
return 0.0f;
}
- const MDeformVert &dvert = dverts_[index];
- for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) {
- if (weight.def_nr == dvert_index_) {
- return weight.weight;
- }
+ if (const MDeformWeight *weight = this->find_weight_at_index(index)) {
+ return weight->weight;
}
return 0.0f;
- ;
}
void set(const int64_t index, const float value) override
{
- MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
- weight->weight = value;
+ MDeformVert &dvert = dverts_[index];
+ if (value == 0.0f) {
+ if (MDeformWeight *weight = this->find_weight_at_index(index)) {
+ weight->weight = 0.0f;
+ }
+ }
+ else {
+ MDeformWeight *weight = BKE_defvert_ensure_index(&dvert, dvert_index_);
+ weight->weight = value;
+ }
+ }
+
+ void set_all(Span<float> src) override
+ {
+ for (const int64_t index : src.index_range()) {
+ this->set(index, src[index]);
+ }
+ }
+
+ void materialize(IndexMask mask, MutableSpan<float> r_span) const override
+ {
+ if (dverts_ == nullptr) {
+ return r_span.fill_indices(mask, 0.0f);
+ }
+ for (const int64_t index : mask) {
+ if (const MDeformWeight *weight = this->find_weight_at_index(index)) {
+ r_span[index] = weight->weight;
+ }
+ else {
+ r_span[index] = 0.0f;
+ }
+ }
+ }
+
+ void materialize_to_uninitialized(IndexMask mask, MutableSpan<float> r_span) const override
+ {
+ this->materialize(mask, r_span);
+ }
+
+ private:
+ MDeformWeight *find_weight_at_index(const int64_t index)
+ {
+ for (MDeformWeight &weight : MutableSpan(dverts_[index].dw, dverts_[index].totweight)) {
+ if (weight.def_nr == dvert_index_) {
+ return &weight;
+ }
+ }
+ return nullptr;
+ }
+ const MDeformWeight *find_weight_at_index(const int64_t index) const
+ {
+ for (const MDeformWeight &weight : Span(dverts_[index].dw, dverts_[index].totweight)) {
+ if (weight.def_nr == dvert_index_) {
+ return &weight;
+ }
+ }
+ return nullptr;
}
};
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index ff08b596770..44ffd64e475 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -7,7 +7,6 @@
#include "BKE_mesh_wrapper.h"
#include "BKE_modifier.h"
#include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
#include "DNA_collection_types.h"
#include "DNA_layer_types.h"
diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc
index e4ed2a40f10..a5eff1f9d5a 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.cc
+++ b/source/blender/blenkernel/intern/gpencil_geom.cc
@@ -451,6 +451,10 @@ bool BKE_gpencil_stroke_sample(bGPdata *gpd,
}
/* TODO: Implement feature point preservation. */
int count = stroke_march_count(gps, dist, sharp_threshold);
+ const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0;
+ if (is_cyclic) {
+ count--;
+ }
bGPDspoint *new_pt = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint) * count,
"gp_stroke_points_sampled");
@@ -499,6 +503,9 @@ bool BKE_gpencil_stroke_sample(bGPdata *gpd,
&ratio_result,
&index_from,
&index_to)) > -1) {
+ if (is_cyclic && next_point_index == 0) {
+ break; /* last point finished */
+ }
pt2 = &new_pt[i];
copy_v3_v3(&pt2->x, last_coord);
new_pt[i].pressure = pressure;
@@ -533,10 +540,9 @@ bool BKE_gpencil_stroke_sample(bGPdata *gpd,
gps->dvert = new_dv;
}
+ BLI_assert(i == count);
gps->totpoints = i;
- gps->flag &= (~GP_STROKE_CYCLIC);
-
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(gpd, gps);
diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc
index 4a1cbdba42a..b65f3416f0f 100644
--- a/source/blender/blenkernel/intern/image.cc
+++ b/source/blender/blenkernel/intern/image.cc
@@ -9,6 +9,7 @@
#include <cmath>
#include <cstdio>
#include <cstring>
+#include <ctime>
#include <fcntl.h>
#ifndef WIN32
# include <unistd.h>
@@ -16,7 +17,8 @@
# include <io.h>
#endif
-#include <ctime>
+#include <regex>
+#include <string>
#include "BLI_array.hh"
@@ -29,10 +31,7 @@
#include "IMB_imbuf_types.h"
#include "IMB_metadata.h"
#include "IMB_moviecache.h"
-
-#ifdef WITH_OPENEXR
-# include "intern/openexr/openexr_multi.h"
-#endif
+#include "IMB_openexr.h"
/* Allow using deprecated functionality for .blend file I/O. */
#define DNA_DEPRECATED_ALLOW
@@ -68,6 +67,7 @@
#include "BKE_icons.h"
#include "BKE_idtype.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -239,7 +239,7 @@ static void image_foreach_cache(ID *id,
auto gputexture_offset = [image](int target, int eye, int resolution) {
constexpr size_t base_offset = offsetof(Image, gputexture);
- const auto first = &image->gputexture[0][0][0];
+ struct GPUTexture **first = &image->gputexture[0][0][0];
const size_t array_offset = sizeof(*first) *
(&image->gputexture[target][eye][resolution] - first);
return base_offset + array_offset;
@@ -489,9 +489,9 @@ static void image_add_view(Image *ima, const char *viewname, const char *filepat
/** \name Image Cache
* \{ */
-typedef struct ImageCacheKey {
+struct ImageCacheKey {
int index;
-} ImageCacheKey;
+};
static unsigned int imagecache_hashhash(const void *key_v)
{
@@ -1490,607 +1490,6 @@ void BKE_image_all_free_anim_ibufs(Main *bmain, int cfra)
/** \name Read and Write
* \{ */
-int BKE_image_imtype_to_ftype(const char imtype, ImbFormatOptions *r_options)
-{
- memset(r_options, 0, sizeof(*r_options));
-
- if (imtype == R_IMF_IMTYPE_TARGA) {
- return IMB_FTYPE_TGA;
- }
- if (imtype == R_IMF_IMTYPE_RAWTGA) {
- r_options->flag = RAWTGA;
- return IMB_FTYPE_TGA;
- }
- if (imtype == R_IMF_IMTYPE_IRIS) {
- return IMB_FTYPE_IMAGIC;
- }
-#ifdef WITH_HDR
- if (imtype == R_IMF_IMTYPE_RADHDR) {
- return IMB_FTYPE_RADHDR;
- }
-#endif
- if (imtype == R_IMF_IMTYPE_PNG) {
- r_options->quality = 15;
- return IMB_FTYPE_PNG;
- }
-#ifdef WITH_DDS
- if (imtype == R_IMF_IMTYPE_DDS) {
- return IMB_FTYPE_DDS;
- }
-#endif
- if (imtype == R_IMF_IMTYPE_BMP) {
- return IMB_FTYPE_BMP;
- }
-#ifdef WITH_TIFF
- if (imtype == R_IMF_IMTYPE_TIFF) {
- return IMB_FTYPE_TIF;
- }
-#endif
- if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
- return IMB_FTYPE_OPENEXR;
- }
-#ifdef WITH_CINEON
- if (imtype == R_IMF_IMTYPE_CINEON) {
- return IMB_FTYPE_CINEON;
- }
- if (imtype == R_IMF_IMTYPE_DPX) {
- return IMB_FTYPE_DPX;
- }
-#endif
-#ifdef WITH_OPENJPEG
- if (imtype == R_IMF_IMTYPE_JP2) {
- r_options->flag |= JP2_JP2;
- r_options->quality = 90;
- return IMB_FTYPE_JP2;
- }
-#endif
-
- r_options->quality = 90;
- return IMB_FTYPE_JPG;
-}
-
-char BKE_image_ftype_to_imtype(const int ftype, const ImbFormatOptions *options)
-{
- if (ftype == IMB_FTYPE_NONE) {
- return R_IMF_IMTYPE_TARGA;
- }
- if (ftype == IMB_FTYPE_IMAGIC) {
- return R_IMF_IMTYPE_IRIS;
- }
-#ifdef WITH_HDR
- if (ftype == IMB_FTYPE_RADHDR) {
- return R_IMF_IMTYPE_RADHDR;
- }
-#endif
- if (ftype == IMB_FTYPE_PNG) {
- return R_IMF_IMTYPE_PNG;
- }
-#ifdef WITH_DDS
- if (ftype == IMB_FTYPE_DDS) {
- return R_IMF_IMTYPE_DDS;
- }
-#endif
- if (ftype == IMB_FTYPE_BMP) {
- return R_IMF_IMTYPE_BMP;
- }
-#ifdef WITH_TIFF
- if (ftype == IMB_FTYPE_TIF) {
- return R_IMF_IMTYPE_TIFF;
- }
-#endif
- if (ftype == IMB_FTYPE_OPENEXR) {
- return R_IMF_IMTYPE_OPENEXR;
- }
-#ifdef WITH_CINEON
- if (ftype == IMB_FTYPE_CINEON) {
- return R_IMF_IMTYPE_CINEON;
- }
- if (ftype == IMB_FTYPE_DPX) {
- return R_IMF_IMTYPE_DPX;
- }
-#endif
- if (ftype == IMB_FTYPE_TGA) {
- if (options && (options->flag & RAWTGA)) {
- return R_IMF_IMTYPE_RAWTGA;
- }
-
- return R_IMF_IMTYPE_TARGA;
- }
-#ifdef WITH_OPENJPEG
- if (ftype == IMB_FTYPE_JP2) {
- return R_IMF_IMTYPE_JP2;
- }
-#endif
-
- return R_IMF_IMTYPE_JPEG90;
-}
-
-bool BKE_imtype_is_movie(const char imtype)
-{
- switch (imtype) {
- case R_IMF_IMTYPE_AVIRAW:
- case R_IMF_IMTYPE_AVIJPEG:
- case R_IMF_IMTYPE_FFMPEG:
- case R_IMF_IMTYPE_H264:
- case R_IMF_IMTYPE_THEORA:
- case R_IMF_IMTYPE_XVID:
- return true;
- }
- return false;
-}
-
-bool BKE_imtype_supports_zbuf(const char imtype)
-{
- switch (imtype) {
- case R_IMF_IMTYPE_IRIZ:
- case R_IMF_IMTYPE_OPENEXR: /* But not #R_IMF_IMTYPE_MULTILAYER. */
- return true;
- }
- return false;
-}
-
-bool BKE_imtype_supports_compress(const char imtype)
-{
- switch (imtype) {
- case R_IMF_IMTYPE_PNG:
- return true;
- }
- return false;
-}
-
-bool BKE_imtype_supports_quality(const char imtype)
-{
- switch (imtype) {
- case R_IMF_IMTYPE_JPEG90:
- case R_IMF_IMTYPE_JP2:
- case R_IMF_IMTYPE_AVIJPEG:
- return true;
- }
- return false;
-}
-
-bool BKE_imtype_requires_linear_float(const char imtype)
-{
- switch (imtype) {
- case R_IMF_IMTYPE_CINEON:
- case R_IMF_IMTYPE_DPX:
- case R_IMF_IMTYPE_RADHDR:
- case R_IMF_IMTYPE_OPENEXR:
- case R_IMF_IMTYPE_MULTILAYER:
- return true;
- }
- return false;
-}
-
-char BKE_imtype_valid_channels(const char imtype, bool write_file)
-{
- char chan_flag = IMA_CHAN_FLAG_RGB; /* Assume all support RGB. */
-
- /* Alpha. */
- switch (imtype) {
- case R_IMF_IMTYPE_BMP:
- if (write_file) {
- break;
- }
- ATTR_FALLTHROUGH;
- case R_IMF_IMTYPE_TARGA:
- case R_IMF_IMTYPE_RAWTGA:
- case R_IMF_IMTYPE_IRIS:
- case R_IMF_IMTYPE_PNG:
- case R_IMF_IMTYPE_TIFF:
- case R_IMF_IMTYPE_OPENEXR:
- case R_IMF_IMTYPE_MULTILAYER:
- case R_IMF_IMTYPE_DDS:
- case R_IMF_IMTYPE_JP2:
- case R_IMF_IMTYPE_DPX:
- chan_flag |= IMA_CHAN_FLAG_ALPHA;
- break;
- }
-
- /* BW. */
- switch (imtype) {
- case R_IMF_IMTYPE_BMP:
- case R_IMF_IMTYPE_PNG:
- case R_IMF_IMTYPE_JPEG90:
- case R_IMF_IMTYPE_TARGA:
- case R_IMF_IMTYPE_RAWTGA:
- case R_IMF_IMTYPE_TIFF:
- case R_IMF_IMTYPE_IRIS:
- chan_flag |= IMA_CHAN_FLAG_BW;
- break;
- }
-
- return chan_flag;
-}
-
-char BKE_imtype_valid_depths(const char imtype)
-{
- switch (imtype) {
- case R_IMF_IMTYPE_RADHDR:
- return R_IMF_CHAN_DEPTH_32;
- case R_IMF_IMTYPE_TIFF:
- return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_16;
- case R_IMF_IMTYPE_OPENEXR:
- return R_IMF_CHAN_DEPTH_16 | R_IMF_CHAN_DEPTH_32;
- case R_IMF_IMTYPE_MULTILAYER:
- return R_IMF_CHAN_DEPTH_16 | R_IMF_CHAN_DEPTH_32;
- /* NOTE: CINEON uses an unusual 10bits-LOG per channel. */
- case R_IMF_IMTYPE_DPX:
- return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_10 | R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16;
- case R_IMF_IMTYPE_CINEON:
- return R_IMF_CHAN_DEPTH_10;
- case R_IMF_IMTYPE_JP2:
- return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16;
- case R_IMF_IMTYPE_PNG:
- return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_16;
- /* Most formats are 8bit only. */
- default:
- return R_IMF_CHAN_DEPTH_8;
- }
-}
-
-char BKE_imtype_from_arg(const char *imtype_arg)
-{
- if (STREQ(imtype_arg, "TGA")) {
- return R_IMF_IMTYPE_TARGA;
- }
- if (STREQ(imtype_arg, "IRIS")) {
- return R_IMF_IMTYPE_IRIS;
- }
-#ifdef WITH_DDS
- if (STREQ(imtype_arg, "DDS")) {
- return R_IMF_IMTYPE_DDS;
- }
-#endif
- if (STREQ(imtype_arg, "JPEG")) {
- return R_IMF_IMTYPE_JPEG90;
- }
- if (STREQ(imtype_arg, "IRIZ")) {
- return R_IMF_IMTYPE_IRIZ;
- }
- if (STREQ(imtype_arg, "RAWTGA")) {
- return R_IMF_IMTYPE_RAWTGA;
- }
- if (STREQ(imtype_arg, "AVIRAW")) {
- return R_IMF_IMTYPE_AVIRAW;
- }
- if (STREQ(imtype_arg, "AVIJPEG")) {
- return R_IMF_IMTYPE_AVIJPEG;
- }
- if (STREQ(imtype_arg, "PNG")) {
- return R_IMF_IMTYPE_PNG;
- }
- if (STREQ(imtype_arg, "BMP")) {
- return R_IMF_IMTYPE_BMP;
- }
-#ifdef WITH_HDR
- if (STREQ(imtype_arg, "HDR")) {
- return R_IMF_IMTYPE_RADHDR;
- }
-#endif
-#ifdef WITH_TIFF
- if (STREQ(imtype_arg, "TIFF")) {
- return R_IMF_IMTYPE_TIFF;
- }
-#endif
-#ifdef WITH_OPENEXR
- if (STREQ(imtype_arg, "OPEN_EXR")) {
- return R_IMF_IMTYPE_OPENEXR;
- }
- if (STREQ(imtype_arg, "OPEN_EXR_MULTILAYER")) {
- return R_IMF_IMTYPE_MULTILAYER;
- }
- if (STREQ(imtype_arg, "EXR")) {
- return R_IMF_IMTYPE_OPENEXR;
- }
- if (STREQ(imtype_arg, "MULTILAYER")) {
- return R_IMF_IMTYPE_MULTILAYER;
- }
-#endif
- if (STREQ(imtype_arg, "FFMPEG")) {
- return R_IMF_IMTYPE_FFMPEG;
- }
-#ifdef WITH_CINEON
- if (STREQ(imtype_arg, "CINEON")) {
- return R_IMF_IMTYPE_CINEON;
- }
- if (STREQ(imtype_arg, "DPX")) {
- return R_IMF_IMTYPE_DPX;
- }
-#endif
-#ifdef WITH_OPENJPEG
- if (STREQ(imtype_arg, "JP2")) {
- return R_IMF_IMTYPE_JP2;
- }
-#endif
-
- return R_IMF_IMTYPE_INVALID;
-}
-
-static bool do_add_image_extension(char *string,
- const char imtype,
- const ImageFormatData *im_format)
-{
- const char *extension = nullptr;
- const char *extension_test;
- (void)im_format; /* may be unused, depends on build options */
-
- if (imtype == R_IMF_IMTYPE_IRIS) {
- if (!BLI_path_extension_check(string, extension_test = ".rgb")) {
- extension = extension_test;
- }
- }
- else if (imtype == R_IMF_IMTYPE_IRIZ) {
- if (!BLI_path_extension_check(string, extension_test = ".rgb")) {
- extension = extension_test;
- }
- }
-#ifdef WITH_HDR
- else if (imtype == R_IMF_IMTYPE_RADHDR) {
- if (!BLI_path_extension_check(string, extension_test = ".hdr")) {
- extension = extension_test;
- }
- }
-#endif
- else if (ELEM(imtype,
- R_IMF_IMTYPE_PNG,
- R_IMF_IMTYPE_FFMPEG,
- R_IMF_IMTYPE_H264,
- R_IMF_IMTYPE_THEORA,
- R_IMF_IMTYPE_XVID)) {
- if (!BLI_path_extension_check(string, extension_test = ".png")) {
- extension = extension_test;
- }
- }
-#ifdef WITH_DDS
- else if (imtype == R_IMF_IMTYPE_DDS) {
- if (!BLI_path_extension_check(string, extension_test = ".dds")) {
- extension = extension_test;
- }
- }
-#endif
- else if (ELEM(imtype, R_IMF_IMTYPE_TARGA, R_IMF_IMTYPE_RAWTGA)) {
- if (!BLI_path_extension_check(string, extension_test = ".tga")) {
- extension = extension_test;
- }
- }
- else if (imtype == R_IMF_IMTYPE_BMP) {
- if (!BLI_path_extension_check(string, extension_test = ".bmp")) {
- extension = extension_test;
- }
- }
-#ifdef WITH_TIFF
- else if (imtype == R_IMF_IMTYPE_TIFF) {
- if (!BLI_path_extension_check_n(string, extension_test = ".tif", ".tiff", nullptr)) {
- extension = extension_test;
- }
- }
-#endif
-#ifdef WITH_OPENIMAGEIO
- else if (imtype == R_IMF_IMTYPE_PSD) {
- if (!BLI_path_extension_check(string, extension_test = ".psd")) {
- extension = extension_test;
- }
- }
-#endif
-#ifdef WITH_OPENEXR
- else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
- if (!BLI_path_extension_check(string, extension_test = ".exr")) {
- extension = extension_test;
- }
- }
-#endif
-#ifdef WITH_CINEON
- else if (imtype == R_IMF_IMTYPE_CINEON) {
- if (!BLI_path_extension_check(string, extension_test = ".cin")) {
- extension = extension_test;
- }
- }
- else if (imtype == R_IMF_IMTYPE_DPX) {
- if (!BLI_path_extension_check(string, extension_test = ".dpx")) {
- extension = extension_test;
- }
- }
-#endif
-#ifdef WITH_OPENJPEG
- else if (imtype == R_IMF_IMTYPE_JP2) {
- if (im_format) {
- if (im_format->jp2_codec == R_IMF_JP2_CODEC_JP2) {
- if (!BLI_path_extension_check(string, extension_test = ".jp2")) {
- extension = extension_test;
- }
- }
- else if (im_format->jp2_codec == R_IMF_JP2_CODEC_J2K) {
- if (!BLI_path_extension_check(string, extension_test = ".j2c")) {
- extension = extension_test;
- }
- }
- else {
- BLI_assert_msg(0, "Unsupported jp2 codec was specified in im_format->jp2_codec");
- }
- }
- else {
- if (!BLI_path_extension_check(string, extension_test = ".jp2")) {
- extension = extension_test;
- }
- }
- }
-#endif
- else { // R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG, R_IMF_IMTYPE_JPEG90 etc
- if (!(BLI_path_extension_check_n(string, extension_test = ".jpg", ".jpeg", nullptr))) {
- extension = extension_test;
- }
- }
-
- if (extension) {
- /* prefer this in many cases to avoid .png.tga, but in certain cases it breaks */
- /* remove any other known image extension */
- if (BLI_path_extension_check_array(string, imb_ext_image)) {
- return BLI_path_extension_replace(string, FILE_MAX, extension);
- }
-
- return BLI_path_extension_ensure(string, FILE_MAX, extension);
- }
-
- return false;
-}
-
-int BKE_image_path_ensure_ext_from_imformat(char *string, const ImageFormatData *im_format)
-{
- return do_add_image_extension(string, im_format->imtype, im_format);
-}
-
-int BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype)
-{
- return do_add_image_extension(string, imtype, nullptr);
-}
-
-void BKE_imformat_defaults(ImageFormatData *im_format)
-{
- memset(im_format, 0, sizeof(*im_format));
- im_format->planes = R_IMF_PLANES_RGBA;
- im_format->imtype = R_IMF_IMTYPE_PNG;
- im_format->depth = R_IMF_CHAN_DEPTH_8;
- im_format->quality = 90;
- im_format->compress = 15;
-
- BKE_color_managed_display_settings_init(&im_format->display_settings);
- BKE_color_managed_view_settings_init_default(&im_format->view_settings,
- &im_format->display_settings);
-}
-
-void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *imbuf)
-{
- int ftype = imbuf->ftype;
- int custom_flags = imbuf->foptions.flag;
- char quality = imbuf->foptions.quality;
-
- BKE_imformat_defaults(im_format);
-
- /* file type */
-
- if (ftype == IMB_FTYPE_IMAGIC) {
- im_format->imtype = R_IMF_IMTYPE_IRIS;
- }
-#ifdef WITH_HDR
- else if (ftype == IMB_FTYPE_RADHDR) {
- im_format->imtype = R_IMF_IMTYPE_RADHDR;
- }
-#endif
- else if (ftype == IMB_FTYPE_PNG) {
- im_format->imtype = R_IMF_IMTYPE_PNG;
-
- if (custom_flags & PNG_16BIT) {
- im_format->depth = R_IMF_CHAN_DEPTH_16;
- }
-
- im_format->compress = quality;
- }
-
-#ifdef WITH_DDS
- else if (ftype == IMB_FTYPE_DDS) {
- im_format->imtype = R_IMF_IMTYPE_DDS;
- }
-#endif
- else if (ftype == IMB_FTYPE_BMP) {
- im_format->imtype = R_IMF_IMTYPE_BMP;
- }
-#ifdef WITH_TIFF
- else if (ftype == IMB_FTYPE_TIF) {
- im_format->imtype = R_IMF_IMTYPE_TIFF;
- if (custom_flags & TIF_16BIT) {
- im_format->depth = R_IMF_CHAN_DEPTH_16;
- }
- if (custom_flags & TIF_COMPRESS_NONE) {
- im_format->tiff_codec = R_IMF_TIFF_CODEC_NONE;
- }
- if (custom_flags & TIF_COMPRESS_DEFLATE) {
- im_format->tiff_codec = R_IMF_TIFF_CODEC_DEFLATE;
- }
- if (custom_flags & TIF_COMPRESS_LZW) {
- im_format->tiff_codec = R_IMF_TIFF_CODEC_LZW;
- }
- if (custom_flags & TIF_COMPRESS_PACKBITS) {
- im_format->tiff_codec = R_IMF_TIFF_CODEC_PACKBITS;
- }
- }
-#endif
-
-#ifdef WITH_OPENEXR
- else if (ftype == IMB_FTYPE_OPENEXR) {
- im_format->imtype = R_IMF_IMTYPE_OPENEXR;
- if (custom_flags & OPENEXR_HALF) {
- im_format->depth = R_IMF_CHAN_DEPTH_16;
- }
- if (custom_flags & OPENEXR_COMPRESS) {
- im_format->exr_codec = R_IMF_EXR_CODEC_ZIP; /* Can't determine compression */
- }
- if (imbuf->zbuf_float) {
- im_format->flag |= R_IMF_FLAG_ZBUF;
- }
- }
-#endif
-
-#ifdef WITH_CINEON
- else if (ftype == IMB_FTYPE_CINEON) {
- im_format->imtype = R_IMF_IMTYPE_CINEON;
- }
- else if (ftype == IMB_FTYPE_DPX) {
- im_format->imtype = R_IMF_IMTYPE_DPX;
- }
-#endif
- else if (ftype == IMB_FTYPE_TGA) {
- if (custom_flags & RAWTGA) {
- im_format->imtype = R_IMF_IMTYPE_RAWTGA;
- }
- else {
- im_format->imtype = R_IMF_IMTYPE_TARGA;
- }
- }
-#ifdef WITH_OPENJPEG
- else if (ftype == IMB_FTYPE_JP2) {
- im_format->imtype = R_IMF_IMTYPE_JP2;
- im_format->quality = quality;
-
- if (custom_flags & JP2_16BIT) {
- im_format->depth = R_IMF_CHAN_DEPTH_16;
- }
- else if (custom_flags & JP2_12BIT) {
- im_format->depth = R_IMF_CHAN_DEPTH_12;
- }
-
- if (custom_flags & JP2_YCC) {
- im_format->jp2_flag |= R_IMF_JP2_FLAG_YCC;
- }
-
- if (custom_flags & JP2_CINE) {
- im_format->jp2_flag |= R_IMF_JP2_FLAG_CINE_PRESET;
- if (custom_flags & JP2_CINE_48FPS) {
- im_format->jp2_flag |= R_IMF_JP2_FLAG_CINE_48;
- }
- }
-
- if (custom_flags & JP2_JP2) {
- im_format->jp2_codec = R_IMF_JP2_CODEC_JP2;
- }
- else if (custom_flags & JP2_J2K) {
- im_format->jp2_codec = R_IMF_JP2_CODEC_J2K;
- }
- else {
- BLI_assert_msg(0, "Unsupported jp2 codec was specified in file type");
- }
- }
-#endif
-
- else {
- im_format->imtype = R_IMF_IMTYPE_JPEG90;
- im_format->quality = quality;
- }
-
- /* planes */
- im_format->planes = imbuf->planes;
-}
-
#define STAMP_NAME_SIZE ((MAX_ID_NAME - 2) + 16)
/* could allow access externally - 512 is for long names,
* STAMP_NAME_SIZE is for id names, allowing them some room for description */
@@ -2943,9 +2342,9 @@ static void metadata_get_field(void *data, const char *propname, char *propvalue
IMB_metadata_get_field(imbuf->metadata, propname, propvalue, len);
}
-void BKE_imbuf_stamp_info(RenderResult *rr, struct ImBuf *ibuf)
+void BKE_imbuf_stamp_info(const RenderResult *rr, ImBuf *ibuf)
{
- struct StampData *stamp_data = rr->stamp_data;
+ StampData *stamp_data = const_cast<StampData *>(rr->stamp_data);
IMB_metadata_ensure(&ibuf->metadata);
BKE_stamp_info_callback(ibuf, stamp_data, metadata_set_field, false);
}
@@ -2959,12 +2358,12 @@ static void metadata_copy_custom_fields(const char *field, const char *value, vo
BKE_render_result_stamp_data(rr, field, value);
}
-void BKE_stamp_info_from_imbuf(RenderResult *rr, struct ImBuf *ibuf)
+void BKE_stamp_info_from_imbuf(RenderResult *rr, ImBuf *ibuf)
{
if (rr->stamp_data == nullptr) {
rr->stamp_data = MEM_cnew<StampData>("RenderResult.stamp_data");
}
- struct StampData *stamp_data = rr->stamp_data;
+ StampData *stamp_data = rr->stamp_data;
IMB_metadata_ensure(&ibuf->metadata);
BKE_stamp_info_callback(ibuf, stamp_data, metadata_get_field, true);
/* Copy render engine specific settings. */
@@ -2994,171 +2393,9 @@ bool BKE_imbuf_alpha_test(ImBuf *ibuf)
return false;
}
-void BKE_imbuf_write_prepare(ImBuf *ibuf, const ImageFormatData *imf)
-{
- char imtype = imf->imtype;
- char compress = imf->compress;
- char quality = imf->quality;
-
- /* initialize all from image format */
- ibuf->foptions.flag = 0;
-
- if (imtype == R_IMF_IMTYPE_IRIS) {
- ibuf->ftype = IMB_FTYPE_IMAGIC;
- }
-#ifdef WITH_HDR
- else if (imtype == R_IMF_IMTYPE_RADHDR) {
- ibuf->ftype = IMB_FTYPE_RADHDR;
- }
-#endif
- else if (ELEM(imtype,
- R_IMF_IMTYPE_PNG,
- R_IMF_IMTYPE_FFMPEG,
- R_IMF_IMTYPE_H264,
- R_IMF_IMTYPE_THEORA,
- R_IMF_IMTYPE_XVID)) {
- ibuf->ftype = IMB_FTYPE_PNG;
-
- if (imtype == R_IMF_IMTYPE_PNG) {
- if (imf->depth == R_IMF_CHAN_DEPTH_16) {
- ibuf->foptions.flag |= PNG_16BIT;
- }
-
- ibuf->foptions.quality = compress;
- }
- }
-#ifdef WITH_DDS
- else if (imtype == R_IMF_IMTYPE_DDS) {
- ibuf->ftype = IMB_FTYPE_DDS;
- }
-#endif
- else if (imtype == R_IMF_IMTYPE_BMP) {
- ibuf->ftype = IMB_FTYPE_BMP;
- }
-#ifdef WITH_TIFF
- else if (imtype == R_IMF_IMTYPE_TIFF) {
- ibuf->ftype = IMB_FTYPE_TIF;
-
- if (imf->depth == R_IMF_CHAN_DEPTH_16) {
- ibuf->foptions.flag |= TIF_16BIT;
- }
- if (imf->tiff_codec == R_IMF_TIFF_CODEC_NONE) {
- ibuf->foptions.flag |= TIF_COMPRESS_NONE;
- }
- else if (imf->tiff_codec == R_IMF_TIFF_CODEC_DEFLATE) {
- ibuf->foptions.flag |= TIF_COMPRESS_DEFLATE;
- }
- else if (imf->tiff_codec == R_IMF_TIFF_CODEC_LZW) {
- ibuf->foptions.flag |= TIF_COMPRESS_LZW;
- }
- else if (imf->tiff_codec == R_IMF_TIFF_CODEC_PACKBITS) {
- ibuf->foptions.flag |= TIF_COMPRESS_PACKBITS;
- }
- }
-#endif
-#ifdef WITH_OPENEXR
- else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
- ibuf->ftype = IMB_FTYPE_OPENEXR;
- if (imf->depth == R_IMF_CHAN_DEPTH_16) {
- ibuf->foptions.flag |= OPENEXR_HALF;
- }
- ibuf->foptions.flag |= (imf->exr_codec & OPENEXR_COMPRESS);
-
- if (!(imf->flag & R_IMF_FLAG_ZBUF)) {
- /* Signal for exr saving. */
- IMB_freezbuffloatImBuf(ibuf);
- }
- }
-#endif
-#ifdef WITH_CINEON
- else if (imtype == R_IMF_IMTYPE_CINEON) {
- ibuf->ftype = IMB_FTYPE_CINEON;
- if (imf->cineon_flag & R_IMF_CINEON_FLAG_LOG) {
- ibuf->foptions.flag |= CINEON_LOG;
- }
- if (imf->depth == R_IMF_CHAN_DEPTH_16) {
- ibuf->foptions.flag |= CINEON_16BIT;
- }
- else if (imf->depth == R_IMF_CHAN_DEPTH_12) {
- ibuf->foptions.flag |= CINEON_12BIT;
- }
- else if (imf->depth == R_IMF_CHAN_DEPTH_10) {
- ibuf->foptions.flag |= CINEON_10BIT;
- }
- }
- else if (imtype == R_IMF_IMTYPE_DPX) {
- ibuf->ftype = IMB_FTYPE_DPX;
- if (imf->cineon_flag & R_IMF_CINEON_FLAG_LOG) {
- ibuf->foptions.flag |= CINEON_LOG;
- }
- if (imf->depth == R_IMF_CHAN_DEPTH_16) {
- ibuf->foptions.flag |= CINEON_16BIT;
- }
- else if (imf->depth == R_IMF_CHAN_DEPTH_12) {
- ibuf->foptions.flag |= CINEON_12BIT;
- }
- else if (imf->depth == R_IMF_CHAN_DEPTH_10) {
- ibuf->foptions.flag |= CINEON_10BIT;
- }
- }
-#endif
- else if (imtype == R_IMF_IMTYPE_TARGA) {
- ibuf->ftype = IMB_FTYPE_TGA;
- }
- else if (imtype == R_IMF_IMTYPE_RAWTGA) {
- ibuf->ftype = IMB_FTYPE_TGA;
- ibuf->foptions.flag = RAWTGA;
- }
-#ifdef WITH_OPENJPEG
- else if (imtype == R_IMF_IMTYPE_JP2) {
- if (quality < 10) {
- quality = 90;
- }
- ibuf->ftype = IMB_FTYPE_JP2;
- ibuf->foptions.quality = quality;
-
- if (imf->depth == R_IMF_CHAN_DEPTH_16) {
- ibuf->foptions.flag |= JP2_16BIT;
- }
- else if (imf->depth == R_IMF_CHAN_DEPTH_12) {
- ibuf->foptions.flag |= JP2_12BIT;
- }
-
- if (imf->jp2_flag & R_IMF_JP2_FLAG_YCC) {
- ibuf->foptions.flag |= JP2_YCC;
- }
-
- if (imf->jp2_flag & R_IMF_JP2_FLAG_CINE_PRESET) {
- ibuf->foptions.flag |= JP2_CINE;
- if (imf->jp2_flag & R_IMF_JP2_FLAG_CINE_48) {
- ibuf->foptions.flag |= JP2_CINE_48FPS;
- }
- }
-
- if (imf->jp2_codec == R_IMF_JP2_CODEC_JP2) {
- ibuf->foptions.flag |= JP2_JP2;
- }
- else if (imf->jp2_codec == R_IMF_JP2_CODEC_J2K) {
- ibuf->foptions.flag |= JP2_J2K;
- }
- else {
- BLI_assert_msg(0, "Unsupported jp2 codec was specified in im_format->jp2_codec");
- }
- }
-#endif
- else {
- /* #R_IMF_IMTYPE_JPEG90, etc. fallback to JPEG image. */
- if (quality < 10) {
- quality = 90;
- }
- ibuf->ftype = IMB_FTYPE_JPG;
- ibuf->foptions.quality = quality;
- }
-}
-
int BKE_imbuf_write(ImBuf *ibuf, const char *name, const ImageFormatData *imf)
{
- BKE_imbuf_write_prepare(ibuf, imf);
+ BKE_image_format_to_imbuf(ibuf, imf);
BLI_make_existing_file(name);
@@ -3190,8 +2427,8 @@ int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf, cons
return ok;
}
-int BKE_imbuf_write_stamp(Scene *scene,
- struct RenderResult *rr,
+int BKE_imbuf_write_stamp(const Scene *scene,
+ const struct RenderResult *rr,
ImBuf *ibuf,
const char *name,
const struct ImageFormatData *imf)
@@ -3203,60 +2440,6 @@ int BKE_imbuf_write_stamp(Scene *scene,
return BKE_imbuf_write(ibuf, name, imf);
}
-static void do_makepicstring(char *string,
- const char *base,
- const char *relbase,
- int frame,
- const char imtype,
- const ImageFormatData *im_format,
- const bool use_ext,
- const bool use_frames,
- const char *suffix)
-{
- if (string == nullptr) {
- return;
- }
- BLI_strncpy(string, base, FILE_MAX - 10); /* weak assumption */
- BLI_path_abs(string, relbase);
-
- if (use_frames) {
- BLI_path_frame(string, frame, 4);
- }
-
- if (suffix) {
- BLI_path_suffix(string, FILE_MAX, suffix, "");
- }
-
- if (use_ext) {
- do_add_image_extension(string, imtype, im_format);
- }
-}
-
-void BKE_image_path_from_imformat(char *string,
- const char *base,
- const char *relbase,
- int frame,
- const ImageFormatData *im_format,
- const bool use_ext,
- const bool use_frames,
- const char *suffix)
-{
- do_makepicstring(
- string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames, suffix);
-}
-
-void BKE_image_path_from_imtype(char *string,
- const char *base,
- const char *relbase,
- int frame,
- const char imtype,
- const bool use_ext,
- const bool use_frames,
- const char *suffix)
-{
- do_makepicstring(string, base, relbase, frame, imtype, nullptr, use_ext, use_frames, suffix);
-}
-
struct anim *openanim_noload(const char *name,
int flags,
int streamindex,
@@ -3930,14 +3113,15 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *tile_start, i
int max_udim = 0;
int id;
- struct direntry *dir;
- uint totfile = BLI_filelist_dir_contents(dirname, &dir);
- for (int i = 0; i < totfile; i++) {
- if (!(dir[i].type & S_IFREG)) {
+ struct direntry *dirs;
+ const uint dirs_num = BLI_filelist_dir_contents(dirname, &dirs);
+ for (int i = 0; i < dirs_num; i++) {
+ if (!(dirs[i].type & S_IFREG)) {
continue;
}
- if (!BKE_image_get_tile_number_from_filepath(dir[i].relname, udim_pattern, tile_format, &id)) {
+ if (!BKE_image_get_tile_number_from_filepath(
+ dirs[i].relname, udim_pattern, tile_format, &id)) {
continue;
}
@@ -3950,7 +3134,7 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *tile_start, i
min_udim = min_ii(min_udim, id);
max_udim = max_ii(max_udim, id);
}
- BLI_filelist_free(dir, totfile);
+ BLI_filelist_free(dirs, dirs_num);
MEM_SAFE_FREE(udim_pattern);
if (is_udim && min_udim <= IMA_UDIM_MAX) {
@@ -4135,69 +3319,24 @@ void BKE_image_ensure_tile_token(char *filename)
return;
}
- /* Is there a sequence of digits in the filename? */
- ushort digits;
- char head[FILE_MAX], tail[FILE_MAX];
- BLI_path_sequence_decode(filename, head, tail, &digits);
- if (digits == 4) {
- sprintf(filename, "%s<UDIM>%s", head, tail);
- return;
- }
+ std::string path(filename);
+ std::smatch match;
- /* Is there a sequence like u##_v#### in the filename? */
- uint cur = 0;
- uint name_end = strlen(filename);
- uint u_digits = 0;
- uint v_digits = 0;
- uint u_start = (uint)-1;
- bool u_found = false;
- bool v_found = false;
- bool sep_found = false;
- while (cur < name_end) {
- if (filename[cur] == 'u') {
- u_found = true;
- u_digits = 0;
- u_start = cur;
- }
- else if (filename[cur] == 'v') {
- v_found = true;
- v_digits = 0;
- }
- else if (u_found && !v_found) {
- if (isdigit(filename[cur]) && u_digits < 2) {
- u_digits++;
- }
- else if (filename[cur] == '_') {
- sep_found = true;
- }
- else {
- u_found = false;
- }
- }
- else if (u_found && u_digits > 0 && v_found) {
- if (isdigit(filename[cur])) {
- if (v_digits < 4) {
- v_digits++;
- }
- else {
- u_found = false;
- v_found = false;
- }
- }
- else if (v_digits > 0) {
- break;
- }
- }
-
- cur++;
+ /* General 4-digit "udim" pattern. As this format is susceptible to ambiguity
+ * with other digit sequences, we can leverage the supported range of roughly
+ * 1000 through 2000 to provide better detection.
+ */
+ std::regex pattern(R"((^|.*?\D)([12]\d{3})(\D.*))");
+ if (std::regex_search(path, match, pattern)) {
+ BLI_strncpy(filename, match.format("$1<UDIM>$3").c_str(), FILE_MAX);
+ return;
}
- if (u_found && sep_found && v_found && (u_digits + v_digits > 1)) {
- const char *token = "<UVTILE>";
- const size_t token_length = strlen(token);
- memmove(filename + u_start + token_length, filename + cur, name_end - cur);
- memcpy(filename + u_start, token, token_length);
- filename[u_start + token_length + (name_end - cur)] = '\0';
+ /* General `u##_v###` `uvtile` pattern. */
+ pattern = std::regex(R"((.*)(u\d{1,2}_v\d{1,3})(\D.*))");
+ if (std::regex_search(path, match, pattern)) {
+ BLI_strncpy(filename, match.format("$1<UVTILE>$3").c_str(), FILE_MAX);
+ return;
}
}
@@ -4212,15 +3351,15 @@ bool BKE_image_tile_filepath_exists(const char *filepath)
char *udim_pattern = BKE_image_get_tile_strformat(filepath, &tile_format);
bool found = false;
- struct direntry *dir;
- uint totfile = BLI_filelist_dir_contents(dirname, &dir);
- for (int i = 0; i < totfile; i++) {
- if (!(dir[i].type & S_IFREG)) {
+ struct direntry *dirs;
+ const uint dirs_num = BLI_filelist_dir_contents(dirname, &dirs);
+ for (int i = 0; i < dirs_num; i++) {
+ if (!(dirs[i].type & S_IFREG)) {
continue;
}
int id;
- if (!BKE_image_get_tile_number_from_filepath(dir[i].path, udim_pattern, tile_format, &id)) {
+ if (!BKE_image_get_tile_number_from_filepath(dirs[i].path, udim_pattern, tile_format, &id)) {
continue;
}
@@ -4231,7 +3370,7 @@ bool BKE_image_tile_filepath_exists(const char *filepath)
found = true;
break;
}
- BLI_filelist_free(dir, totfile);
+ BLI_filelist_free(dirs, dirs_num);
MEM_SAFE_FREE(udim_pattern);
return found;
@@ -5105,31 +4244,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc
RE_AcquireResultImage(re, &rres, actview);
}
else if ((slot = BKE_image_get_renderslot(ima, ima->render_slot))->render) {
- /* Unfortunately each field needs to be set individually because RenderResult
- * contains volatile fields and using memcpy would invoke undefined behavior with c++. */
- rres.next = slot->render->next;
- rres.prev = slot->render->prev;
- rres.rectx = slot->render->rectx;
- rres.recty = slot->render->recty;
- rres.sample_nr = slot->render->sample_nr;
- rres.rect32 = slot->render->rect32;
- rres.rectf = slot->render->rectf;
- rres.rectz = slot->render->rectz;
- rres.tilerect = slot->render->tilerect;
- rres.xof = slot->render->xof;
- rres.yof = slot->render->yof;
- rres.layers = slot->render->layers;
- rres.views = slot->render->views;
- rres.renrect.xmin = slot->render->renrect.xmin;
- rres.renrect.xmax = slot->render->renrect.xmax;
- rres.renrect.ymin = slot->render->renrect.ymin;
- rres.renrect.ymax = slot->render->renrect.ymax;
- rres.renlay = slot->render->renlay;
- rres.framenr = slot->render->framenr;
- rres.text = slot->render->text;
- rres.error = slot->render->error;
- rres.stamp_data = slot->render->stamp_data;
- rres.passes_allocated = slot->render->passes_allocated;
+ rres = *(slot->render);
rres.have_combined = ((RenderView *)rres.views.first)->rectf != nullptr;
}
@@ -5292,7 +4407,7 @@ static int image_get_multiview_index(Image *ima, ImageUser *iuser)
}
if (is_backdrop) {
if (BKE_image_is_stereo(ima)) {
- /* backdrop hackaround (since there is no iuser */
+ /* Backdrop hack / workaround (since there is no `iuser`). */
return ima->eye;
}
}
@@ -5939,7 +5054,7 @@ void BKE_image_user_file_path_ex(ImageUser *iuser, Image *ima, char *filepath, b
bool BKE_image_has_alpha(Image *image)
{
void *lock;
- ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, nullptr, &lock);
const int planes = (ibuf ? ibuf->planes : 0);
BKE_image_release_ibuf(image, ibuf, lock);
@@ -6140,8 +5255,8 @@ bool BKE_image_buffer_format_writable(ImBuf *ibuf)
{
ImageFormatData im_format;
ImbFormatOptions options_dummy;
- BKE_imbuf_to_image_format(&im_format, ibuf);
- return (BKE_image_imtype_to_ftype(im_format.imtype, &options_dummy) == ibuf->ftype);
+ BKE_image_format_from_imbuf(&im_format, ibuf);
+ return (BKE_imtype_to_ftype(im_format.imtype, &options_dummy) == ibuf->ftype);
}
void BKE_image_file_format_set(Image *image, int ftype, const ImbFormatOptions *options)
diff --git a/source/blender/blenkernel/intern/image_format.cc b/source/blender/blenkernel/intern/image_format.cc
new file mode 100644
index 00000000000..3ff0b3da963
--- /dev/null
+++ b/source/blender/blenkernel/intern/image_format.cc
@@ -0,0 +1,966 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <cstring>
+
+#include "DNA_defaults.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_image_format.h"
+
+/* Init/Copy/Free */
+
+void BKE_image_format_init(ImageFormatData *imf, const bool render)
+{
+ *imf = *DNA_struct_default_get(ImageFormatData);
+
+ BKE_color_managed_display_settings_init(&imf->display_settings);
+
+ if (render) {
+ BKE_color_managed_view_settings_init_render(
+ &imf->view_settings, &imf->display_settings, "Filmic");
+ }
+ else {
+ BKE_color_managed_view_settings_init_default(&imf->view_settings, &imf->display_settings);
+ }
+
+ BKE_color_managed_colorspace_settings_init(&imf->linear_colorspace_settings);
+}
+
+void BKE_image_format_copy(ImageFormatData *imf_dst, const ImageFormatData *imf_src)
+{
+ memcpy(imf_dst, imf_src, sizeof(*imf_dst));
+ BKE_color_managed_display_settings_copy(&imf_dst->display_settings, &imf_src->display_settings);
+ BKE_color_managed_view_settings_copy(&imf_dst->view_settings, &imf_src->view_settings);
+ BKE_color_managed_colorspace_settings_copy(&imf_dst->linear_colorspace_settings,
+ &imf_src->linear_colorspace_settings);
+}
+
+void BKE_image_format_free(ImageFormatData *imf)
+{
+ BKE_color_managed_view_settings_free(&imf->view_settings);
+}
+
+void BKE_image_format_blend_read_data(BlendDataReader *reader, ImageFormatData *imf)
+{
+ BKE_color_managed_view_settings_blend_read_data(reader, &imf->view_settings);
+}
+
+void BKE_image_format_blend_write(BlendWriter *writer, ImageFormatData *imf)
+{
+ BKE_color_managed_view_settings_blend_write(writer, &imf->view_settings);
+}
+
+/* File Types */
+
+int BKE_imtype_to_ftype(const char imtype, ImbFormatOptions *r_options)
+{
+ memset(r_options, 0, sizeof(*r_options));
+
+ if (imtype == R_IMF_IMTYPE_TARGA) {
+ return IMB_FTYPE_TGA;
+ }
+ if (imtype == R_IMF_IMTYPE_RAWTGA) {
+ r_options->flag = RAWTGA;
+ return IMB_FTYPE_TGA;
+ }
+ if (imtype == R_IMF_IMTYPE_IRIS) {
+ return IMB_FTYPE_IMAGIC;
+ }
+#ifdef WITH_HDR
+ if (imtype == R_IMF_IMTYPE_RADHDR) {
+ return IMB_FTYPE_RADHDR;
+ }
+#endif
+ if (imtype == R_IMF_IMTYPE_PNG) {
+ r_options->quality = 15;
+ return IMB_FTYPE_PNG;
+ }
+#ifdef WITH_DDS
+ if (imtype == R_IMF_IMTYPE_DDS) {
+ return IMB_FTYPE_DDS;
+ }
+#endif
+ if (imtype == R_IMF_IMTYPE_BMP) {
+ return IMB_FTYPE_BMP;
+ }
+#ifdef WITH_TIFF
+ if (imtype == R_IMF_IMTYPE_TIFF) {
+ return IMB_FTYPE_TIF;
+ }
+#endif
+ if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
+ return IMB_FTYPE_OPENEXR;
+ }
+#ifdef WITH_CINEON
+ if (imtype == R_IMF_IMTYPE_CINEON) {
+ return IMB_FTYPE_CINEON;
+ }
+ if (imtype == R_IMF_IMTYPE_DPX) {
+ return IMB_FTYPE_DPX;
+ }
+#endif
+#ifdef WITH_OPENJPEG
+ if (imtype == R_IMF_IMTYPE_JP2) {
+ r_options->flag |= JP2_JP2;
+ r_options->quality = 90;
+ return IMB_FTYPE_JP2;
+ }
+#endif
+#ifdef WITH_WEBP
+ if (imtype == R_IMF_IMTYPE_WEBP) {
+ r_options->quality = 90;
+ return IMB_FTYPE_WEBP;
+ }
+#endif
+
+ r_options->quality = 90;
+ return IMB_FTYPE_JPG;
+}
+
+char BKE_ftype_to_imtype(const int ftype, const ImbFormatOptions *options)
+{
+ if (ftype == IMB_FTYPE_NONE) {
+ return R_IMF_IMTYPE_TARGA;
+ }
+ if (ftype == IMB_FTYPE_IMAGIC) {
+ return R_IMF_IMTYPE_IRIS;
+ }
+#ifdef WITH_HDR
+ if (ftype == IMB_FTYPE_RADHDR) {
+ return R_IMF_IMTYPE_RADHDR;
+ }
+#endif
+ if (ftype == IMB_FTYPE_PNG) {
+ return R_IMF_IMTYPE_PNG;
+ }
+#ifdef WITH_DDS
+ if (ftype == IMB_FTYPE_DDS) {
+ return R_IMF_IMTYPE_DDS;
+ }
+#endif
+ if (ftype == IMB_FTYPE_BMP) {
+ return R_IMF_IMTYPE_BMP;
+ }
+#ifdef WITH_TIFF
+ if (ftype == IMB_FTYPE_TIF) {
+ return R_IMF_IMTYPE_TIFF;
+ }
+#endif
+ if (ftype == IMB_FTYPE_OPENEXR) {
+ return R_IMF_IMTYPE_OPENEXR;
+ }
+#ifdef WITH_CINEON
+ if (ftype == IMB_FTYPE_CINEON) {
+ return R_IMF_IMTYPE_CINEON;
+ }
+ if (ftype == IMB_FTYPE_DPX) {
+ return R_IMF_IMTYPE_DPX;
+ }
+#endif
+ if (ftype == IMB_FTYPE_TGA) {
+ if (options && (options->flag & RAWTGA)) {
+ return R_IMF_IMTYPE_RAWTGA;
+ }
+
+ return R_IMF_IMTYPE_TARGA;
+ }
+#ifdef WITH_OPENJPEG
+ if (ftype == IMB_FTYPE_JP2) {
+ return R_IMF_IMTYPE_JP2;
+ }
+#endif
+#ifdef WITH_WEBP
+ if (ftype == IMB_FTYPE_WEBP) {
+ return R_IMF_IMTYPE_WEBP;
+ }
+#endif
+
+ return R_IMF_IMTYPE_JPEG90;
+}
+
+bool BKE_imtype_is_movie(const char imtype)
+{
+ switch (imtype) {
+ case R_IMF_IMTYPE_AVIRAW:
+ case R_IMF_IMTYPE_AVIJPEG:
+ case R_IMF_IMTYPE_FFMPEG:
+ case R_IMF_IMTYPE_H264:
+ case R_IMF_IMTYPE_THEORA:
+ case R_IMF_IMTYPE_XVID:
+ return true;
+ }
+ return false;
+}
+
+bool BKE_imtype_supports_zbuf(const char imtype)
+{
+ switch (imtype) {
+ case R_IMF_IMTYPE_IRIZ:
+ case R_IMF_IMTYPE_OPENEXR: /* but not R_IMF_IMTYPE_MULTILAYER */
+ return true;
+ }
+ return false;
+}
+
+bool BKE_imtype_supports_compress(const char imtype)
+{
+ switch (imtype) {
+ case R_IMF_IMTYPE_PNG:
+ return true;
+ }
+ return false;
+}
+
+bool BKE_imtype_supports_quality(const char imtype)
+{
+ switch (imtype) {
+ case R_IMF_IMTYPE_JPEG90:
+ case R_IMF_IMTYPE_JP2:
+ case R_IMF_IMTYPE_AVIJPEG:
+ case R_IMF_IMTYPE_WEBP:
+ return true;
+ }
+ return false;
+}
+
+bool BKE_imtype_requires_linear_float(const char imtype)
+{
+ switch (imtype) {
+ case R_IMF_IMTYPE_CINEON:
+ case R_IMF_IMTYPE_DPX:
+ case R_IMF_IMTYPE_RADHDR:
+ case R_IMF_IMTYPE_OPENEXR:
+ case R_IMF_IMTYPE_MULTILAYER:
+ return true;
+ }
+ return false;
+}
+
+char BKE_imtype_valid_channels(const char imtype, bool write_file)
+{
+ char chan_flag = IMA_CHAN_FLAG_RGB; /* Assume all support RGB. */
+
+ /* Alpha. */
+ switch (imtype) {
+ case R_IMF_IMTYPE_BMP:
+ if (write_file) {
+ break;
+ }
+ ATTR_FALLTHROUGH;
+ case R_IMF_IMTYPE_TARGA:
+ case R_IMF_IMTYPE_RAWTGA:
+ case R_IMF_IMTYPE_IRIS:
+ case R_IMF_IMTYPE_PNG:
+ case R_IMF_IMTYPE_TIFF:
+ case R_IMF_IMTYPE_OPENEXR:
+ case R_IMF_IMTYPE_MULTILAYER:
+ case R_IMF_IMTYPE_DDS:
+ case R_IMF_IMTYPE_JP2:
+ case R_IMF_IMTYPE_DPX:
+ case R_IMF_IMTYPE_WEBP:
+ chan_flag |= IMA_CHAN_FLAG_ALPHA;
+ break;
+ }
+
+ /* BW. */
+ switch (imtype) {
+ case R_IMF_IMTYPE_BMP:
+ case R_IMF_IMTYPE_PNG:
+ case R_IMF_IMTYPE_JPEG90:
+ case R_IMF_IMTYPE_TARGA:
+ case R_IMF_IMTYPE_RAWTGA:
+ case R_IMF_IMTYPE_TIFF:
+ case R_IMF_IMTYPE_IRIS:
+ chan_flag |= IMA_CHAN_FLAG_BW;
+ break;
+ }
+
+ return chan_flag;
+}
+
+char BKE_imtype_valid_depths(const char imtype)
+{
+ switch (imtype) {
+ case R_IMF_IMTYPE_RADHDR:
+ return R_IMF_CHAN_DEPTH_32;
+ case R_IMF_IMTYPE_TIFF:
+ return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_16;
+ case R_IMF_IMTYPE_OPENEXR:
+ return R_IMF_CHAN_DEPTH_16 | R_IMF_CHAN_DEPTH_32;
+ case R_IMF_IMTYPE_MULTILAYER:
+ return R_IMF_CHAN_DEPTH_16 | R_IMF_CHAN_DEPTH_32;
+ /* NOTE: CINEON uses an unusual 10bits-LOG per channel. */
+ case R_IMF_IMTYPE_DPX:
+ return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_10 | R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16;
+ case R_IMF_IMTYPE_CINEON:
+ return R_IMF_CHAN_DEPTH_10;
+ case R_IMF_IMTYPE_JP2:
+ return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16;
+ case R_IMF_IMTYPE_PNG:
+ return R_IMF_CHAN_DEPTH_8 | R_IMF_CHAN_DEPTH_16;
+ /* Most formats are 8bit only. */
+ default:
+ return R_IMF_CHAN_DEPTH_8;
+ }
+}
+
+char BKE_imtype_from_arg(const char *imtype_arg)
+{
+ if (STREQ(imtype_arg, "TGA")) {
+ return R_IMF_IMTYPE_TARGA;
+ }
+ if (STREQ(imtype_arg, "IRIS")) {
+ return R_IMF_IMTYPE_IRIS;
+ }
+#ifdef WITH_DDS
+ if (STREQ(imtype_arg, "DDS")) {
+ return R_IMF_IMTYPE_DDS;
+ }
+#endif
+ if (STREQ(imtype_arg, "JPEG")) {
+ return R_IMF_IMTYPE_JPEG90;
+ }
+ if (STREQ(imtype_arg, "IRIZ")) {
+ return R_IMF_IMTYPE_IRIZ;
+ }
+ if (STREQ(imtype_arg, "RAWTGA")) {
+ return R_IMF_IMTYPE_RAWTGA;
+ }
+ if (STREQ(imtype_arg, "AVIRAW")) {
+ return R_IMF_IMTYPE_AVIRAW;
+ }
+ if (STREQ(imtype_arg, "AVIJPEG")) {
+ return R_IMF_IMTYPE_AVIJPEG;
+ }
+ if (STREQ(imtype_arg, "PNG")) {
+ return R_IMF_IMTYPE_PNG;
+ }
+ if (STREQ(imtype_arg, "BMP")) {
+ return R_IMF_IMTYPE_BMP;
+ }
+#ifdef WITH_HDR
+ if (STREQ(imtype_arg, "HDR")) {
+ return R_IMF_IMTYPE_RADHDR;
+ }
+#endif
+#ifdef WITH_TIFF
+ if (STREQ(imtype_arg, "TIFF")) {
+ return R_IMF_IMTYPE_TIFF;
+ }
+#endif
+#ifdef WITH_OPENEXR
+ if (STREQ(imtype_arg, "OPEN_EXR")) {
+ return R_IMF_IMTYPE_OPENEXR;
+ }
+ if (STREQ(imtype_arg, "OPEN_EXR_MULTILAYER")) {
+ return R_IMF_IMTYPE_MULTILAYER;
+ }
+ if (STREQ(imtype_arg, "EXR")) {
+ return R_IMF_IMTYPE_OPENEXR;
+ }
+ if (STREQ(imtype_arg, "MULTILAYER")) {
+ return R_IMF_IMTYPE_MULTILAYER;
+ }
+#endif
+ if (STREQ(imtype_arg, "FFMPEG")) {
+ return R_IMF_IMTYPE_FFMPEG;
+ }
+#ifdef WITH_CINEON
+ if (STREQ(imtype_arg, "CINEON")) {
+ return R_IMF_IMTYPE_CINEON;
+ }
+ if (STREQ(imtype_arg, "DPX")) {
+ return R_IMF_IMTYPE_DPX;
+ }
+#endif
+#ifdef WITH_OPENJPEG
+ if (STREQ(imtype_arg, "JP2")) {
+ return R_IMF_IMTYPE_JP2;
+ }
+#endif
+#ifdef WITH_WEBP
+ if (STREQ(imtype_arg, "WEBP")) {
+ return R_IMF_IMTYPE_WEBP;
+ }
+#endif
+
+ return R_IMF_IMTYPE_INVALID;
+}
+
+/* File Paths */
+
+static bool do_add_image_extension(char *string,
+ const char imtype,
+ const ImageFormatData *im_format)
+{
+ const char *extension = nullptr;
+ const char *extension_test;
+ (void)im_format; /* may be unused, depends on build options */
+
+ if (imtype == R_IMF_IMTYPE_IRIS) {
+ if (!BLI_path_extension_check(string, extension_test = ".rgb")) {
+ extension = extension_test;
+ }
+ }
+ else if (imtype == R_IMF_IMTYPE_IRIZ) {
+ if (!BLI_path_extension_check(string, extension_test = ".rgb")) {
+ extension = extension_test;
+ }
+ }
+#ifdef WITH_HDR
+ else if (imtype == R_IMF_IMTYPE_RADHDR) {
+ if (!BLI_path_extension_check(string, extension_test = ".hdr")) {
+ extension = extension_test;
+ }
+ }
+#endif
+ else if (ELEM(imtype,
+ R_IMF_IMTYPE_PNG,
+ R_IMF_IMTYPE_FFMPEG,
+ R_IMF_IMTYPE_H264,
+ R_IMF_IMTYPE_THEORA,
+ R_IMF_IMTYPE_XVID)) {
+ if (!BLI_path_extension_check(string, extension_test = ".png")) {
+ extension = extension_test;
+ }
+ }
+#ifdef WITH_DDS
+ else if (imtype == R_IMF_IMTYPE_DDS) {
+ if (!BLI_path_extension_check(string, extension_test = ".dds")) {
+ extension = extension_test;
+ }
+ }
+#endif
+ else if (ELEM(imtype, R_IMF_IMTYPE_TARGA, R_IMF_IMTYPE_RAWTGA)) {
+ if (!BLI_path_extension_check(string, extension_test = ".tga")) {
+ extension = extension_test;
+ }
+ }
+ else if (imtype == R_IMF_IMTYPE_BMP) {
+ if (!BLI_path_extension_check(string, extension_test = ".bmp")) {
+ extension = extension_test;
+ }
+ }
+#ifdef WITH_TIFF
+ else if (imtype == R_IMF_IMTYPE_TIFF) {
+ if (!BLI_path_extension_check_n(string, extension_test = ".tif", ".tiff", nullptr)) {
+ extension = extension_test;
+ }
+ }
+#endif
+#ifdef WITH_OPENIMAGEIO
+ else if (imtype == R_IMF_IMTYPE_PSD) {
+ if (!BLI_path_extension_check(string, extension_test = ".psd")) {
+ extension = extension_test;
+ }
+ }
+#endif
+#ifdef WITH_OPENEXR
+ else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
+ if (!BLI_path_extension_check(string, extension_test = ".exr")) {
+ extension = extension_test;
+ }
+ }
+#endif
+#ifdef WITH_CINEON
+ else if (imtype == R_IMF_IMTYPE_CINEON) {
+ if (!BLI_path_extension_check(string, extension_test = ".cin")) {
+ extension = extension_test;
+ }
+ }
+ else if (imtype == R_IMF_IMTYPE_DPX) {
+ if (!BLI_path_extension_check(string, extension_test = ".dpx")) {
+ extension = extension_test;
+ }
+ }
+#endif
+#ifdef WITH_OPENJPEG
+ else if (imtype == R_IMF_IMTYPE_JP2) {
+ if (im_format) {
+ if (im_format->jp2_codec == R_IMF_JP2_CODEC_JP2) {
+ if (!BLI_path_extension_check(string, extension_test = ".jp2")) {
+ extension = extension_test;
+ }
+ }
+ else if (im_format->jp2_codec == R_IMF_JP2_CODEC_J2K) {
+ if (!BLI_path_extension_check(string, extension_test = ".j2c")) {
+ extension = extension_test;
+ }
+ }
+ else {
+ BLI_assert_msg(0, "Unsupported jp2 codec was specified in im_format->jp2_codec");
+ }
+ }
+ else {
+ if (!BLI_path_extension_check(string, extension_test = ".jp2")) {
+ extension = extension_test;
+ }
+ }
+ }
+#endif
+#ifdef WITH_WEBP
+ else if (imtype == R_IMF_IMTYPE_WEBP) {
+ if (!BLI_path_extension_check(string, extension_test = ".webp"))
+ extension = extension_test;
+ }
+#endif
+ else { // R_IMF_IMTYPE_AVIRAW, R_IMF_IMTYPE_AVIJPEG, R_IMF_IMTYPE_JPEG90 etc
+ if (!(BLI_path_extension_check_n(string, extension_test = ".jpg", ".jpeg", nullptr))) {
+ extension = extension_test;
+ }
+ }
+
+ if (extension) {
+ /* prefer this in many cases to avoid .png.tga, but in certain cases it breaks */
+ /* remove any other known image extension */
+ if (BLI_path_extension_check_array(string, imb_ext_image)) {
+ return BLI_path_extension_replace(string, FILE_MAX, extension);
+ }
+
+ return BLI_path_extension_ensure(string, FILE_MAX, extension);
+ }
+
+ return false;
+}
+
+int BKE_image_path_ensure_ext_from_imformat(char *string, const ImageFormatData *im_format)
+{
+ return do_add_image_extension(string, im_format->imtype, im_format);
+}
+
+int BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype)
+{
+ return do_add_image_extension(string, imtype, nullptr);
+}
+
+static void do_makepicstring(char *string,
+ const char *base,
+ const char *relbase,
+ int frame,
+ const char imtype,
+ const ImageFormatData *im_format,
+ const bool use_ext,
+ const bool use_frames,
+ const char *suffix)
+{
+ if (string == nullptr) {
+ return;
+ }
+ BLI_strncpy(string, base, FILE_MAX - 10); /* weak assumption */
+ BLI_path_abs(string, relbase);
+
+ if (use_frames) {
+ BLI_path_frame(string, frame, 4);
+ }
+
+ if (suffix) {
+ BLI_path_suffix(string, FILE_MAX, suffix, "");
+ }
+
+ if (use_ext) {
+ do_add_image_extension(string, imtype, im_format);
+ }
+}
+
+void BKE_image_path_from_imformat(char *string,
+ const char *base,
+ const char *relbase,
+ int frame,
+ const ImageFormatData *im_format,
+ const bool use_ext,
+ const bool use_frames,
+ const char *suffix)
+{
+ do_makepicstring(
+ string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames, suffix);
+}
+
+void BKE_image_path_from_imtype(char *string,
+ const char *base,
+ const char *relbase,
+ int frame,
+ const char imtype,
+ const bool use_ext,
+ const bool use_frames,
+ const char *suffix)
+{
+ do_makepicstring(string, base, relbase, frame, imtype, nullptr, use_ext, use_frames, suffix);
+}
+
+/* ImBuf Conversion */
+
+void BKE_image_format_to_imbuf(ImBuf *ibuf, const ImageFormatData *imf)
+{
+ /* Write to ImBuf in preparation for file writing. */
+ char imtype = imf->imtype;
+ char compress = imf->compress;
+ char quality = imf->quality;
+
+ /* initialize all from image format */
+ ibuf->foptions.flag = 0;
+
+ if (imtype == R_IMF_IMTYPE_IRIS) {
+ ibuf->ftype = IMB_FTYPE_IMAGIC;
+ }
+#ifdef WITH_HDR
+ else if (imtype == R_IMF_IMTYPE_RADHDR) {
+ ibuf->ftype = IMB_FTYPE_RADHDR;
+ }
+#endif
+ else if (ELEM(imtype,
+ R_IMF_IMTYPE_PNG,
+ R_IMF_IMTYPE_FFMPEG,
+ R_IMF_IMTYPE_H264,
+ R_IMF_IMTYPE_THEORA,
+ R_IMF_IMTYPE_XVID)) {
+ ibuf->ftype = IMB_FTYPE_PNG;
+
+ if (imtype == R_IMF_IMTYPE_PNG) {
+ if (imf->depth == R_IMF_CHAN_DEPTH_16) {
+ ibuf->foptions.flag |= PNG_16BIT;
+ }
+
+ ibuf->foptions.quality = compress;
+ }
+ }
+#ifdef WITH_DDS
+ else if (imtype == R_IMF_IMTYPE_DDS) {
+ ibuf->ftype = IMB_FTYPE_DDS;
+ }
+#endif
+ else if (imtype == R_IMF_IMTYPE_BMP) {
+ ibuf->ftype = IMB_FTYPE_BMP;
+ }
+#ifdef WITH_TIFF
+ else if (imtype == R_IMF_IMTYPE_TIFF) {
+ ibuf->ftype = IMB_FTYPE_TIF;
+
+ if (imf->depth == R_IMF_CHAN_DEPTH_16) {
+ ibuf->foptions.flag |= TIF_16BIT;
+ }
+ if (imf->tiff_codec == R_IMF_TIFF_CODEC_NONE) {
+ ibuf->foptions.flag |= TIF_COMPRESS_NONE;
+ }
+ else if (imf->tiff_codec == R_IMF_TIFF_CODEC_DEFLATE) {
+ ibuf->foptions.flag |= TIF_COMPRESS_DEFLATE;
+ }
+ else if (imf->tiff_codec == R_IMF_TIFF_CODEC_LZW) {
+ ibuf->foptions.flag |= TIF_COMPRESS_LZW;
+ }
+ else if (imf->tiff_codec == R_IMF_TIFF_CODEC_PACKBITS) {
+ ibuf->foptions.flag |= TIF_COMPRESS_PACKBITS;
+ }
+ }
+#endif
+#ifdef WITH_OPENEXR
+ else if (ELEM(imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
+ ibuf->ftype = IMB_FTYPE_OPENEXR;
+ if (imf->depth == R_IMF_CHAN_DEPTH_16) {
+ ibuf->foptions.flag |= OPENEXR_HALF;
+ }
+ ibuf->foptions.flag |= (imf->exr_codec & OPENEXR_COMPRESS);
+
+ if (!(imf->flag & R_IMF_FLAG_ZBUF)) {
+ /* Signal for exr saving. */
+ IMB_freezbuffloatImBuf(ibuf);
+ }
+ }
+#endif
+#ifdef WITH_CINEON
+ else if (imtype == R_IMF_IMTYPE_CINEON) {
+ ibuf->ftype = IMB_FTYPE_CINEON;
+ if (imf->cineon_flag & R_IMF_CINEON_FLAG_LOG) {
+ ibuf->foptions.flag |= CINEON_LOG;
+ }
+ if (imf->depth == R_IMF_CHAN_DEPTH_16) {
+ ibuf->foptions.flag |= CINEON_16BIT;
+ }
+ else if (imf->depth == R_IMF_CHAN_DEPTH_12) {
+ ibuf->foptions.flag |= CINEON_12BIT;
+ }
+ else if (imf->depth == R_IMF_CHAN_DEPTH_10) {
+ ibuf->foptions.flag |= CINEON_10BIT;
+ }
+ }
+ else if (imtype == R_IMF_IMTYPE_DPX) {
+ ibuf->ftype = IMB_FTYPE_DPX;
+ if (imf->cineon_flag & R_IMF_CINEON_FLAG_LOG) {
+ ibuf->foptions.flag |= CINEON_LOG;
+ }
+ if (imf->depth == R_IMF_CHAN_DEPTH_16) {
+ ibuf->foptions.flag |= CINEON_16BIT;
+ }
+ else if (imf->depth == R_IMF_CHAN_DEPTH_12) {
+ ibuf->foptions.flag |= CINEON_12BIT;
+ }
+ else if (imf->depth == R_IMF_CHAN_DEPTH_10) {
+ ibuf->foptions.flag |= CINEON_10BIT;
+ }
+ }
+#endif
+ else if (imtype == R_IMF_IMTYPE_TARGA) {
+ ibuf->ftype = IMB_FTYPE_TGA;
+ }
+ else if (imtype == R_IMF_IMTYPE_RAWTGA) {
+ ibuf->ftype = IMB_FTYPE_TGA;
+ ibuf->foptions.flag = RAWTGA;
+ }
+#ifdef WITH_OPENJPEG
+ else if (imtype == R_IMF_IMTYPE_JP2) {
+ if (quality < 10) {
+ quality = 90;
+ }
+ ibuf->ftype = IMB_FTYPE_JP2;
+ ibuf->foptions.quality = quality;
+
+ if (imf->depth == R_IMF_CHAN_DEPTH_16) {
+ ibuf->foptions.flag |= JP2_16BIT;
+ }
+ else if (imf->depth == R_IMF_CHAN_DEPTH_12) {
+ ibuf->foptions.flag |= JP2_12BIT;
+ }
+
+ if (imf->jp2_flag & R_IMF_JP2_FLAG_YCC) {
+ ibuf->foptions.flag |= JP2_YCC;
+ }
+
+ if (imf->jp2_flag & R_IMF_JP2_FLAG_CINE_PRESET) {
+ ibuf->foptions.flag |= JP2_CINE;
+ if (imf->jp2_flag & R_IMF_JP2_FLAG_CINE_48) {
+ ibuf->foptions.flag |= JP2_CINE_48FPS;
+ }
+ }
+
+ if (imf->jp2_codec == R_IMF_JP2_CODEC_JP2) {
+ ibuf->foptions.flag |= JP2_JP2;
+ }
+ else if (imf->jp2_codec == R_IMF_JP2_CODEC_J2K) {
+ ibuf->foptions.flag |= JP2_J2K;
+ }
+ else {
+ BLI_assert_msg(0, "Unsupported jp2 codec was specified in im_format->jp2_codec");
+ }
+ }
+#endif
+#ifdef WITH_WEBP
+ else if (imtype == R_IMF_IMTYPE_WEBP) {
+ ibuf->ftype = IMB_FTYPE_WEBP;
+ ibuf->foptions.quality = quality;
+ }
+#endif
+ else {
+ /* #R_IMF_IMTYPE_JPEG90, etc. default to JPEG. */
+ if (quality < 10) {
+ quality = 90;
+ }
+ ibuf->ftype = IMB_FTYPE_JPG;
+ ibuf->foptions.quality = quality;
+ }
+}
+
+void BKE_image_format_from_imbuf(ImageFormatData *im_format, const ImBuf *imbuf)
+{
+ /* Read from ImBuf after file read. */
+ int ftype = imbuf->ftype;
+ int custom_flags = imbuf->foptions.flag;
+ char quality = imbuf->foptions.quality;
+
+ BKE_image_format_init(im_format, false);
+
+ /* file type */
+ if (ftype == IMB_FTYPE_IMAGIC) {
+ im_format->imtype = R_IMF_IMTYPE_IRIS;
+ }
+#ifdef WITH_HDR
+ else if (ftype == IMB_FTYPE_RADHDR) {
+ im_format->imtype = R_IMF_IMTYPE_RADHDR;
+ }
+#endif
+ else if (ftype == IMB_FTYPE_PNG) {
+ im_format->imtype = R_IMF_IMTYPE_PNG;
+
+ if (custom_flags & PNG_16BIT) {
+ im_format->depth = R_IMF_CHAN_DEPTH_16;
+ }
+
+ im_format->compress = quality;
+ }
+
+#ifdef WITH_DDS
+ else if (ftype == IMB_FTYPE_DDS) {
+ im_format->imtype = R_IMF_IMTYPE_DDS;
+ }
+#endif
+ else if (ftype == IMB_FTYPE_BMP) {
+ im_format->imtype = R_IMF_IMTYPE_BMP;
+ }
+#ifdef WITH_TIFF
+ else if (ftype == IMB_FTYPE_TIF) {
+ im_format->imtype = R_IMF_IMTYPE_TIFF;
+ if (custom_flags & TIF_16BIT) {
+ im_format->depth = R_IMF_CHAN_DEPTH_16;
+ }
+ if (custom_flags & TIF_COMPRESS_NONE) {
+ im_format->tiff_codec = R_IMF_TIFF_CODEC_NONE;
+ }
+ if (custom_flags & TIF_COMPRESS_DEFLATE) {
+ im_format->tiff_codec = R_IMF_TIFF_CODEC_DEFLATE;
+ }
+ if (custom_flags & TIF_COMPRESS_LZW) {
+ im_format->tiff_codec = R_IMF_TIFF_CODEC_LZW;
+ }
+ if (custom_flags & TIF_COMPRESS_PACKBITS) {
+ im_format->tiff_codec = R_IMF_TIFF_CODEC_PACKBITS;
+ }
+ }
+#endif
+
+#ifdef WITH_OPENEXR
+ else if (ftype == IMB_FTYPE_OPENEXR) {
+ im_format->imtype = R_IMF_IMTYPE_OPENEXR;
+ if (custom_flags & OPENEXR_HALF) {
+ im_format->depth = R_IMF_CHAN_DEPTH_16;
+ }
+ if (custom_flags & OPENEXR_COMPRESS) {
+ im_format->exr_codec = R_IMF_EXR_CODEC_ZIP; /* Can't determine compression */
+ }
+ if (imbuf->zbuf_float) {
+ im_format->flag |= R_IMF_FLAG_ZBUF;
+ }
+ }
+#endif
+
+#ifdef WITH_CINEON
+ else if (ftype == IMB_FTYPE_CINEON) {
+ im_format->imtype = R_IMF_IMTYPE_CINEON;
+ }
+ else if (ftype == IMB_FTYPE_DPX) {
+ im_format->imtype = R_IMF_IMTYPE_DPX;
+ }
+#endif
+ else if (ftype == IMB_FTYPE_TGA) {
+ if (custom_flags & RAWTGA) {
+ im_format->imtype = R_IMF_IMTYPE_RAWTGA;
+ }
+ else {
+ im_format->imtype = R_IMF_IMTYPE_TARGA;
+ }
+ }
+#ifdef WITH_OPENJPEG
+ else if (ftype == IMB_FTYPE_JP2) {
+ im_format->imtype = R_IMF_IMTYPE_JP2;
+ im_format->quality = quality;
+
+ if (custom_flags & JP2_16BIT) {
+ im_format->depth = R_IMF_CHAN_DEPTH_16;
+ }
+ else if (custom_flags & JP2_12BIT) {
+ im_format->depth = R_IMF_CHAN_DEPTH_12;
+ }
+
+ if (custom_flags & JP2_YCC) {
+ im_format->jp2_flag |= R_IMF_JP2_FLAG_YCC;
+ }
+
+ if (custom_flags & JP2_CINE) {
+ im_format->jp2_flag |= R_IMF_JP2_FLAG_CINE_PRESET;
+ if (custom_flags & JP2_CINE_48FPS) {
+ im_format->jp2_flag |= R_IMF_JP2_FLAG_CINE_48;
+ }
+ }
+
+ if (custom_flags & JP2_JP2) {
+ im_format->jp2_codec = R_IMF_JP2_CODEC_JP2;
+ }
+ else if (custom_flags & JP2_J2K) {
+ im_format->jp2_codec = R_IMF_JP2_CODEC_J2K;
+ }
+ else {
+ BLI_assert_msg(0, "Unsupported jp2 codec was specified in file type");
+ }
+ }
+#endif
+#ifdef WITH_WEBP
+ else if (ftype == IMB_FTYPE_WEBP) {
+ im_format->imtype = R_IMF_IMTYPE_WEBP;
+ im_format->quality = quality;
+ }
+#endif
+
+ else {
+ im_format->imtype = R_IMF_IMTYPE_JPEG90;
+ im_format->quality = quality;
+ }
+
+ /* planes */
+ im_format->planes = imbuf->planes;
+}
+
+/* Color Management */
+
+void BKE_image_format_color_management_copy(ImageFormatData *imf, const ImageFormatData *imf_src)
+{
+ BKE_color_managed_view_settings_free(&imf->view_settings);
+
+ BKE_color_managed_display_settings_copy(&imf->display_settings, &imf_src->display_settings);
+ BKE_color_managed_view_settings_copy(&imf->view_settings, &imf_src->view_settings);
+ BKE_color_managed_colorspace_settings_copy(&imf->linear_colorspace_settings,
+ &imf_src->linear_colorspace_settings);
+}
+
+void BKE_image_format_color_management_copy_from_scene(ImageFormatData *imf, const Scene *scene)
+{
+ BKE_color_managed_view_settings_free(&imf->view_settings);
+
+ BKE_color_managed_display_settings_copy(&imf->display_settings, &scene->display_settings);
+ BKE_color_managed_view_settings_copy(&imf->view_settings, &scene->view_settings);
+ STRNCPY(imf->linear_colorspace_settings.name,
+ IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR));
+}
+
+/* Output */
+
+void BKE_image_format_init_for_write(ImageFormatData *imf,
+ const Scene *scene_src,
+ const ImageFormatData *imf_src)
+{
+ *imf = (imf_src) ? *imf_src : scene_src->r.im_format;
+
+ if (imf_src && imf_src->color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) {
+ /* Use settings specific to one node, image save operation, etc. */
+ BKE_color_managed_display_settings_copy(&imf->display_settings, &imf_src->display_settings);
+ BKE_color_managed_view_settings_copy(&imf->view_settings, &imf_src->view_settings);
+ BKE_color_managed_colorspace_settings_copy(&imf->linear_colorspace_settings,
+ &imf_src->linear_colorspace_settings);
+ }
+ else if (scene_src->r.im_format.color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) {
+ /* Use scene settings specific to render output. */
+ BKE_color_managed_display_settings_copy(&imf->display_settings,
+ &scene_src->r.im_format.display_settings);
+ BKE_color_managed_view_settings_copy(&imf->view_settings,
+ &scene_src->r.im_format.view_settings);
+ BKE_color_managed_colorspace_settings_copy(&imf->linear_colorspace_settings,
+ &scene_src->r.im_format.linear_colorspace_settings);
+ }
+ else {
+ /* Use general scene settings also used for display. */
+ BKE_color_managed_display_settings_copy(&imf->display_settings, &scene_src->display_settings);
+ BKE_color_managed_view_settings_copy(&imf->view_settings, &scene_src->view_settings);
+ STRNCPY(imf->linear_colorspace_settings.name,
+ IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR));
+ }
+}
diff --git a/source/blender/blenkernel/intern/image_partial_update.cc b/source/blender/blenkernel/intern/image_partial_update.cc
index 4606a14ab69..c77ee77a5f2 100644
--- a/source/blender/blenkernel/intern/image_partial_update.cc
+++ b/source/blender/blenkernel/intern/image_partial_update.cc
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2021 Blender Foundation. */
/**
- * \file image_gpu_partial_update.cc
+ * \file
* \ingroup bke
*
* To reduce the overhead of image processing this file contains a mechanism to detect areas of the
diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c
deleted file mode 100644
index ae8f4c044fe..00000000000
--- a/source/blender/blenkernel/intern/image_save.c
+++ /dev/null
@@ -1,441 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later
- * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
-
-/** \file
- * \ingroup bke
- */
-
-#include <errno.h>
-#include <string.h>
-
-#include "BLI_listbase.h"
-#include "BLI_path_util.h"
-#include "BLI_string.h"
-
-#include "DNA_image_types.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "IMB_colormanagement.h"
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-
-#include "BKE_colortools.h"
-#include "BKE_image.h"
-#include "BKE_image_save.h"
-#include "BKE_main.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
-
-#include "RE_pipeline.h"
-
-void BKE_image_save_options_init(ImageSaveOptions *opts, Main *bmain, Scene *scene)
-{
- memset(opts, 0, sizeof(*opts));
-
- opts->bmain = bmain;
- opts->scene = scene;
-
- BKE_imformat_defaults(&opts->im_format);
-}
-
-static void image_save_post(ReportList *reports,
- Image *ima,
- ImBuf *ibuf,
- int ok,
- ImageSaveOptions *opts,
- int save_copy,
- const char *filepath,
- bool *r_colorspace_changed)
-{
- if (!ok) {
- BKE_reportf(reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
- return;
- }
-
- if (save_copy) {
- return;
- }
-
- if (opts->do_newpath) {
- BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
- BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
- }
-
- ibuf->userflags &= ~IB_BITMAPDIRTY;
-
- /* change type? */
- if (ima->type == IMA_TYPE_R_RESULT) {
- ima->type = IMA_TYPE_IMAGE;
-
- /* workaround to ensure the render result buffer is no longer used
- * by this image, otherwise can crash when a new render result is
- * created. */
- if (ibuf->rect && !(ibuf->mall & IB_rect)) {
- imb_freerectImBuf(ibuf);
- }
- if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat)) {
- imb_freerectfloatImBuf(ibuf);
- }
- if (ibuf->zbuf && !(ibuf->mall & IB_zbuf)) {
- IMB_freezbufImBuf(ibuf);
- }
- if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat)) {
- IMB_freezbuffloatImBuf(ibuf);
- }
- }
- if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
- ima->source = IMA_SRC_FILE;
- ima->type = IMA_TYPE_IMAGE;
- }
-
- /* only image path, never ibuf */
- if (opts->relative) {
- const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id);
- BLI_path_rel(ima->filepath, relbase); /* only after saving */
- }
-
- ColorManagedColorspaceSettings old_colorspace_settings;
- BKE_color_managed_colorspace_settings_copy(&old_colorspace_settings, &ima->colorspace_settings);
- IMB_colormanagement_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
- if (!BKE_color_managed_colorspace_settings_equals(&old_colorspace_settings,
- &ima->colorspace_settings)) {
- *r_colorspace_changed = true;
- }
-}
-
-static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
-{
- if (colormanaged_ibuf != ibuf) {
- /* This guys might be modified by image buffer write functions,
- * need to copy them back from color managed image buffer to an
- * original one, so file type of image is being properly updated.
- */
- ibuf->ftype = colormanaged_ibuf->ftype;
- ibuf->foptions = colormanaged_ibuf->foptions;
- ibuf->planes = colormanaged_ibuf->planes;
-
- IMB_freeImBuf(colormanaged_ibuf);
- }
-}
-
-/**
- * \return success.
- * \note `ima->filepath` and `ibuf->name` should end up the same.
- * \note for multi-view the first `ibuf` is important to get the settings.
- */
-static bool image_save_single(ReportList *reports,
- Image *ima,
- ImageUser *iuser,
- ImageSaveOptions *opts,
- bool *r_colorspace_changed)
-{
- void *lock;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
- RenderResult *rr = NULL;
- bool ok = false;
-
- if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
- BKE_image_release_ibuf(ima, ibuf, lock);
- goto cleanup;
- }
-
- ImBuf *colormanaged_ibuf = NULL;
- const bool save_copy = opts->save_copy;
- const bool save_as_render = opts->save_as_render;
- ImageFormatData *imf = &opts->im_format;
-
- if (ima->type == IMA_TYPE_R_RESULT) {
- /* enforce user setting for RGB or RGBA, but skip BW */
- if (opts->im_format.planes == R_IMF_PLANES_RGBA) {
- ibuf->planes = R_IMF_PLANES_RGBA;
- }
- else if (opts->im_format.planes == R_IMF_PLANES_RGB) {
- ibuf->planes = R_IMF_PLANES_RGB;
- }
- }
- else {
- /* TODO: better solution, if a 24bit image is painted onto it may contain alpha. */
- if ((opts->im_format.planes == R_IMF_PLANES_RGBA) &&
- /* it has been painted onto */
- (ibuf->userflags & IB_BITMAPDIRTY)) {
- /* checks each pixel, not ideal */
- ibuf->planes = BKE_imbuf_alpha_test(ibuf) ? R_IMF_PLANES_RGBA : R_IMF_PLANES_RGB;
- }
- }
-
- /* we need renderresult for exr and rendered multiview */
- rr = BKE_image_acquire_renderresult(opts->scene, ima);
- bool is_mono = rr ? BLI_listbase_count_at_most(&rr->views, 2) < 2 :
- BLI_listbase_count_at_most(&ima->views, 2) < 2;
- bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
- RE_HasFloatPixels(rr);
- bool is_multilayer = is_exr_rr && (imf->imtype == R_IMF_IMTYPE_MULTILAYER);
- int layer = (iuser && !is_multilayer) ? iuser->layer : -1;
-
- /* error handling */
- if (!rr) {
- if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
- BKE_report(reports, RPT_ERROR, "Did not write, no Multilayer Image");
- BKE_image_release_ibuf(ima, ibuf, lock);
- goto cleanup;
- }
- }
- else {
- if (imf->views_format == R_IMF_VIEWS_STEREO_3D) {
- if (!BKE_image_is_stereo(ima)) {
- BKE_reportf(reports,
- RPT_ERROR,
- "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
- STEREO_LEFT_NAME,
- STEREO_RIGHT_NAME);
- BKE_image_release_ibuf(ima, ibuf, lock);
- goto cleanup;
- }
-
- /* It shouldn't ever happen. */
- if ((BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name)) == NULL) ||
- (BLI_findstring(&rr->views, STEREO_RIGHT_NAME, offsetof(RenderView, name)) == NULL)) {
- BKE_reportf(reports,
- RPT_ERROR,
- "Did not write, the image doesn't have a \"%s\" and \"%s\" views",
- STEREO_LEFT_NAME,
- STEREO_RIGHT_NAME);
- BKE_image_release_ibuf(ima, ibuf, lock);
- goto cleanup;
- }
- }
- BKE_imbuf_stamp_info(rr, ibuf);
- }
-
- /* fancy multiview OpenEXR */
- if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
- /* save render result */
- ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer);
- image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
- BKE_image_release_ibuf(ima, ibuf, lock);
- }
- /* regular mono pipeline */
- else if (is_mono) {
- if (is_exr_rr) {
- ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer);
- }
- else {
- colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(
- ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
- ok = BKE_imbuf_write_as(colormanaged_ibuf, opts->filepath, imf, save_copy);
- imbuf_save_post(ibuf, colormanaged_ibuf);
- }
- image_save_post(reports,
- ima,
- ibuf,
- ok,
- opts,
- (is_exr_rr ? true : save_copy),
- opts->filepath,
- r_colorspace_changed);
- BKE_image_release_ibuf(ima, ibuf, lock);
- }
- /* individual multiview images */
- else if (imf->views_format == R_IMF_VIEWS_INDIVIDUAL) {
- unsigned char planes = ibuf->planes;
- const int totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views));
-
- if (!is_exr_rr) {
- BKE_image_release_ibuf(ima, ibuf, lock);
- }
-
- for (int i = 0; i < totviews; i++) {
- char filepath[FILE_MAX];
- bool ok_view = false;
- const char *view = rr ? ((RenderView *)BLI_findlink(&rr->views, i))->name :
- ((ImageView *)BLI_findlink(&ima->views, i))->name;
-
- if (is_exr_rr) {
- BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath);
- ok_view = RE_WriteRenderResult(reports, rr, filepath, imf, view, layer);
- image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
- }
- else {
- /* copy iuser to get the correct ibuf for this view */
- ImageUser view_iuser;
-
- if (iuser) {
- /* copy iuser to get the correct ibuf for this view */
- view_iuser = *iuser;
- }
- else {
- BKE_imageuser_default(&view_iuser);
- }
-
- view_iuser.view = i;
- view_iuser.flag &= ~IMA_SHOW_STEREO;
-
- if (rr) {
- BKE_image_multilayer_index(rr, &view_iuser);
- }
- else {
- BKE_image_multiview_index(ima, &view_iuser);
- }
-
- ibuf = BKE_image_acquire_ibuf(ima, &view_iuser, &lock);
- ibuf->planes = planes;
-
- BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath);
-
- colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(
- ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
- ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &opts->im_format, save_copy);
- imbuf_save_post(ibuf, colormanaged_ibuf);
- image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
- BKE_image_release_ibuf(ima, ibuf, lock);
- }
- ok &= ok_view;
- }
-
- if (is_exr_rr) {
- BKE_image_release_ibuf(ima, ibuf, lock);
- }
- }
- /* stereo (multiview) images */
- else if (opts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
- if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
- ok = RE_WriteRenderResult(reports, rr, opts->filepath, imf, NULL, layer);
- image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
- BKE_image_release_ibuf(ima, ibuf, lock);
- }
- else {
- ImBuf *ibuf_stereo[2] = {NULL};
-
- unsigned char planes = ibuf->planes;
- const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
-
- /* we need to get the specific per-view buffers */
- BKE_image_release_ibuf(ima, ibuf, lock);
-
- for (int i = 0; i < 2; i++) {
- ImageUser view_iuser;
-
- if (iuser) {
- view_iuser = *iuser;
- }
- else {
- BKE_imageuser_default(&view_iuser);
- }
-
- view_iuser.flag &= ~IMA_SHOW_STEREO;
-
- if (rr) {
- int id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
- view_iuser.view = id;
- BKE_image_multilayer_index(rr, &view_iuser);
- }
- else {
- view_iuser.view = i;
- BKE_image_multiview_index(ima, &view_iuser);
- }
-
- ibuf = BKE_image_acquire_ibuf(ima, &view_iuser, &lock);
-
- if (ibuf == NULL) {
- BKE_report(
- reports, RPT_ERROR, "Did not write, unexpected error when saving stereo image");
- goto cleanup;
- }
-
- ibuf->planes = planes;
-
- /* color manage the ImBuf leaving it ready for saving */
- colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(
- ibuf, save_as_render, true, &imf->view_settings, &imf->display_settings, imf);
-
- BKE_imbuf_write_prepare(colormanaged_ibuf, imf);
- IMB_prepare_write_ImBuf(IMB_isfloat(colormanaged_ibuf), colormanaged_ibuf);
-
- /* duplicate buffer to prevent locker issue when using render result */
- ibuf_stereo[i] = IMB_dupImBuf(colormanaged_ibuf);
-
- imbuf_save_post(ibuf, colormanaged_ibuf);
- BKE_image_release_ibuf(ima, ibuf, lock);
- }
-
- ibuf = IMB_stereo3d_ImBuf(imf, ibuf_stereo[0], ibuf_stereo[1]);
-
- /* save via traditional path */
- ok = BKE_imbuf_write_as(ibuf, opts->filepath, imf, save_copy);
-
- IMB_freeImBuf(ibuf);
-
- for (int i = 0; i < 2; i++) {
- IMB_freeImBuf(ibuf_stereo[i]);
- }
- }
- }
-
-cleanup:
- if (rr) {
- BKE_image_release_renderresult(opts->scene, ima);
- }
-
- return ok;
-}
-
-bool BKE_image_save(
- ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, ImageSaveOptions *opts)
-{
- ImageUser save_iuser;
- BKE_imageuser_default(&save_iuser);
-
- bool colorspace_changed = false;
-
- eUDIM_TILE_FORMAT tile_format;
- char *udim_pattern = NULL;
-
- if (ima->source == IMA_SRC_TILED) {
- /* Verify filepath for tiled images contains a valid UDIM marker. */
- udim_pattern = BKE_image_get_tile_strformat(opts->filepath, &tile_format);
- if (tile_format == UDIM_TILE_FORMAT_NONE) {
- BKE_reportf(reports,
- RPT_ERROR,
- "When saving a tiled image, the path '%s' must contain a valid UDIM marker",
- opts->filepath);
- return false;
- }
-
- /* For saving a tiled image we need an iuser, so use a local one if there isn't already one. */
- if (iuser == NULL) {
- iuser = &save_iuser;
- }
- }
-
- /* Save images */
- bool ok = false;
- if (ima->source != IMA_SRC_TILED) {
- ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
- }
- else {
- char filepath[FILE_MAX];
- BLI_strncpy(filepath, opts->filepath, sizeof(filepath));
-
- /* Save all the tiles. */
- LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
- BKE_image_set_filepath_from_tile_number(
- opts->filepath, udim_pattern, tile_format, tile->tile_number);
-
- iuser->tile = tile->tile_number;
- ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
- if (!ok) {
- break;
- }
- }
- BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
- BLI_strncpy(opts->filepath, filepath, sizeof(opts->filepath));
- MEM_freeN(udim_pattern);
- }
-
- if (colorspace_changed) {
- BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_COLORMANAGE);
- }
-
- return ok;
-}
diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc
new file mode 100644
index 00000000000..0d7d238f3b2
--- /dev/null
+++ b/source/blender/blenkernel/intern/image_save.cc
@@ -0,0 +1,822 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <cerrno>
+#include <cstring>
+
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_vector.hh"
+
+#include "DNA_image_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_openexr.h"
+
+#include "BKE_colortools.h"
+#include "BKE_image.h"
+#include "BKE_image_format.h"
+#include "BKE_image_save.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+
+#include "RE_pipeline.h"
+
+using blender::Vector;
+
+void BKE_image_save_options_init(ImageSaveOptions *opts, Main *bmain, Scene *scene)
+{
+ memset(opts, 0, sizeof(*opts));
+
+ opts->bmain = bmain;
+ opts->scene = scene;
+
+ BKE_image_format_init(&opts->im_format, false);
+}
+
+void BKE_image_save_options_free(ImageSaveOptions *opts)
+{
+ BKE_image_format_free(&opts->im_format);
+}
+
+static void image_save_post(ReportList *reports,
+ Image *ima,
+ ImBuf *ibuf,
+ int ok,
+ ImageSaveOptions *opts,
+ int save_copy,
+ const char *filepath,
+ bool *r_colorspace_changed)
+{
+ if (!ok) {
+ BKE_reportf(reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
+ return;
+ }
+
+ if (save_copy) {
+ return;
+ }
+
+ if (opts->do_newpath) {
+ BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
+ BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
+ }
+
+ ibuf->userflags &= ~IB_BITMAPDIRTY;
+
+ /* change type? */
+ if (ima->type == IMA_TYPE_R_RESULT) {
+ ima->type = IMA_TYPE_IMAGE;
+
+ /* workaround to ensure the render result buffer is no longer used
+ * by this image, otherwise can crash when a new render result is
+ * created. */
+ if (ibuf->rect && !(ibuf->mall & IB_rect)) {
+ imb_freerectImBuf(ibuf);
+ }
+ if (ibuf->rect_float && !(ibuf->mall & IB_rectfloat)) {
+ imb_freerectfloatImBuf(ibuf);
+ }
+ if (ibuf->zbuf && !(ibuf->mall & IB_zbuf)) {
+ IMB_freezbufImBuf(ibuf);
+ }
+ if (ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat)) {
+ IMB_freezbuffloatImBuf(ibuf);
+ }
+ }
+ if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
+ ima->source = IMA_SRC_FILE;
+ ima->type = IMA_TYPE_IMAGE;
+ }
+
+ /* only image path, never ibuf */
+ if (opts->relative) {
+ const char *relbase = ID_BLEND_PATH(opts->bmain, &ima->id);
+ BLI_path_rel(ima->filepath, relbase); /* only after saving */
+ }
+
+ ColorManagedColorspaceSettings old_colorspace_settings;
+ BKE_color_managed_colorspace_settings_copy(&old_colorspace_settings, &ima->colorspace_settings);
+ IMB_colormanagement_colorspace_from_ibuf_ftype(&ima->colorspace_settings, ibuf);
+ if (!BKE_color_managed_colorspace_settings_equals(&old_colorspace_settings,
+ &ima->colorspace_settings)) {
+ *r_colorspace_changed = true;
+ }
+}
+
+static void imbuf_save_post(ImBuf *ibuf, ImBuf *colormanaged_ibuf)
+{
+ if (colormanaged_ibuf != ibuf) {
+ /* This guys might be modified by image buffer write functions,
+ * need to copy them back from color managed image buffer to an
+ * original one, so file type of image is being properly updated.
+ */
+ ibuf->ftype = colormanaged_ibuf->ftype;
+ ibuf->foptions = colormanaged_ibuf->foptions;
+ ibuf->planes = colormanaged_ibuf->planes;
+
+ IMB_freeImBuf(colormanaged_ibuf);
+ }
+}
+
+/**
+ * \return success.
+ * \note `ima->filepath` and `ibuf->name` should end up the same.
+ * \note for multi-view the first `ibuf` is important to get the settings.
+ */
+static bool image_save_single(ReportList *reports,
+ Image *ima,
+ ImageUser *iuser,
+ ImageSaveOptions *opts,
+ bool *r_colorspace_changed)
+{
+ void *lock;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
+ RenderResult *rr = nullptr;
+ bool ok = false;
+
+ if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) {
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ return ok;
+ }
+
+ ImBuf *colormanaged_ibuf = nullptr;
+ const bool save_copy = opts->save_copy;
+ const bool save_as_render = opts->save_as_render;
+ ImageFormatData *imf = &opts->im_format;
+
+ if (ima->type == IMA_TYPE_R_RESULT) {
+ /* enforce user setting for RGB or RGBA, but skip BW */
+ if (opts->im_format.planes == R_IMF_PLANES_RGBA) {
+ ibuf->planes = R_IMF_PLANES_RGBA;
+ }
+ else if (opts->im_format.planes == R_IMF_PLANES_RGB) {
+ ibuf->planes = R_IMF_PLANES_RGB;
+ }
+ }
+ else {
+ /* TODO: better solution, if a 24bit image is painted onto it may contain alpha. */
+ if ((opts->im_format.planes == R_IMF_PLANES_RGBA) &&
+ /* it has been painted onto */
+ (ibuf->userflags & IB_BITMAPDIRTY)) {
+ /* checks each pixel, not ideal */
+ ibuf->planes = BKE_imbuf_alpha_test(ibuf) ? R_IMF_PLANES_RGBA : R_IMF_PLANES_RGB;
+ }
+ }
+
+ /* we need renderresult for exr and rendered multiview */
+ rr = BKE_image_acquire_renderresult(opts->scene, ima);
+ bool is_mono = rr ? BLI_listbase_count_at_most(&rr->views, 2) < 2 :
+ BLI_listbase_count_at_most(&ima->views, 2) < 2;
+ bool is_exr_rr = rr && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
+ RE_HasFloatPixels(rr);
+ bool is_multilayer = is_exr_rr && (imf->imtype == R_IMF_IMTYPE_MULTILAYER);
+ int layer = (iuser && !is_multilayer) ? iuser->layer : -1;
+
+ /* error handling */
+ if (rr == nullptr) {
+ if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
+ BKE_report(reports, RPT_ERROR, "Did not write, no Multilayer Image");
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ return ok;
+ }
+ }
+ else {
+ if (imf->views_format == R_IMF_VIEWS_STEREO_3D) {
+ if (!BKE_image_is_stereo(ima)) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ R"(Did not write, the image doesn't have a "%s" and "%s" views)",
+ STEREO_LEFT_NAME,
+ STEREO_RIGHT_NAME);
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ BKE_image_release_renderresult(opts->scene, ima);
+ return ok;
+ }
+
+ /* It shouldn't ever happen. */
+ if ((BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name)) == nullptr) ||
+ (BLI_findstring(&rr->views, STEREO_RIGHT_NAME, offsetof(RenderView, name)) == nullptr)) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ R"(Did not write, the image doesn't have a "%s" and "%s" views)",
+ STEREO_LEFT_NAME,
+ STEREO_RIGHT_NAME);
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ BKE_image_release_renderresult(opts->scene, ima);
+ return ok;
+ }
+ }
+ BKE_imbuf_stamp_info(rr, ibuf);
+ }
+
+ /* fancy multiview OpenEXR */
+ if (imf->views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
+ /* save render result */
+ ok = BKE_image_render_write_exr(
+ reports, rr, opts->filepath, imf, save_as_render, nullptr, layer);
+ image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ }
+ /* regular mono pipeline */
+ else if (is_mono) {
+ if (is_exr_rr) {
+ ok = BKE_image_render_write_exr(
+ reports, rr, opts->filepath, imf, save_as_render, nullptr, layer);
+ }
+ else {
+ colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf);
+ ok = BKE_imbuf_write_as(colormanaged_ibuf, opts->filepath, imf, save_copy);
+ imbuf_save_post(ibuf, colormanaged_ibuf);
+ }
+ image_save_post(reports,
+ ima,
+ ibuf,
+ ok,
+ opts,
+ (is_exr_rr ? true : save_copy),
+ opts->filepath,
+ r_colorspace_changed);
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ }
+ /* individual multiview images */
+ else if (imf->views_format == R_IMF_VIEWS_INDIVIDUAL) {
+ unsigned char planes = ibuf->planes;
+ const int totviews = (rr ? BLI_listbase_count(&rr->views) : BLI_listbase_count(&ima->views));
+
+ if (!is_exr_rr) {
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ }
+
+ for (int i = 0; i < totviews; i++) {
+ char filepath[FILE_MAX];
+ bool ok_view = false;
+ const char *view = rr ? ((RenderView *)BLI_findlink(&rr->views, i))->name :
+ ((ImageView *)BLI_findlink(&ima->views, i))->name;
+
+ if (is_exr_rr) {
+ BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath);
+ ok_view = BKE_image_render_write_exr(
+ reports, rr, filepath, imf, save_as_render, view, layer);
+ image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
+ }
+ else {
+ /* copy iuser to get the correct ibuf for this view */
+ ImageUser view_iuser;
+
+ if (iuser) {
+ /* copy iuser to get the correct ibuf for this view */
+ view_iuser = *iuser;
+ }
+ else {
+ BKE_imageuser_default(&view_iuser);
+ }
+
+ view_iuser.view = i;
+ view_iuser.flag &= ~IMA_SHOW_STEREO;
+
+ if (rr) {
+ BKE_image_multilayer_index(rr, &view_iuser);
+ }
+ else {
+ BKE_image_multiview_index(ima, &view_iuser);
+ }
+
+ ibuf = BKE_image_acquire_ibuf(ima, &view_iuser, &lock);
+ ibuf->planes = planes;
+
+ BKE_scene_multiview_view_filepath_get(&opts->scene->r, opts->filepath, view, filepath);
+
+ colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf);
+ ok_view = BKE_imbuf_write_as(colormanaged_ibuf, filepath, &opts->im_format, save_copy);
+ imbuf_save_post(ibuf, colormanaged_ibuf);
+ image_save_post(reports, ima, ibuf, ok_view, opts, true, filepath, r_colorspace_changed);
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ }
+ ok &= ok_view;
+ }
+
+ if (is_exr_rr) {
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ }
+ }
+ /* stereo (multiview) images */
+ else if (opts->im_format.views_format == R_IMF_VIEWS_STEREO_3D) {
+ if (imf->imtype == R_IMF_IMTYPE_MULTILAYER) {
+ ok = BKE_image_render_write_exr(
+ reports, rr, opts->filepath, imf, save_as_render, nullptr, layer);
+ image_save_post(reports, ima, ibuf, ok, opts, true, opts->filepath, r_colorspace_changed);
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ }
+ else {
+ ImBuf *ibuf_stereo[2] = {nullptr};
+
+ unsigned char planes = ibuf->planes;
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+
+ /* we need to get the specific per-view buffers */
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ bool stereo_ok = true;
+
+ for (int i = 0; i < 2; i++) {
+ ImageUser view_iuser;
+
+ if (iuser) {
+ view_iuser = *iuser;
+ }
+ else {
+ BKE_imageuser_default(&view_iuser);
+ }
+
+ view_iuser.flag &= ~IMA_SHOW_STEREO;
+
+ if (rr) {
+ int id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
+ view_iuser.view = id;
+ BKE_image_multilayer_index(rr, &view_iuser);
+ }
+ else {
+ view_iuser.view = i;
+ BKE_image_multiview_index(ima, &view_iuser);
+ }
+
+ ibuf = BKE_image_acquire_ibuf(ima, &view_iuser, &lock);
+
+ if (ibuf == nullptr) {
+ BKE_report(
+ reports, RPT_ERROR, "Did not write, unexpected error when saving stereo image");
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ stereo_ok = false;
+ break;
+ }
+
+ ibuf->planes = planes;
+
+ /* color manage the ImBuf leaving it ready for saving */
+ colormanaged_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, save_as_render, true, imf);
+
+ BKE_image_format_to_imbuf(colormanaged_ibuf, imf);
+ IMB_prepare_write_ImBuf(IMB_isfloat(colormanaged_ibuf), colormanaged_ibuf);
+
+ /* duplicate buffer to prevent locker issue when using render result */
+ ibuf_stereo[i] = IMB_dupImBuf(colormanaged_ibuf);
+
+ imbuf_save_post(ibuf, colormanaged_ibuf);
+
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ }
+
+ if (stereo_ok) {
+ ibuf = IMB_stereo3d_ImBuf(imf, ibuf_stereo[0], ibuf_stereo[1]);
+
+ /* save via traditional path */
+ ok = BKE_imbuf_write_as(ibuf, opts->filepath, imf, save_copy);
+
+ IMB_freeImBuf(ibuf);
+ }
+
+ for (int i = 0; i < 2; i++) {
+ IMB_freeImBuf(ibuf_stereo[i]);
+ }
+ }
+ }
+
+ if (rr) {
+ BKE_image_release_renderresult(opts->scene, ima);
+ }
+
+ return ok;
+}
+
+bool BKE_image_save(
+ ReportList *reports, Main *bmain, Image *ima, ImageUser *iuser, ImageSaveOptions *opts)
+{
+ ImageUser save_iuser;
+ BKE_imageuser_default(&save_iuser);
+
+ bool colorspace_changed = false;
+
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = nullptr;
+
+ if (ima->source == IMA_SRC_TILED) {
+ /* Verify filepath for tiled images contains a valid UDIM marker. */
+ udim_pattern = BKE_image_get_tile_strformat(opts->filepath, &tile_format);
+ if (tile_format == UDIM_TILE_FORMAT_NONE) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "When saving a tiled image, the path '%s' must contain a valid UDIM marker",
+ opts->filepath);
+ return false;
+ }
+
+ /* For saving a tiled image we need an iuser, so use a local one if there isn't already one.
+ */
+ if (iuser == nullptr) {
+ iuser = &save_iuser;
+ }
+ }
+
+ /* Save images */
+ bool ok = false;
+ if (ima->source != IMA_SRC_TILED) {
+ ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
+ }
+ else {
+ char filepath[FILE_MAX];
+ BLI_strncpy(filepath, opts->filepath, sizeof(filepath));
+
+ /* Save all the tiles. */
+ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
+ BKE_image_set_filepath_from_tile_number(
+ opts->filepath, udim_pattern, tile_format, tile->tile_number);
+
+ iuser->tile = tile->tile_number;
+ ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
+ if (!ok) {
+ break;
+ }
+ }
+ BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
+ BLI_strncpy(opts->filepath, filepath, sizeof(opts->filepath));
+ MEM_freeN(udim_pattern);
+ }
+
+ if (colorspace_changed) {
+ BKE_image_signal(bmain, ima, nullptr, IMA_SIGNAL_COLORMANAGE);
+ }
+
+ return ok;
+}
+
+/* OpenEXR saving, single and multilayer. */
+
+static float *image_exr_from_scene_linear_to_output(float *rect,
+ const int width,
+ const int height,
+ const int channels,
+ const ImageFormatData *imf,
+ Vector<float *> &tmp_output_rects)
+{
+ if (imf == nullptr) {
+ return rect;
+ }
+
+ const char *to_colorspace = imf->linear_colorspace_settings.name;
+ if (to_colorspace[0] == '\0' || IMB_colormanagement_space_name_is_scene_linear(to_colorspace)) {
+ return rect;
+ }
+
+ float *output_rect = (float *)MEM_dupallocN(rect);
+ tmp_output_rects.append(output_rect);
+
+ const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(
+ COLOR_ROLE_SCENE_LINEAR);
+ IMB_colormanagement_transform(
+ output_rect, width, height, channels, from_colorspace, to_colorspace, false);
+
+ return output_rect;
+}
+
+bool BKE_image_render_write_exr(ReportList *reports,
+ const RenderResult *rr,
+ const char *filepath,
+ const ImageFormatData *imf,
+ const bool save_as_render,
+ const char *view,
+ int layer)
+{
+ void *exrhandle = IMB_exr_get_handle();
+ const bool half_float = (imf && imf->depth == R_IMF_CHAN_DEPTH_16);
+ const bool multi_layer = !(imf && imf->imtype == R_IMF_IMTYPE_OPENEXR);
+ const bool write_z = !multi_layer && (imf && (imf->flag & R_IMF_FLAG_ZBUF));
+ Vector<float *> tmp_output_rects;
+
+ /* Write first layer if not multilayer and no layer was specified. */
+ if (!multi_layer && layer == -1) {
+ layer = 0;
+ }
+
+ /* First add views since IMB_exr_add_channel checks number of views. */
+ const RenderView *first_rview = (const RenderView *)rr->views.first;
+ if (first_rview && (first_rview->next || first_rview->name[0])) {
+ LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
+ if (!view || STREQ(view, rview->name)) {
+ IMB_exr_add_view(exrhandle, rview->name);
+ }
+ }
+ }
+
+ /* Compositing result. */
+ if (rr->have_combined) {
+ LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
+ if (!rview->rectf) {
+ continue;
+ }
+
+ const char *viewname = rview->name;
+ if (view) {
+ if (!STREQ(view, viewname)) {
+ continue;
+ }
+
+ viewname = "";
+ }
+
+ /* Skip compositing if only a single other layer is requested. */
+ if (!multi_layer && layer != 0) {
+ continue;
+ }
+
+ float *output_rect = (save_as_render) ?
+ image_exr_from_scene_linear_to_output(
+ rview->rectf, rr->rectx, rr->recty, 4, imf, tmp_output_rects) :
+ rview->rectf;
+
+ for (int a = 0; a < 4; a++) {
+ char passname[EXR_PASS_MAXNAME];
+ char layname[EXR_PASS_MAXNAME];
+ const char *chan_id = "RGBA";
+
+ if (multi_layer) {
+ RE_render_result_full_channel_name(passname, nullptr, "Combined", nullptr, chan_id, a);
+ BLI_strncpy(layname, "Composite", sizeof(layname));
+ }
+ else {
+ passname[0] = chan_id[a];
+ passname[1] = '\0';
+ layname[0] = '\0';
+ }
+
+ IMB_exr_add_channel(
+ exrhandle, layname, passname, viewname, 4, 4 * rr->rectx, output_rect + a, half_float);
+ }
+
+ if (write_z && rview->rectz) {
+ const char *layname = (multi_layer) ? "Composite" : "";
+ IMB_exr_add_channel(exrhandle, layname, "Z", viewname, 1, rr->rectx, rview->rectz, false);
+ }
+ }
+ }
+
+ /* Other render layers. */
+ int nr = (rr->have_combined) ? 1 : 0;
+ LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
+ /* Skip other render layers if requested. */
+ if (!multi_layer && nr != layer) {
+ continue;
+ }
+
+ LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) {
+ /* Skip non-RGBA and Z passes if not using multi layer. */
+ if (!multi_layer && !(STREQ(rp->name, RE_PASSNAME_COMBINED) || STREQ(rp->name, "") ||
+ (STREQ(rp->name, RE_PASSNAME_Z) && write_z))) {
+ continue;
+ }
+
+ /* Skip pass if it does not match the requested view(s). */
+ const char *viewname = rp->view;
+ if (view) {
+ if (!STREQ(view, viewname)) {
+ continue;
+ }
+
+ viewname = "";
+ }
+
+ /* We only store RGBA passes as half float, for
+ * others precision loss can be problematic. */
+ const bool pass_RGBA = (STR_ELEM(rp->chan_id, "RGB", "RGBA", "R", "G", "B", "A"));
+ const bool pass_half_float = half_float && pass_RGBA;
+
+ /* Colorspace conversion only happens on RGBA passes. */
+ float *output_rect = (save_as_render && pass_RGBA) ?
+ image_exr_from_scene_linear_to_output(
+ rp->rect, rr->rectx, rr->recty, 4, imf, tmp_output_rects) :
+ rp->rect;
+
+ for (int a = 0; a < rp->channels; a++) {
+ /* Save Combined as RGBA if single layer save. */
+ char passname[EXR_PASS_MAXNAME];
+ char layname[EXR_PASS_MAXNAME];
+
+ if (multi_layer) {
+ RE_render_result_full_channel_name(passname, nullptr, rp->name, nullptr, rp->chan_id, a);
+ BLI_strncpy(layname, rl->name, sizeof(layname));
+ }
+ else {
+ passname[0] = rp->chan_id[a];
+ passname[1] = '\0';
+ layname[0] = '\0';
+ }
+
+ IMB_exr_add_channel(exrhandle,
+ layname,
+ passname,
+ viewname,
+ rp->channels,
+ rp->channels * rr->rectx,
+ output_rect + a,
+ pass_half_float);
+ }
+ }
+ }
+
+ errno = 0;
+
+ BLI_make_existing_file(filepath);
+
+ int compress = (imf ? imf->exr_codec : 0);
+ bool success = IMB_exr_begin_write(
+ exrhandle, filepath, rr->rectx, rr->recty, compress, rr->stamp_data);
+ if (success) {
+ IMB_exr_write_channels(exrhandle);
+ }
+ else {
+ /* TODO: get the error from openexr's exception. */
+ BKE_reportf(
+ reports, RPT_ERROR, "Error writing render result, %s (see console)", strerror(errno));
+ }
+
+ for (float *rect : tmp_output_rects) {
+ MEM_freeN(rect);
+ }
+
+ IMB_exr_close(exrhandle);
+ return success;
+}
+
+/* Render output. */
+
+static void image_render_print_save_message(ReportList *reports, const char *name, int ok, int err)
+{
+ if (ok) {
+ /* no need to report, just some helpful console info */
+ printf("Saved: '%s'\n", name);
+ }
+ else {
+ /* report on error since users will want to know what failed */
+ BKE_reportf(reports, RPT_ERROR, "Render error (%s) cannot save: '%s'", strerror(err), name);
+ }
+}
+
+static int image_render_write_stamp_test(ReportList *reports,
+ const Scene *scene,
+ const RenderResult *rr,
+ ImBuf *ibuf,
+ const char *name,
+ const ImageFormatData *imf,
+ const bool stamp)
+{
+ int ok;
+
+ if (stamp) {
+ /* writes the name of the individual cameras */
+ ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, imf);
+ }
+ else {
+ ok = BKE_imbuf_write(ibuf, name, imf);
+ }
+
+ image_render_print_save_message(reports, name, ok, errno);
+
+ return ok;
+}
+
+bool BKE_image_render_write(ReportList *reports,
+ RenderResult *rr,
+ const Scene *scene,
+ const bool stamp,
+ const char *filepath_basis)
+{
+ bool ok = true;
+
+ if (!rr) {
+ return false;
+ }
+
+ ImageFormatData image_format;
+ BKE_image_format_init_for_write(&image_format, scene, nullptr);
+
+ const bool is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2;
+ const bool is_exr_rr = ELEM(
+ image_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
+ RE_HasFloatPixels(rr);
+ const float dither = scene->r.dither_intensity;
+
+ if (image_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
+ ok = BKE_image_render_write_exr(reports, rr, filepath_basis, &image_format, true, nullptr, -1);
+ image_render_print_save_message(reports, filepath_basis, ok, errno);
+ }
+
+ /* mono, legacy code */
+ else if (is_mono || (image_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ int view_id = 0;
+ for (const RenderView *rv = (const RenderView *)rr->views.first; rv;
+ rv = rv->next, view_id++) {
+ char filepath[FILE_MAX];
+ if (is_mono) {
+ STRNCPY(filepath, filepath_basis);
+ }
+ else {
+ BKE_scene_multiview_view_filepath_get(&scene->r, filepath_basis, rv->name, filepath);
+ }
+
+ if (is_exr_rr) {
+ ok = BKE_image_render_write_exr(reports, rr, filepath, &image_format, true, rv->name, -1);
+ image_render_print_save_message(reports, filepath, ok, errno);
+
+ /* optional preview images for exr */
+ if (ok && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
+ image_format.imtype = R_IMF_IMTYPE_JPEG90;
+
+ if (BLI_path_extension_check(filepath, ".exr")) {
+ filepath[strlen(filepath) - 4] = 0;
+ }
+ BKE_image_path_ensure_ext_from_imformat(filepath, &image_format);
+
+ ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id);
+ ibuf->planes = 24;
+ IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format);
+
+ ok = image_render_write_stamp_test(
+ reports, scene, rr, ibuf, filepath, &image_format, stamp);
+
+ IMB_freeImBuf(ibuf);
+ }
+ }
+ else {
+ ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id);
+
+ IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format);
+
+ ok = image_render_write_stamp_test(
+ reports, scene, rr, ibuf, filepath, &image_format, stamp);
+
+ /* imbuf knows which rects are not part of ibuf */
+ IMB_freeImBuf(ibuf);
+ }
+ }
+ }
+ else { /* R_IMF_VIEWS_STEREO_3D */
+ BLI_assert(image_format.views_format == R_IMF_VIEWS_STEREO_3D);
+
+ char filepath[FILE_MAX];
+ STRNCPY(filepath, filepath_basis);
+
+ if (image_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
+ printf("Stereo 3D not supported for MultiLayer image: %s\n", filepath);
+ }
+ else {
+ ImBuf *ibuf_arr[3] = {nullptr};
+ const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
+ ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &image_format, dither, view_id);
+ IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &image_format);
+ IMB_prepare_write_ImBuf(IMB_isfloat(ibuf_arr[i]), ibuf_arr[i]);
+ }
+
+ ibuf_arr[2] = IMB_stereo3d_ImBuf(&image_format, ibuf_arr[0], ibuf_arr[1]);
+
+ ok = image_render_write_stamp_test(
+ reports, scene, rr, ibuf_arr[2], filepath, &image_format, stamp);
+
+ /* optional preview images for exr */
+ if (ok && is_exr_rr && (image_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
+ image_format.imtype = R_IMF_IMTYPE_JPEG90;
+
+ if (BLI_path_extension_check(filepath, ".exr")) {
+ filepath[strlen(filepath) - 4] = 0;
+ }
+
+ BKE_image_path_ensure_ext_from_imformat(filepath, &image_format);
+ ibuf_arr[2]->planes = 24;
+
+ ok = image_render_write_stamp_test(
+ reports, scene, rr, ibuf_arr[2], filepath, &image_format, stamp);
+ }
+
+ /* imbuf knows which rects are not part of ibuf */
+ for (i = 0; i < 3; i++) {
+ IMB_freeImBuf(ibuf_arr[i]);
+ }
+ }
+ }
+
+ BKE_image_format_free(&image_format);
+
+ return ok;
+}
diff --git a/source/blender/blenkernel/intern/image_test.cc b/source/blender/blenkernel/intern/image_test.cc
new file mode 100644
index 00000000000..9c15fc62d21
--- /dev/null
+++ b/source/blender/blenkernel/intern/image_test.cc
@@ -0,0 +1,186 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. */
+
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "BKE_image.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "testing/testing.h"
+
+namespace blender::bke::tests {
+
+TEST(udim, image_ensure_tile_token)
+{
+ auto verify = [](const char *original, const char *expected) {
+ char result[FILE_MAX];
+
+ BLI_strncpy(result, original, sizeof(result));
+ BKE_image_ensure_tile_token(result);
+ EXPECT_STREQ(result, expected);
+ };
+
+ /* Already present tokens. */
+ verify("test.<UDIM>.png", "test.<UDIM>.png");
+ verify("test.<UVTILE>.png", "test.<UVTILE>.png");
+
+ /* UDIM pattern detection. */
+ verify("test.1002.png", "test.<UDIM>.png");
+ verify("test-1002-ao.png", "test-<UDIM>-ao.png");
+ verify("test_1002_ao.png", "test_<UDIM>_ao.png");
+ verify("test.1002.ver0023.png", "test.<UDIM>.ver0023.png");
+ verify("test.ver0023.1002.png", "test.ver0023.<UDIM>.png");
+ verify("1002test.png", "<UDIM>test.png");
+ verify("test1002.png", "test<UDIM>.png");
+
+ /* UVTILE pattern detection. */
+ verify("uv-test.u2_v10.png", "uv-test.<UVTILE>.png");
+ verify("uv-test-u2_v10-ao.png", "uv-test-<UVTILE>-ao.png");
+ verify("uv-test_u2_v10_ao.png", "uv-test_<UVTILE>_ao.png");
+ verify("uv-test.u10_v100.png", "uv-test.<UVTILE>.png");
+ verify("u_v-test.u2_v10.png", "u_v-test.<UVTILE>.png");
+ verify("u2_v10uv-test.png", "<UVTILE>uv-test.png");
+ verify("u2_v10u_v-test.png", "<UVTILE>u_v-test.png");
+
+ /* Incorrect patterns. */
+ for (const char *incorrect : {"test.123.png",
+ "test.12345.png",
+ "test.uv.png",
+ "test.u1v.png",
+ "test.uv1.png",
+ "test.u_v.png",
+ "test.u1_v.png",
+ "test.u_v2.png",
+ "test.u2v3.png",
+ "test.u123_v1.png",
+ "test.u1_v12345.png"}) {
+ /* These should not result in modifications happening. */
+ verify(incorrect, incorrect);
+ }
+}
+
+TEST(udim, image_get_tile_strformat)
+{
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern;
+
+ /* Parameter validation. */
+ udim_pattern = BKE_image_get_tile_strformat(nullptr, &tile_format);
+ EXPECT_EQ(udim_pattern, nullptr);
+
+ udim_pattern = BKE_image_get_tile_strformat("", nullptr);
+ EXPECT_EQ(udim_pattern, nullptr);
+
+ /* Typical usage. */
+ udim_pattern = BKE_image_get_tile_strformat("", &tile_format);
+ EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_NONE);
+ EXPECT_EQ(udim_pattern, nullptr);
+
+ udim_pattern = BKE_image_get_tile_strformat("test.<UNKNOWN>.png", &tile_format);
+ EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_NONE);
+ EXPECT_EQ(udim_pattern, nullptr);
+
+ udim_pattern = BKE_image_get_tile_strformat("test.<UDIM>.png", &tile_format);
+ EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UDIM);
+ EXPECT_STREQ(udim_pattern, "test.%d.png");
+ MEM_freeN(udim_pattern);
+
+ udim_pattern = BKE_image_get_tile_strformat("test.<UVTILE>.png", &tile_format);
+ EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UVTILE);
+ EXPECT_STREQ(udim_pattern, "test.u%d_v%d.png");
+ MEM_freeN(udim_pattern);
+}
+
+TEST(udim, image_get_tile_number_from_filepath)
+{
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern;
+ int tile_number;
+
+ udim_pattern = BKE_image_get_tile_strformat("test.<UDIM>.png", &tile_format);
+ EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UDIM);
+ EXPECT_NE(udim_pattern, nullptr);
+
+ /* Parameter validation. */
+ EXPECT_FALSE(
+ BKE_image_get_tile_number_from_filepath(nullptr, udim_pattern, tile_format, &tile_number));
+ EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+ "test.1004.png", nullptr, tile_format, &tile_number));
+ EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+ "test.1004.png", udim_pattern, UDIM_TILE_FORMAT_NONE, &tile_number));
+ EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+ "test.1004.png", udim_pattern, tile_format, nullptr));
+
+ /* UDIM tile format tests. */
+ EXPECT_TRUE(BKE_image_get_tile_number_from_filepath(
+ "test.1004.png", udim_pattern, tile_format, &tile_number));
+ EXPECT_EQ(tile_number, 1004);
+
+ EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+ "has_no_number.png", udim_pattern, tile_format, &tile_number));
+ EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+ "test.X.png", udim_pattern, tile_format, &tile_number));
+ EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+ "wrong.1004.png", udim_pattern, tile_format, &tile_number));
+
+ MEM_freeN(udim_pattern);
+
+ /* UVTILE tile format tests. */
+ udim_pattern = BKE_image_get_tile_strformat("test.<UVTILE>.png", &tile_format);
+ EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UVTILE);
+ EXPECT_NE(udim_pattern, nullptr);
+
+ EXPECT_TRUE(BKE_image_get_tile_number_from_filepath(
+ "test.u2_v2.png", udim_pattern, tile_format, &tile_number));
+ EXPECT_EQ(tile_number, 1012);
+
+ EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+ "has_no_number.png", udim_pattern, tile_format, &tile_number));
+ EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+ "test.u1_vX.png", udim_pattern, tile_format, &tile_number));
+ EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+ "test.uX_v1.png", udim_pattern, tile_format, &tile_number));
+ EXPECT_FALSE(BKE_image_get_tile_number_from_filepath(
+ "wrong.u2_v2.png", udim_pattern, tile_format, &tile_number));
+
+ MEM_freeN(udim_pattern);
+}
+
+TEST(udim, image_set_filepath_from_tile_number)
+{
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern;
+
+ udim_pattern = BKE_image_get_tile_strformat("test.<UDIM>.png", &tile_format);
+ EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UDIM);
+ EXPECT_NE(udim_pattern, nullptr);
+
+ char filepath[FILE_MAX];
+
+ /* Parameter validation. */
+ BLI_strncpy(filepath, "xxxx", FILE_MAX);
+
+ BKE_image_set_filepath_from_tile_number(nullptr, udim_pattern, tile_format, 1028);
+ BKE_image_set_filepath_from_tile_number(filepath, nullptr, tile_format, 1028);
+ EXPECT_STREQ(filepath, "xxxx");
+ BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, UDIM_TILE_FORMAT_NONE, 1028);
+ EXPECT_STREQ(filepath, "xxxx");
+
+ /* UDIM tile format tests. */
+ BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, tile_format, 1028);
+ EXPECT_STREQ(filepath, "test.1028.png");
+ MEM_freeN(udim_pattern);
+
+ /* UVTILE tile format tests. */
+ udim_pattern = BKE_image_get_tile_strformat("test.<UVTILE>.png", &tile_format);
+ EXPECT_EQ(tile_format, UDIM_TILE_FORMAT_UVTILE);
+ EXPECT_NE(udim_pattern, nullptr);
+
+ BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, tile_format, 1028);
+ EXPECT_STREQ(filepath, "test.u8_v3.png");
+ MEM_freeN(udim_pattern);
+}
+
+} // namespace blender::bke::tests
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 11d6e6ef973..5247e9f358b 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -2171,16 +2171,14 @@ void BKE_keyblock_convert_from_mesh(Mesh *me, Key *key, KeyBlock *kb)
BKE_keyblock_update_from_mesh(me, kb);
}
-void BKE_keyblock_convert_to_mesh(KeyBlock *kb, Mesh *me)
+void BKE_keyblock_convert_to_mesh(KeyBlock *kb, struct MVert *mvert, int totvert)
{
- MVert *mvert;
const float(*fp)[3];
int a, tot;
- mvert = me->mvert;
fp = kb->data;
- tot = min_ii(kb->totelem, me->totvert);
+ tot = min_ii(kb->totelem, totvert);
for (a = 0; a < tot; a++, fp++, mvert++) {
copy_v3_v3(mvert->co, *fp);
@@ -2193,68 +2191,77 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
float (*r_polynors)[3],
float (*r_loopnors)[3])
{
- /* We use a temp, shallow copy of mesh to work. */
- Mesh me;
- bool free_polynors = false;
-
if (r_vertnors == NULL && r_polynors == NULL && r_loopnors == NULL) {
return;
}
- me = *mesh;
- me.mvert = MEM_dupallocN(mesh->mvert);
- CustomData_reset(&me.vdata);
- CustomData_reset(&me.edata);
- CustomData_reset(&me.pdata);
- CustomData_reset(&me.ldata);
- CustomData_reset(&me.fdata);
-
- BKE_keyblock_convert_to_mesh(kb, &me);
-
- if (r_polynors == NULL && r_loopnors != NULL) {
- r_polynors = MEM_mallocN(sizeof(float[3]) * me.totpoly, __func__);
- free_polynors = true;
- }
-
- const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
- if (r_vertnors) {
- memcpy(r_vertnors, vert_normals, sizeof(float[3]) * me.totvert);
- }
-
- const float(*face_normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
- memcpy(r_polynors, face_normals, sizeof(float[3]) * me.totpoly);
-
- if (r_loopnors) {
+ MVert *mvert = MEM_dupallocN(mesh->mvert);
+ BKE_keyblock_convert_to_mesh(kb, mesh->mvert, mesh->totvert);
+
+ const bool loop_normals_needed = r_loopnors != NULL;
+ const bool vert_normals_needed = r_vertnors != NULL || loop_normals_needed;
+ const bool poly_normals_needed = r_polynors != NULL || vert_normals_needed ||
+ loop_normals_needed;
+
+ float(*vert_normals)[3] = r_vertnors;
+ float(*poly_normals)[3] = r_polynors;
+ bool free_vert_normals = false;
+ bool free_poly_normals = false;
+ if (vert_normals_needed && r_vertnors == NULL) {
+ vert_normals = MEM_malloc_arrayN(mesh->totvert, sizeof(float[3]), __func__);
+ free_vert_normals = true;
+ }
+ if (poly_normals_needed && r_polynors == NULL) {
+ poly_normals = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__);
+ free_poly_normals = true;
+ }
+
+ if (poly_normals_needed) {
+ BKE_mesh_calc_normals_poly(mvert,
+ mesh->totvert,
+ mesh->mloop,
+ mesh->totloop,
+ mesh->mpoly,
+ mesh->totpoly,
+ poly_normals);
+ }
+ if (vert_normals_needed) {
+ BKE_mesh_calc_normals_poly_and_vertex(mvert,
+ mesh->totvert,
+ mesh->mloop,
+ mesh->totloop,
+ mesh->mpoly,
+ mesh->totpoly,
+ poly_normals,
+ vert_normals);
+ }
+ if (loop_normals_needed) {
short(*clnors)[2] = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); /* May be NULL. */
-
- BKE_mesh_normals_loop_split(me.mvert,
+ BKE_mesh_normals_loop_split(mesh->mvert,
vert_normals,
- me.totvert,
- me.medge,
- me.totedge,
- me.mloop,
+ mesh->totvert,
+ mesh->medge,
+ mesh->totedge,
+ mesh->mloop,
r_loopnors,
- me.totloop,
- me.mpoly,
- face_normals,
- me.totpoly,
- (me.flag & ME_AUTOSMOOTH) != 0,
- me.smoothresh,
+ mesh->totloop,
+ mesh->mpoly,
+ poly_normals,
+ mesh->totpoly,
+ (mesh->flag & ME_AUTOSMOOTH) != 0,
+ mesh->smoothresh,
NULL,
clnors,
NULL);
}
- CustomData_free(&me.vdata, me.totvert);
- CustomData_free(&me.edata, me.totedge);
- CustomData_free(&me.pdata, me.totpoly);
- CustomData_free(&me.ldata, me.totloop);
- CustomData_free(&me.fdata, me.totface);
- MEM_freeN(me.mvert);
-
- if (free_polynors) {
- MEM_freeN(r_polynors);
+ if (free_vert_normals) {
+ MEM_freeN(vert_normals);
+ }
+ if (free_poly_normals) {
+ MEM_freeN(poly_normals);
}
+ MEM_freeN(mvert);
}
/************************* raw coords ************************/
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 701788a4e29..64ebb08f5d0 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -417,6 +417,39 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
}
BLI_assert(id_hierarchy_root != NULL);
+ LinkNode *relinked_ids = NULL;
+ /* Still checking the whole Main, that way we can tag other local IDs as needing to be
+ * remapped to use newly created overriding IDs, if needed. */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ ID *other_id;
+ /* In case we created new overrides as 'no main', they are not accessible directly in this
+ * loop, but we can get to them through their reference's `newid` pointer. */
+ if (do_no_main && id->lib == id_root_reference->lib && id->newid != NULL) {
+ other_id = id->newid;
+ /* Otherwise we cannot properly distinguish between IDs that are actually from the
+ * linked library (and should not be remapped), and IDs that are overrides re-generated
+ * from the reference from the linked library, and must therefore be remapped.
+ *
+ * This is reset afterwards at the end of this loop. */
+ other_id->lib = NULL;
+ }
+ else {
+ other_id = id;
+ }
+
+ /* If other ID is a linked one, but not from the same library as our reference, then we
+ * consider we should also relink it, as part of recursive resync. */
+ if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib != id_root_reference->lib) {
+ BLI_linklist_prepend(&relinked_ids, other_id);
+ }
+ if (other_id != id) {
+ other_id->lib = id_root_reference->lib;
+ }
+ }
+ FOREACH_MAIN_ID_END;
+
+ struct IDRemapper *id_remapper = BKE_id_remapper_create();
for (todo_id_iter = todo_ids.first; todo_id_iter != NULL; todo_id_iter = todo_id_iter->next) {
reference_id = todo_id_iter->data;
ID *local_id = reference_id->newid;
@@ -427,55 +460,25 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain,
local_id->override_library->hierarchy_root = id_hierarchy_root;
+ BKE_id_remapper_add(id_remapper, reference_id, local_id);
+
Key *reference_key, *local_key = NULL;
if ((reference_key = BKE_key_from_id(reference_id)) != NULL) {
local_key = BKE_key_from_id(reference_id->newid);
BLI_assert(local_key != NULL);
- }
-
- /* Still checking the whole Main, that way we can tag other local IDs as needing to be
- * remapped to use newly created overriding IDs, if needed. */
- ID *id;
- FOREACH_MAIN_ID_BEGIN (bmain, id) {
- ID *other_id;
- /* In case we created new overrides as 'no main', they are not accessible directly in this
- * loop, but we can get to them through their reference's `newid` pointer. */
- if (do_no_main && id->lib == reference_id->lib && id->newid != NULL) {
- other_id = id->newid;
- /* Otherwise we cannot properly distinguish between IDs that are actually from the
- * linked library (and should not be remapped), and IDs that are overrides re-generated
- * from the reference from the linked library, and must therefore be remapped.
- *
- * This is reset afterwards at the end of this loop. */
- other_id->lib = NULL;
- }
- else {
- other_id = id;
- }
- /* If other ID is a linked one, but not from the same library as our reference, then we
- * consider we should also remap it, as part of recursive resync. */
- if ((other_id->tag & LIB_TAG_DOIT) != 0 && other_id->lib != reference_id->lib &&
- other_id != local_id) {
- BKE_libblock_relink_ex(bmain,
- other_id,
- reference_id,
- local_id,
- ID_REMAP_SKIP_OVERRIDE_LIBRARY | ID_REMAP_FORCE_USER_REFCOUNT);
- if (reference_key != NULL) {
- BKE_libblock_relink_ex(bmain,
- other_id,
- &reference_key->id,
- &local_key->id,
- ID_REMAP_SKIP_OVERRIDE_LIBRARY | ID_REMAP_FORCE_USER_REFCOUNT);
- }
- }
- if (other_id != id) {
- other_id->lib = reference_id->lib;
- }
+ BKE_id_remapper_add(id_remapper, &reference_key->id, &local_key->id);
}
- FOREACH_MAIN_ID_END;
}
+
+ BKE_libblock_relink_multiple(bmain,
+ relinked_ids,
+ ID_REMAP_TYPE_REMAP,
+ id_remapper,
+ ID_REMAP_SKIP_OVERRIDE_LIBRARY | ID_REMAP_FORCE_USER_REFCOUNT);
+
+ BKE_id_remapper_free(id_remapper);
+ BLI_linklist_free(relinked_ids, NULL);
}
else {
/* We need to cleanup potentially already created data. */
@@ -1353,8 +1356,9 @@ static void lib_override_library_remap(Main *bmain,
{
ID *id;
struct IDRemapper *remapper = BKE_id_remapper_create();
- FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ LinkNode *nomain_ids = NULL;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (id->tag & LIB_TAG_DOIT && id->newid != NULL && id->lib == id_root_reference->lib) {
ID *id_override_new = id->newid;
ID *id_override_old = BLI_ghash_lookup(linkedref_to_old_override, id);
@@ -1363,26 +1367,28 @@ static void lib_override_library_remap(Main *bmain,
}
BKE_id_remapper_add(remapper, id_override_old, id_override_new);
- /* Remap no-main override IDs we just created too. */
- GHashIterator linkedref_to_old_override_iter;
- GHASH_ITER (linkedref_to_old_override_iter, linkedref_to_old_override) {
- ID *id_override_old_iter = BLI_ghashIterator_getValue(&linkedref_to_old_override_iter);
- if ((id_override_old_iter->tag & LIB_TAG_NO_MAIN) == 0) {
- continue;
- }
-
- BKE_libblock_relink_ex(bmain,
- id_override_old_iter,
- id_override_old,
- id_override_new,
- ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
- }
}
}
FOREACH_MAIN_ID_END;
+ /* Remap no-main override IDs we just created too. */
+ GHashIterator linkedref_to_old_override_iter;
+ GHASH_ITER (linkedref_to_old_override_iter, linkedref_to_old_override) {
+ ID *id_override_old_iter = BLI_ghashIterator_getValue(&linkedref_to_old_override_iter);
+ if ((id_override_old_iter->tag & LIB_TAG_NO_MAIN) == 0) {
+ continue;
+ }
+
+ BLI_linklist_prepend(&nomain_ids, id_override_old_iter);
+ }
+
/* Remap all IDs to use the new override. */
BKE_libblock_remap_multiple(bmain, remapper, 0);
+ BKE_libblock_relink_multiple(bmain,
+ nomain_ids,
+ ID_REMAP_TYPE_REMAP,
+ remapper,
+ ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
BKE_id_remapper_free(remapper);
}
@@ -1641,6 +1647,8 @@ static bool lib_override_library_resync(Main *bmain,
BKE_main_collection_sync(bmain);
+ LinkNode *id_override_old_list = NULL;
+
/* We need to apply override rules in a separate loop, after all ID pointers have been properly
* remapped, and all new local override IDs have gotten their proper original names, otherwise
* override operations based on those ID names would fail. */
@@ -1690,19 +1698,27 @@ static bool lib_override_library_resync(Main *bmain,
RNA_OVERRIDE_APPLY_FLAG_NOP);
}
- /* Once overrides have been properly 'transferred' from old to new ID, we can clear ID usages
- * of the old one.
- * This is necessary in case said old ID is not in Main anymore. */
- BKE_libblock_relink_ex(bmain,
- id_override_old,
- NULL,
- NULL,
- ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
- id_override_old->tag |= LIB_TAG_NO_USER_REFCOUNT;
+ BLI_linklist_prepend(&id_override_old_list, id_override_old);
}
}
FOREACH_MAIN_ID_END;
+ /* Once overrides have been properly 'transferred' from old to new ID, we can clear ID usages
+ * of the old one.
+ * This is necessary in case said old ID is not in Main anymore. */
+ struct IDRemapper *id_remapper = BKE_id_remapper_create();
+ BKE_libblock_relink_multiple(bmain,
+ id_override_old_list,
+ ID_REMAP_TYPE_CLEANUP,
+ id_remapper,
+ ID_REMAP_FORCE_USER_REFCOUNT | ID_REMAP_FORCE_NEVER_NULL_USAGE);
+ for (LinkNode *ln_iter = id_override_old_list; ln_iter != NULL; ln_iter = ln_iter->next) {
+ ID *id_override_old = ln_iter->link;
+ id_override_old->tag |= LIB_TAG_NO_USER_REFCOUNT;
+ }
+ BKE_id_remapper_free(id_remapper);
+ BLI_linklist_free(id_override_old_list, NULL);
+
/* Delete old override IDs.
* Note that we have to use tagged group deletion here, since ID deletion also uses
* LIB_TAG_DOIT. This improves performances anyway, so everything is fine. */
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 24e7178dd63..1a6fcf5ff43 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -8,6 +8,7 @@
#include "CLG_log.h"
+#include "BLI_linklist.h"
#include "BLI_utildefines.h"
#include "DNA_collection_types.h"
@@ -681,6 +682,126 @@ void BKE_libblock_unlink(Main *bmain,
* ... sigh
*/
+typedef struct LibblockRelinkMultipleUserData {
+ Main *bmain;
+ LinkNode *ids;
+} LibBlockRelinkMultipleUserData;
+
+static void libblock_relink_foreach_idpair_cb(ID *old_id, ID *new_id, void *user_data)
+{
+ LibBlockRelinkMultipleUserData *data = user_data;
+ Main *bmain = data->bmain;
+ LinkNode *ids = data->ids;
+
+ BLI_assert(old_id != NULL);
+ BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
+ BLI_assert(old_id != new_id);
+
+ bool is_object_update_processed = false;
+ for (LinkNode *ln_iter = ids; ln_iter != NULL; ln_iter = ln_iter->next) {
+ ID *id_iter = ln_iter->link;
+
+ /* Some after-process updates.
+ * This is a bit ugly, but cannot see a way to avoid it.
+ * Maybe we should do a per-ID callback for this instead?
+ */
+ switch (GS(id_iter->name)) {
+ case ID_SCE:
+ case ID_GR: {
+ /* NOTE: here we know which collection we have affected, so at lest for NULL children
+ * detection we can only process that one.
+ * This is also a required fix in case `id` would not be in Main anymore, which can happen
+ * e.g. when called from `id_delete`. */
+ Collection *owner_collection = (GS(id_iter->name) == ID_GR) ?
+ (Collection *)id_iter :
+ ((Scene *)id_iter)->master_collection;
+ switch (GS(old_id->name)) {
+ case ID_OB:
+ if (!is_object_update_processed) {
+ libblock_remap_data_postprocess_object_update(
+ bmain, (Object *)old_id, (Object *)new_id);
+ is_object_update_processed = true;
+ }
+ break;
+ case ID_GR:
+ libblock_remap_data_postprocess_collection_update(
+ bmain, owner_collection, (Collection *)old_id, (Collection *)new_id);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case ID_OB:
+ if (new_id != NULL) { /* Only affects us in case obdata was relinked (changed). */
+ libblock_remap_data_postprocess_obdata_relink(bmain, (Object *)id_iter, new_id);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void BKE_libblock_relink_multiple(Main *bmain,
+ LinkNode *ids,
+ const eIDRemapType remap_type,
+ struct IDRemapper *id_remapper,
+ const short remap_flags)
+{
+ BLI_assert(remap_type == ID_REMAP_TYPE_REMAP || BKE_id_remapper_is_empty(id_remapper));
+
+ for (LinkNode *ln_iter = ids; ln_iter != NULL; ln_iter = ln_iter->next) {
+ ID *id_iter = ln_iter->link;
+ libblock_remap_data(bmain, id_iter, remap_type, id_remapper, remap_flags);
+ }
+
+ switch (remap_type) {
+ case ID_REMAP_TYPE_REMAP: {
+ LibBlockRelinkMultipleUserData user_data = {0};
+ user_data.bmain = bmain;
+ user_data.ids = ids;
+
+ BKE_id_remapper_iter(id_remapper, libblock_relink_foreach_idpair_cb, &user_data);
+ break;
+ }
+ case ID_REMAP_TYPE_CLEANUP: {
+ bool is_object_update_processed = false;
+ for (LinkNode *ln_iter = ids; ln_iter != NULL; ln_iter = ln_iter->next) {
+ ID *id_iter = ln_iter->link;
+
+ switch (GS(id_iter->name)) {
+ case ID_SCE:
+ case ID_GR: {
+ /* NOTE: here we know which collection we have affected, so at lest for NULL children
+ * detection we can only process that one.
+ * This is also a required fix in case `id` would not be in Main anymore, which can
+ * happen e.g. when called from `id_delete`. */
+ Collection *owner_collection = (GS(id_iter->name) == ID_GR) ?
+ (Collection *)id_iter :
+ ((Scene *)id_iter)->master_collection;
+ /* No choice but to check whole objects once, and all children collections. */
+ libblock_remap_data_postprocess_collection_update(bmain, owner_collection, NULL, NULL);
+ if (!is_object_update_processed) {
+ libblock_remap_data_postprocess_object_update(bmain, NULL, NULL);
+ is_object_update_processed = true;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ }
+
+ DEG_relations_tag_update(bmain);
+}
+
void BKE_libblock_relink_ex(
Main *bmain, void *idv, void *old_idv, void *new_idv, const short remap_flags)
{
@@ -690,13 +811,15 @@ void BKE_libblock_relink_ex(
ID *id = idv;
ID *old_id = old_idv;
ID *new_id = new_idv;
+ LinkNode ids = {.next = NULL, .link = idv};
/* No need to lock here, we are only affecting given ID, not bmain database. */
struct IDRemapper *id_remapper = BKE_id_remapper_create();
eIDRemapType remap_type = ID_REMAP_TYPE_REMAP;
- BLI_assert(id);
- if (old_id) {
+ BLI_assert(id != NULL);
+ UNUSED_VARS_NDEBUG(id);
+ if (old_id != NULL) {
BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name));
BLI_assert(old_id != new_id);
BKE_id_remapper_add(id_remapper, old_id, new_id);
@@ -706,56 +829,19 @@ void BKE_libblock_relink_ex(
remap_type = ID_REMAP_TYPE_CLEANUP;
}
- libblock_remap_data(bmain, id, remap_type, id_remapper, remap_flags);
- BKE_id_remapper_free(id_remapper);
-
- /* Some after-process updates.
- * This is a bit ugly, but cannot see a way to avoid it.
- * Maybe we should do a per-ID callback for this instead?
- */
- switch (GS(id->name)) {
- case ID_SCE:
- case ID_GR: {
- /* NOTE: here we know which collection we have affected, so at lest for NULL children
- * detection we can only process that one.
- * This is also a required fix in case `id` would not be in Main anymore, which can happen
- * e.g. when called from `id_delete`. */
- Collection *owner_collection = (GS(id->name) == ID_GR) ? (Collection *)id :
- ((Scene *)id)->master_collection;
- if (old_id) {
- switch (GS(old_id->name)) {
- case ID_OB:
- libblock_remap_data_postprocess_object_update(
- bmain, (Object *)old_id, (Object *)new_id);
- break;
- case ID_GR:
- libblock_remap_data_postprocess_collection_update(
- bmain, owner_collection, (Collection *)old_id, (Collection *)new_id);
- break;
- default:
- break;
- }
- }
- else {
- /* No choice but to check whole objects/collections. */
- libblock_remap_data_postprocess_collection_update(bmain, owner_collection, NULL, NULL);
- libblock_remap_data_postprocess_object_update(bmain, NULL, NULL);
- }
- break;
- }
- case ID_OB:
- if (new_id) { /* Only affects us in case obdata was relinked (changed). */
- libblock_remap_data_postprocess_obdata_relink(bmain, (Object *)id, new_id);
- }
- break;
- default:
- break;
- }
+ BKE_libblock_relink_multiple(bmain, &ids, remap_type, id_remapper, remap_flags);
- DEG_relations_tag_update(bmain);
+ BKE_id_remapper_free(id_remapper);
}
-static void libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag);
+typedef struct RelinkToNewIDData {
+ LinkNode *ids;
+ struct IDRemapper *id_remapper;
+} RelinkToNewIDData;
+
+static void libblock_relink_to_newid_prepare_data(Main *bmain,
+ ID *id,
+ RelinkToNewIDData *relink_data);
static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data)
{
const int cb_flag = cb_data->cb_flag;
@@ -764,35 +850,34 @@ static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data)
}
Main *bmain = cb_data->bmain;
- ID *id_owner = cb_data->id_owner;
ID **id_pointer = cb_data->id_pointer;
ID *id = *id_pointer;
+ RelinkToNewIDData *relink_data = (RelinkToNewIDData *)cb_data->user_data;
+
if (id) {
- const int remap_flag = POINTER_AS_INT(cb_data->user_data);
/* See: NEW_ID macro */
if (id->newid != NULL) {
- const int remap_flag_final = remap_flag | ID_REMAP_SKIP_INDIRECT_USAGE |
- ID_REMAP_SKIP_OVERRIDE_LIBRARY;
- BKE_libblock_relink_ex(bmain, id_owner, id, id->newid, (short)remap_flag_final);
+ BKE_id_remapper_add(relink_data->id_remapper, id, id->newid);
id = id->newid;
}
if (id->tag & LIB_TAG_NEW) {
- id->tag &= ~LIB_TAG_NEW;
- libblock_relink_to_newid(bmain, id, remap_flag);
+ libblock_relink_to_newid_prepare_data(bmain, id, relink_data);
}
}
return IDWALK_RET_NOP;
}
-static void libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag)
+static void libblock_relink_to_newid_prepare_data(Main *bmain,
+ ID *id,
+ RelinkToNewIDData *relink_data)
{
if (ID_IS_LINKED(id)) {
return;
}
id->tag &= ~LIB_TAG_NEW;
- BKE_library_foreach_ID_link(
- bmain, id, id_relink_to_newid_looper, POINTER_FROM_INT(remap_flag), 0);
+ BLI_linklist_prepend(&relink_data->ids, id);
+ BKE_library_foreach_ID_link(bmain, id, id_relink_to_newid_looper, relink_data, 0);
}
void BKE_libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag)
@@ -803,8 +888,15 @@ void BKE_libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag)
/* We do not want to have those cached relationship data here. */
BLI_assert(bmain->relations == NULL);
- BKE_layer_collection_resync_forbid();
- libblock_relink_to_newid(bmain, id, remap_flag);
- BKE_layer_collection_resync_allow();
- BKE_main_collection_sync_remap(bmain);
+ RelinkToNewIDData relink_data = {.ids = NULL, .id_remapper = BKE_id_remapper_create()};
+
+ libblock_relink_to_newid_prepare_data(bmain, id, &relink_data);
+
+ const short remap_flag_final = remap_flag | ID_REMAP_SKIP_INDIRECT_USAGE |
+ ID_REMAP_SKIP_OVERRIDE_LIBRARY;
+ BKE_libblock_relink_multiple(
+ bmain, relink_data.ids, ID_REMAP_TYPE_REMAP, relink_data.id_remapper, remap_flag_final);
+
+ BKE_id_remapper_free(relink_data.id_remapper);
+ BLI_linklist_free(relink_data.ids, NULL);
}
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 824c1ab1b90..b30d8f92cc6 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -199,7 +199,7 @@ 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);
+ BKE_bpath_foreach_path_fixed_process(bpath_data, me->ldata.external->filepath);
}
}
@@ -1166,6 +1166,7 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me,
{
BMeshFromMeshParams bmesh_from_mesh_params{};
bmesh_from_mesh_params.calc_face_normal = false;
+ bmesh_from_mesh_params.calc_vert_normal = false;
bmesh_from_mesh_params.add_key_index = add_key_index;
bmesh_from_mesh_params.use_shapekey = true;
bmesh_from_mesh_params.active_shapekey = ob->shapenr;
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index 1542f7119d1..40c6fbcf67e 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -1308,7 +1308,7 @@ Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph,
if (build_shapekey_layers && me->key &&
(kb = (KeyBlock *)BLI_findlink(&me->key->block, ob_eval->shapenr - 1))) {
- BKE_keyblock_convert_to_mesh(kb, me);
+ BKE_keyblock_convert_to_mesh(kb, me->mvert, me->totvert);
}
Mesh *mesh_temp = (Mesh *)BKE_id_copy_ex(nullptr, &me->id, nullptr, LIB_ID_COPY_LOCALIZE);
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc
index da0bd1f021d..6c5a5de31fc 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.cc
+++ b/source/blender/blenkernel/intern/mesh_evaluate.cc
@@ -695,7 +695,7 @@ static void bm_corners_to_loops_ex(ID *id,
if (CustomData_external_test(fdata, CD_MDISPS)) {
if (id && fdata->external) {
- CustomData_external_add(ldata, id, CD_MDISPS, totloop, fdata->external->filename);
+ CustomData_external_add(ldata, id, CD_MDISPS, totloop, fdata->external->filepath);
}
}
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index e9c26c80141..9c4098e2db6 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -561,7 +561,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_edge_users,
+ const int edge_user_count,
const struct MPoly *mpoly_array,
const struct MeshElemMap *edge_poly_map,
void *user_data);
@@ -764,14 +764,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_edge_users,
+ const int edge_user_count,
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_edge_users == 2)) {
+ if ((mp->flag & ME_SMOOTH) && !(me->flag & ME_SHARP) && (edge_user_count == 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]] :
@@ -935,7 +935,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_edge_users),
+ const int UNUSED(edge_user_count),
const MPoly *UNUSED(mpoly_array),
const MeshElemMap *UNUSED(edge_poly_map),
void *user_data)
diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c
index da23aea43f3..9202690b3c9 100644
--- a/source/blender/blenkernel/intern/mesh_mirror.c
+++ b/source/blender/blenkernel/intern/mesh_mirror.c
@@ -46,6 +46,7 @@ Mesh *BKE_mesh_mirror_bisect_on_mirror_plane_for_modifier(MirrorModifierData *mm
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
.cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX,
.emask = CD_MASK_ORIGINDEX,
.pmask = CD_MASK_ORIGINDEX},
@@ -92,6 +93,7 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
},
&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
.cd_mask_extra =
{
.vmask = CD_MASK_SHAPEKEY,
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index 1c2a903d8c3..4448bedb57a 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -306,14 +306,14 @@ static void mesh_calc_normals_poly_and_vertex_finalize_fn(
}
}
-static void mesh_calc_normals_poly_and_vertex(const MVert *mvert,
- const int mvert_len,
- const MLoop *mloop,
- const int UNUSED(mloop_len),
- const MPoly *mpoly,
- const int mpoly_len,
- float (*r_poly_normals)[3],
- float (*r_vert_normals)[3])
+void BKE_mesh_calc_normals_poly_and_vertex(const MVert *mvert,
+ const int mvert_len,
+ const MLoop *mloop,
+ const int UNUSED(mloop_len),
+ const MPoly *mpoly,
+ const int mpoly_len,
+ float (*r_poly_normals)[3],
+ float (*r_vert_normals)[3])
{
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -372,14 +372,14 @@ const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
vert_normals = BKE_mesh_vertex_normals_for_write(&mesh_mutable);
poly_normals = BKE_mesh_poly_normals_for_write(&mesh_mutable);
- mesh_calc_normals_poly_and_vertex(mesh_mutable.mvert,
- mesh_mutable.totvert,
- mesh_mutable.mloop,
- mesh_mutable.totloop,
- mesh_mutable.mpoly,
- mesh_mutable.totpoly,
- poly_normals,
- vert_normals);
+ BKE_mesh_calc_normals_poly_and_vertex(mesh_mutable.mvert,
+ mesh_mutable.totvert,
+ mesh_mutable.mloop,
+ mesh_mutable.totloop,
+ mesh_mutable.mpoly,
+ mesh_mutable.totpoly,
+ poly_normals,
+ vert_normals);
BKE_mesh_vertex_normals_clear_dirty(&mesh_mutable);
BKE_mesh_poly_normals_clear_dirty(&mesh_mutable);
@@ -613,19 +613,19 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
/* Compute ref alpha, average angle of all available edge vectors to lnor. */
if (edge_vectors) {
float alpha = 0.0f;
- int nbr = 0;
+ int count = 0;
while (!BLI_stack_is_empty(edge_vectors)) {
const float *vec = (const float *)BLI_stack_peek(edge_vectors);
alpha += saacosf(dot_v3v3(vec, lnor));
BLI_stack_discard(edge_vectors);
- nbr++;
+ count++;
}
- /* NOTE: In theory, this could be `nbr > 2`,
+ /* NOTE: In theory, this could be `count > 2`,
* but there is one case where we only have two edges for two loops:
* a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.).
*/
- BLI_assert(nbr >= 2); /* This piece of code shall only be called for more than one loop. */
- lnor_space->ref_alpha = alpha / (float)nbr;
+ BLI_assert(count >= 2); /* This piece of code shall only be called for more than one loop. */
+ lnor_space->ref_alpha = alpha / (float)count;
}
else {
lnor_space->ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) +
@@ -1134,7 +1134,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
/* We validate clnors data on the fly - cheapest way to do! */
int clnors_avg[2] = {0, 0};
short(*clnor_ref)[2] = nullptr;
- int clnors_nbr = 0;
+ int clnors_count = 0;
bool clnors_invalid = false;
/* Temp loop normal stack. */
@@ -1194,7 +1194,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
if (clnors_data) {
/* Accumulate all clnors, if they are not all equal we have to fix that! */
short(*clnor)[2] = &clnors_data[mlfan_vert_index];
- if (clnors_nbr) {
+ if (clnors_count) {
clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]);
}
else {
@@ -1202,7 +1202,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
}
clnors_avg[0] += (*clnor)[0];
clnors_avg[1] += (*clnor)[1];
- clnors_nbr++;
+ clnors_count++;
/* We store here a pointer to all custom lnors processed. */
BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor);
}
@@ -1262,8 +1262,8 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli
if (clnors_invalid) {
short *clnor;
- clnors_avg[0] /= clnors_nbr;
- clnors_avg[1] /= clnors_nbr;
+ clnors_avg[0] /= clnors_count;
+ clnors_avg[1] /= clnors_count;
/* Fix/update all clnors of this fan with computed average value. */
if (G.debug & G_DEBUG) {
printf("Invalid clnors in this fan!\n");
@@ -1952,7 +1952,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
BLI_BITMAP_DISABLE(done_loops, i);
}
else {
- int nbr_nors = 0;
+ int avg_nor_count = 0;
float avg_nor[3];
short clnor_data_tmp[2], *clnor_data;
@@ -1962,7 +1962,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
const int nidx = use_vertices ? (int)mloops[lidx].v : lidx;
float *nor = r_custom_loopnors[nidx];
- nbr_nors++;
+ avg_nor_count++;
add_v3_v3(avg_nor, nor);
BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]);
@@ -1970,7 +1970,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
BLI_BITMAP_DISABLE(done_loops, lidx);
}
- mul_v3_fl(avg_nor, 1.0f / (float)nbr_nors);
+ mul_v3_fl(avg_nor, 1.0f / (float)avg_nor_count);
BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], avg_nor, clnor_data_tmp);
while ((clnor_data = (short *)BLI_SMALLSTACK_POP(clnors_data))) {
@@ -2088,8 +2088,8 @@ void BKE_mesh_normals_loop_to_vertex(const int numVerts,
const float (*clnors)[3],
float (*r_vert_clnors)[3])
{
- int *vert_loops_nbr = (int *)MEM_calloc_arrayN(
- (size_t)numVerts, sizeof(*vert_loops_nbr), __func__);
+ int *vert_loops_count = (int *)MEM_calloc_arrayN(
+ (size_t)numVerts, sizeof(*vert_loops_count), __func__);
copy_vn_fl((float *)r_vert_clnors, 3 * numVerts, 0.0f);
@@ -2099,14 +2099,14 @@ void BKE_mesh_normals_loop_to_vertex(const int numVerts,
const uint v = ml->v;
add_v3_v3(r_vert_clnors[v], clnors[i]);
- vert_loops_nbr[v]++;
+ vert_loops_count[v]++;
}
for (i = 0; i < numVerts; i++) {
- mul_v3_fl(r_vert_clnors[i], 1.0f / (float)vert_loops_nbr[i]);
+ mul_v3_fl(r_vert_clnors[i], 1.0f / (float)vert_loops_count[i]);
}
- MEM_freeN(vert_loops_nbr);
+ MEM_freeN(vert_loops_count);
}
#undef LNOR_SPACE_TRIGO_THRESHOLD
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
index b34a241bca8..3c7992ec3d7 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
@@ -401,6 +401,7 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh)
BMeshFromMeshParams bmesh_from_mesh_params{};
bmesh_from_mesh_params.calc_face_normal = true;
+ bmesh_from_mesh_params.calc_vert_normal = true;
BM_mesh_bm_from_me(bm, mesh, &bmesh_from_mesh_params);
BMVert *v;
diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc
index fb526354305..6af765d7de5 100644
--- a/source/blender/blenkernel/intern/mesh_validate.cc
+++ b/source/blender/blenkernel/intern/mesh_validate.cc
@@ -577,7 +577,8 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
else if (mp->loopstart + mp->totloop > totloop) {
/* Invalid loop data. */
PRINT_ERR(
- "\tPoly %u uses loops out of range (loopstart: %d, loopend: %d, max nbr of loops: %u)",
+ "\tPoly %u uses loops out of range "
+ "(loopstart: %d, loopend: %d, max number of loops: %u)",
sp->index,
mp->loopstart,
mp->loopstart + mp->totloop - 1,
@@ -1049,41 +1050,40 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata,
bool BKE_mesh_validate(Mesh *me, const bool do_verbose, const bool cddata_check_mask)
{
- bool is_valid = true;
bool changed;
if (do_verbose) {
CLOG_INFO(&LOG, 0, "MESH: %s", me->id.name + 2);
}
- is_valid &= BKE_mesh_validate_all_customdata(&me->vdata,
- me->totvert,
- &me->edata,
- me->totedge,
- &me->ldata,
- me->totloop,
- &me->pdata,
- me->totpoly,
- cddata_check_mask,
- do_verbose,
- true,
- &changed);
-
- is_valid &= BKE_mesh_validate_arrays(me,
- me->mvert,
- me->totvert,
- me->medge,
- me->totedge,
- me->mface,
- me->totface,
- me->mloop,
- me->totloop,
- me->mpoly,
- me->totpoly,
- me->dvert,
- do_verbose,
- true,
- &changed);
+ BKE_mesh_validate_all_customdata(&me->vdata,
+ me->totvert,
+ &me->edata,
+ me->totedge,
+ &me->ldata,
+ me->totloop,
+ &me->pdata,
+ me->totpoly,
+ cddata_check_mask,
+ do_verbose,
+ true,
+ &changed);
+
+ BKE_mesh_validate_arrays(me,
+ me->mvert,
+ me->totvert,
+ me->medge,
+ me->totedge,
+ me->mface,
+ me->totface,
+ me->mloop,
+ me->totloop,
+ me->mpoly,
+ me->totpoly,
+ me->dvert,
+ do_verbose,
+ true,
+ &changed);
if (changed) {
DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY_ALL_MODES);
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index c23110b4703..3a93b7cde84 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -60,6 +60,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_moviecache.h"
+#include "IMB_openexr.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
@@ -68,10 +69,6 @@
#include "BLO_read_write.h"
-#ifdef WITH_OPENEXR
-# include "intern/openexr/openexr_multi.h"
-#endif
-
static void free_buffers(MovieClip *clip);
static void movie_clip_init_data(ID *id)
diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c
index 80926bfc1e2..cad680ecedd 100644
--- a/source/blender/blenkernel/intern/multires_unsubdivide.c
+++ b/source/blender/blenkernel/intern/multires_unsubdivide.c
@@ -869,6 +869,7 @@ static BMesh *get_bmesh_from_mesh(Mesh *mesh)
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
return bm;
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 9a573919165..e3fe5d77d63 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -55,6 +55,7 @@
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_idtype.h"
+#include "BKE_image_format.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
@@ -532,13 +533,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) {
BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage);
}
- else if ((ntree->type == NTREE_GEOMETRY) &&
- (node->type == GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP)) {
- BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
- NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage;
- BKE_curvemapping_blend_write(writer, (const CurveMapping *)data->curve_vec);
- BKE_curvemapping_blend_write(writer, (const CurveMapping *)data->curve_rgb);
- }
else if (ntree->type == NTREE_SHADER && (node->type == SH_NODE_SCRIPT)) {
NodeShaderScript *nss = (NodeShaderScript *)node->storage;
if (nss->bytecode) {
@@ -602,8 +596,13 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
if (node->type == CMP_NODE_OUTPUT_FILE) {
/* Inputs have their own storage data. */
+ NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage;
+ BKE_image_format_blend_write(writer, &nimf->format);
+
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- BLO_write_struct(writer, NodeImageMultiFileSocket, sock->storage);
+ NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage;
+ BLO_write_struct(writer, NodeImageMultiFileSocket, sockdata);
+ BKE_image_format_blend_write(writer, &sockdata->format);
}
}
if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) {
@@ -715,18 +714,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
BKE_curvemapping_blend_read(reader, (CurveMapping *)node->storage);
break;
}
- case GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP: {
- NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage;
- BLO_read_data_address(reader, &data->curve_vec);
- if (data->curve_vec) {
- BKE_curvemapping_blend_read(reader, data->curve_vec);
- }
- BLO_read_data_address(reader, &data->curve_rgb);
- if (data->curve_rgb) {
- BKE_curvemapping_blend_read(reader, data->curve_rgb);
- }
- break;
- }
case SH_NODE_SCRIPT: {
NodeShaderScript *nss = (NodeShaderScript *)node->storage;
BLO_read_data_address(reader, &nss->bytecode);
@@ -768,6 +755,11 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
iuser->scene = nullptr;
break;
}
+ case CMP_NODE_OUTPUT_FILE: {
+ NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage;
+ BKE_image_format_blend_read_data(reader, &nimf->format);
+ break;
+ }
case FN_NODE_INPUT_STRING: {
NodeInputString *storage = (NodeInputString *)node->storage;
BLO_read_data_address(reader, &storage->string);
@@ -790,6 +782,14 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
direct_link_node_socket(reader, sock);
}
+
+ /* Socket storage. */
+ if (node->type == CMP_NODE_OUTPUT_FILE) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage;
+ BKE_image_format_blend_read_data(reader, &sockdata->format);
+ }
+ }
}
/* interface socket lists */
@@ -3616,15 +3616,13 @@ void nodeSetActive(bNodeTree *ntree, bNode *node)
LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) {
tnode->flag &= ~NODE_ACTIVE;
- if ((node->typeinfo->nclass == NODE_CLASS_TEXTURE) ||
- (node->typeinfo->type == GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE)) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
tnode->flag &= ~NODE_ACTIVE_TEXTURE;
}
}
node->flag |= NODE_ACTIVE;
- if ((node->typeinfo->nclass == NODE_CLASS_TEXTURE) ||
- (node->typeinfo->type == GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE)) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
node->flag |= NODE_ACTIVE_TEXTURE;
}
}
@@ -4692,45 +4690,10 @@ static void registerGeometryNodes()
{
register_node_type_geo_group();
- register_node_type_geo_legacy_attribute_proximity();
- register_node_type_geo_legacy_attribute_randomize();
- register_node_type_geo_legacy_attribute_remove();
- register_node_type_geo_legacy_attribute_transfer();
- register_node_type_geo_legacy_curve_endpoints();
- register_node_type_geo_legacy_curve_reverse();
- register_node_type_geo_legacy_curve_set_handles();
- register_node_type_geo_legacy_curve_spline_type();
- register_node_type_geo_legacy_curve_subdivide();
- register_node_type_geo_legacy_curve_to_points();
- register_node_type_geo_legacy_delete_geometry();
- register_node_type_geo_legacy_edge_split();
- register_node_type_geo_legacy_material_assign();
- register_node_type_geo_legacy_mesh_to_curve();
- register_node_type_geo_legacy_points_to_volume();
- register_node_type_geo_legacy_raycast();
- register_node_type_geo_legacy_select_by_handle_type();
- register_node_type_geo_legacy_select_by_material();
- register_node_type_geo_legacy_subdivision_surface();
- register_node_type_geo_legacy_volume_to_mesh();
-
register_node_type_geo_accumulate_field();
- register_node_type_geo_align_rotation_to_vector();
register_node_type_geo_attribute_capture();
- register_node_type_geo_attribute_clamp();
- register_node_type_geo_attribute_color_ramp();
- register_node_type_geo_attribute_combine_xyz();
- 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();
- register_node_type_geo_attribute_mix();
- register_node_type_geo_attribute_separate_xyz();
register_node_type_geo_attribute_statistic();
- register_node_type_geo_attribute_vector_math();
- register_node_type_geo_attribute_vector_rotate();
register_node_type_geo_boolean();
register_node_type_geo_bounding_box();
register_node_type_geo_collection_info();
@@ -4811,12 +4774,6 @@ static void registerGeometryNodes()
register_node_type_geo_mesh_to_curve();
register_node_type_geo_mesh_to_points();
register_node_type_geo_object_info();
- register_node_type_geo_point_distribute();
- register_node_type_geo_point_instance();
- register_node_type_geo_point_rotate();
- register_node_type_geo_point_scale();
- register_node_type_geo_point_separate();
- register_node_type_geo_point_translate();
register_node_type_geo_points_to_vertices();
register_node_type_geo_points_to_volume();
register_node_type_geo_proximity();
@@ -4824,7 +4781,6 @@ static void registerGeometryNodes()
register_node_type_geo_realize_instances();
register_node_type_geo_remove_attribute();
register_node_type_geo_rotate_instances();
- register_node_type_geo_sample_texture();
register_node_type_geo_scale_elements();
register_node_type_geo_scale_instances();
register_node_type_geo_separate_components();
@@ -4855,8 +4811,6 @@ static void registerGeometryNodes()
static void registerFunctionNodes()
{
- register_node_type_fn_legacy_random_float();
-
register_node_type_fn_align_euler_to_vector();
register_node_type_fn_boolean_math();
register_node_type_fn_compare();
diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc
index 85061018383..baf3a0c8d22 100644
--- a/source/blender/blenkernel/intern/node_tree_update.cc
+++ b/source/blender/blenkernel/intern/node_tree_update.cc
@@ -1455,6 +1455,16 @@ class NodeTreeMainUpdater {
socket_hash = noise::hash(socket_hash, input_socket_hash);
}
}
+ /* The Image Texture node has a special case. The behavior of the color output changes
+ * depending on whether the Alpha output is linked. */
+ if (node.bnode()->type == SH_NODE_TEX_IMAGE && socket.index() == 0) {
+ BLI_assert(socket.name() == "Color");
+ const OutputSocketRef &alpha_socket = node.output(1);
+ BLI_assert(alpha_socket.name() == "Alpha");
+ if (alpha_socket.is_directly_linked()) {
+ socket_hash = noise::hash(socket_hash);
+ }
+ }
hash_by_socket_id[socket.id()] = socket_hash;
sockets_to_check.pop();
}
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 985c9edac1a..1e3b5d77fa7 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -4630,9 +4630,11 @@ bool BKE_object_shapekey_remove(Main *bmain, Object *ob, KeyBlock *kb)
if (key->refkey) {
/* apply new basis key on original data */
switch (ob->type) {
- case OB_MESH:
- BKE_keyblock_convert_to_mesh(key->refkey, (Mesh *)ob->data);
+ case OB_MESH: {
+ Mesh *mesh = (Mesh *)ob->data;
+ BKE_keyblock_convert_to_mesh(key->refkey, mesh->mvert, mesh->totvert);
break;
+ }
case OB_CURVES_LEGACY:
case OB_SURF:
BKE_keyblock_convert_to_curve(
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 70a11dce92d..4dc0130366e 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -25,6 +25,7 @@
#include "BLI_utildefines.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_ocean.h"
#include "ocean_intern.h"
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 62794e3d0ec..e7ed100ed03 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -28,6 +28,7 @@
#include "BLI_utildefines.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
@@ -173,16 +174,16 @@ PackedFile *BKE_packedfile_new_from_memory(void *mem, int memlen)
return pf;
}
-PackedFile *BKE_packedfile_new(ReportList *reports, const char *filename, const char *basepath)
+PackedFile *BKE_packedfile_new(ReportList *reports, const char *filepath, const char *basepath)
{
PackedFile *pf = NULL;
int file, filelen;
char name[FILE_MAX];
void *data;
- /* render result has no filename and can be ignored
+ /* render result has no filepath and can be ignored
* any other files with no name can be ignored too */
- if (filename[0] == '\0') {
+ if (filepath[0] == '\0') {
return pf;
}
@@ -190,7 +191,7 @@ PackedFile *BKE_packedfile_new(ReportList *reports, const char *filename, const
/* convert relative filenames to absolute filenames */
- BLI_strncpy(name, filename, sizeof(name));
+ BLI_strncpy(name, filepath, sizeof(name));
BLI_path_abs(name, basepath);
/* open the file
@@ -284,7 +285,7 @@ void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose)
int BKE_packedfile_write_to_file(ReportList *reports,
const char *ref_file_name,
- const char *filename,
+ const char *filepath,
PackedFile *pf,
const bool guimode)
{
@@ -298,7 +299,7 @@ int BKE_packedfile_write_to_file(ReportList *reports,
if (guimode) {
} // XXX waitcursor(1);
- BLI_strncpy(name, filename, sizeof(name));
+ BLI_strncpy(name, filepath, sizeof(name));
BLI_path_abs(name, ref_file_name);
if (BLI_exists(name)) {
@@ -357,7 +358,7 @@ int BKE_packedfile_write_to_file(ReportList *reports,
}
enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
- const char *filename,
+ const char *filepath,
PackedFile *pf)
{
BLI_stat_t st;
@@ -365,7 +366,7 @@ enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
char buf[4096];
char name[FILE_MAX];
- BLI_strncpy(name, filename, sizeof(name));
+ BLI_strncpy(name, filepath, sizeof(name));
BLI_path_abs(name, ref_file_name);
if (BLI_stat(name, &st) == -1) {
@@ -503,7 +504,7 @@ static void unpack_generate_paths(const char *name,
const PackedFile *pf = imapf->packedfile;
enum eImbFileType ftype = IMB_ispic_type_from_memory((const uchar *)pf->data, pf->size);
if (ftype != IMB_FTYPE_NONE) {
- const int imtype = BKE_image_ftype_to_imtype(ftype, NULL);
+ const int imtype = BKE_ftype_to_imtype(ftype, NULL);
BKE_image_path_ensure_ext_from_imtype(tempname, imtype);
}
}
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 238cf1ad74e..1c58173f570 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -1099,6 +1099,7 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint)
}
else if ((CurvesSculpt **)r_paint == &ts->curves_sculpt) {
CurvesSculpt *data = MEM_callocN(sizeof(*data), __func__);
+ data->curve_length = 0.3f;
paint = &data->paint;
}
else if (*r_paint == &ts->imapaint.paint) {
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index c47b22dcd34..9ea1336a95a 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -2661,8 +2661,8 @@ void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params
int from = PART_FROM_FACE;
totparent = (int)(totchild * part->parents * 0.3f);
- if (use_render_params && part->child_nbr && part->ren_child_nbr) {
- totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
+ if (use_render_params && part->child_percent && part->child_render_percent) {
+ totparent *= (float)part->child_percent / (float)part->child_render_percent;
}
/* hard limit, workaround for it being ignored above */
@@ -2736,8 +2736,8 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx,
if (totchild && part->childtype == PART_CHILD_FACES) {
totparent = (int)(totchild * part->parents * 0.3f);
- if (use_render_params && part->child_nbr && part->ren_child_nbr) {
- totparent *= (float)part->child_nbr / (float)part->ren_child_nbr;
+ if (use_render_params && part->child_percent && part->child_render_percent) {
+ totparent *= (float)part->child_percent / (float)part->child_render_percent;
}
/* part->parents could still be 0 so we can't test with totparent */
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
index 8106ae8b302..5dba4d3f003 100644
--- a/source/blender/blenkernel/intern/particle_child.c
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -142,9 +142,6 @@ static void do_kink_spiral(ParticleThreadContext *ctx,
float kink_freq = part->kink_freq;
float kink_shape = part->kink_shape;
float kink_axis_random = part->kink_axis_random;
- float rough1 = part->rough1;
- float rough2 = part->rough2;
- float rough_end = part->rough_end;
ParticlePathIterator iter;
ParticleCacheKey *key;
@@ -164,9 +161,6 @@ static void do_kink_spiral(ParticleThreadContext *ctx,
if (ptex) {
kink_amp *= ptex->kink_amp;
kink_freq *= ptex->kink_freq;
- rough1 *= ptex->rough1;
- rough2 *= ptex->rough2;
- rough_end *= ptex->roughe;
}
cut_time = (totkeys - 1) * ptex->length;
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index 83fb52ce1ef..d2c3776d4ea 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -64,14 +64,14 @@ static void distribute_simple_children(Scene *scene,
{
ChildParticle *cpa = NULL;
int i, p;
- int child_nbr = psys_get_child_number(scene, psys, use_render_params);
- int totpart = psys_get_tot_child(scene, psys, use_render_params);
+ const int child_num = psys_get_child_number(scene, psys, use_render_params);
+ const int totpart = psys_get_tot_child(scene, psys, use_render_params);
RNG *rng = BLI_rng_new_srandom(31415926 + psys->seed + psys->child_seed);
alloc_child_particles(psys, totpart);
cpa = psys->child;
- for (i = 0; i < child_nbr; i++) {
+ for (i = 0; i < child_num; i++) {
for (p = 0; p < psys->totpart; p++, cpa++) {
float length = 2.0;
cpa->parent = p;
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 3a1aefec2d3..7fdc60a265b 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -98,9 +98,9 @@ float psys_get_current_display_percentage(ParticleSystem *psys, const bool use_r
ParticleSettings *part = psys->part;
if ((use_render_params &&
- !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */
- (part->child_nbr && part->childtype) || /* display percentage applies to children */
- (psys->pointcache->flag & PTCACHE_BAKING)) /* baking is always done with full amount */
+ !particles_are_dynamic(psys)) || /* non-dynamic particles can be rendered fully */
+ (part->child_percent && part->childtype) || /* display percentage applies to children */
+ (psys->pointcache->flag & PTCACHE_BAKING)) /* baking is always done with full amount */
{
return 1.0f;
}
@@ -280,20 +280,20 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart)
int psys_get_child_number(Scene *scene, ParticleSystem *psys, const bool use_render_params)
{
- int nbr;
+ int child_num;
if (!psys->part->childtype) {
return 0;
}
if (use_render_params) {
- nbr = psys->part->ren_child_nbr;
+ child_num = psys->part->child_render_percent;
}
else {
- nbr = psys->part->child_nbr;
+ child_num = psys->part->child_percent;
}
- return get_render_child_particle_number(&scene->r, nbr, use_render_params);
+ return get_render_child_particle_number(&scene->r, child_num, use_render_params);
}
int psys_get_tot_child(Scene *scene, ParticleSystem *psys, const bool use_render_params)
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index baf2f0bac8a..b98c82e365e 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -70,6 +70,7 @@
#include "BKE_idprop.h"
#include "BKE_idtype.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
@@ -201,15 +202,8 @@ static void scene_init_data(ID *id)
colorspace_name,
sizeof(scene->sequencer_colorspace_settings.name));
- /* Those next two sets (render and baking settings) are not currently in use,
- * but are exposed to RNA API and hence must have valid data. */
- BKE_color_managed_display_settings_init(&scene->r.im_format.display_settings);
- BKE_color_managed_view_settings_init_render(
- &scene->r.im_format.view_settings, &scene->r.im_format.display_settings, "Filmic");
-
- BKE_color_managed_display_settings_init(&scene->r.bake.im_format.display_settings);
- BKE_color_managed_view_settings_init_render(
- &scene->r.bake.im_format.view_settings, &scene->r.bake.im_format.display_settings, "Filmic");
+ BKE_image_format_init(&scene->r.im_format, true);
+ BKE_image_format_init(&scene->r.bake.im_format, true);
/* Curve Profile */
scene->toolsettings->custom_bevel_profile_preset = BKE_curveprofile_add(PROF_PRESET_LINE);
@@ -295,15 +289,8 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
BKE_color_managed_colorspace_settings_copy(&scene_dst->sequencer_colorspace_settings,
&scene_src->sequencer_colorspace_settings);
- BKE_color_managed_display_settings_copy(&scene_dst->r.im_format.display_settings,
- &scene_src->r.im_format.display_settings);
- BKE_color_managed_view_settings_copy(&scene_dst->r.im_format.view_settings,
- &scene_src->r.im_format.view_settings);
-
- BKE_color_managed_display_settings_copy(&scene_dst->r.bake.im_format.display_settings,
- &scene_src->r.bake.im_format.display_settings);
- BKE_color_managed_view_settings_copy(&scene_dst->r.bake.im_format.view_settings,
- &scene_src->r.bake.im_format.view_settings);
+ BKE_image_format_copy(&scene_dst->r.im_format, &scene_src->r.im_format);
+ BKE_image_format_copy(&scene_dst->r.bake.im_format, &scene_src->r.bake.im_format);
BKE_curvemapping_copy_data(&scene_dst->r.mblur_shutter_curve, &scene_src->r.mblur_shutter_curve);
@@ -402,6 +389,8 @@ static void scene_free_data(ID *id)
BKE_sound_destroy_scene(scene);
BKE_color_managed_view_settings_free(&scene->view_settings);
+ BKE_image_format_free(&scene->r.im_format);
+ BKE_image_format_free(&scene->r.bake.im_format);
BKE_previewimg_free(&scene->preview);
BKE_curvemapping_free_data(&scene->r.mblur_shutter_curve);
@@ -1044,6 +1033,8 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres
}
BKE_color_managed_view_settings_blend_write(writer, &sce->view_settings);
+ BKE_image_format_blend_write(writer, &sce->r.im_format);
+ BKE_image_format_blend_write(writer, &sce->r.bake.im_format);
/* writing RigidBodyWorld data to the blend file */
if (sce->rigidbody_world) {
@@ -1276,6 +1267,8 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
}
BKE_color_managed_view_settings_blend_read_data(reader, &sce->view_settings);
+ BKE_image_format_blend_read_data(reader, &sce->r.im_format);
+ BKE_image_format_blend_read_data(reader, &sce->r.bake.im_format);
BLO_read_data_address(reader, &sce->rigidbody_world);
RigidBodyWorld *rbw = sce->rigidbody_world;
@@ -1855,15 +1848,8 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type)
BKE_color_managed_colorspace_settings_copy(&sce_copy->sequencer_colorspace_settings,
&sce->sequencer_colorspace_settings);
- BKE_color_managed_display_settings_copy(&sce_copy->r.im_format.display_settings,
- &sce->r.im_format.display_settings);
- BKE_color_managed_view_settings_copy(&sce_copy->r.im_format.view_settings,
- &sce->r.im_format.view_settings);
-
- BKE_color_managed_display_settings_copy(&sce_copy->r.bake.im_format.display_settings,
- &sce->r.bake.im_format.display_settings);
- BKE_color_managed_view_settings_copy(&sce_copy->r.bake.im_format.view_settings,
- &sce->r.bake.im_format.view_settings);
+ BKE_image_format_copy(&sce_copy->r.im_format, &sce->r.im_format);
+ BKE_image_format_copy(&sce_copy->r.bake.im_format, &sce->r.bake.im_format);
BKE_curvemapping_copy_data(&sce_copy->r.mblur_shutter_curve, &sce->r.mblur_shutter_curve);
@@ -2765,17 +2751,17 @@ int get_render_subsurf_level(const RenderData *r, int lvl, bool for_render)
return lvl;
}
-int get_render_child_particle_number(const RenderData *r, int num, bool for_render)
+int get_render_child_particle_number(const RenderData *r, int child_num, bool for_render)
{
if (r->mode & R_SIMPLIFY) {
if (for_render) {
- return (int)(r->simplify_particles_render * num);
+ return (int)(r->simplify_particles_render * child_num);
}
- return (int)(r->simplify_particles * num);
+ return (int)(r->simplify_particles * child_num);
}
- return num;
+ return child_num;
}
Base *_setlooper_base_step(Scene **sce_iter, ViewLayer *view_layer, Base *base)
@@ -3137,7 +3123,9 @@ int BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname)
return 0;
}
-void BKE_scene_multiview_filepath_get(SceneRenderView *srv, const char *filepath, char *r_filepath)
+void BKE_scene_multiview_filepath_get(const SceneRenderView *srv,
+ const char *filepath,
+ char *r_filepath)
{
BLI_strncpy(r_filepath, filepath, FILE_MAX);
BLI_path_suffix(r_filepath, FILE_MAX, srv->suffix, "");
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
index dc5b1d28539..eecb374cd63 100644
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ b/source/blender/blenkernel/intern/spline_base.cc
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_array.hh"
+#include "BLI_generic_virtual_array.hh"
#include "BLI_span.hh"
#include "BLI_task.hh"
#include "BLI_timeit.hh"
@@ -9,19 +10,17 @@
#include "BKE_attribute_math.hh"
#include "BKE_spline.hh"
-#include "FN_generic_virtual_array.hh"
-
using blender::Array;
using blender::float3;
+using blender::GMutableSpan;
+using blender::GSpan;
+using blender::GVArray;
using blender::IndexRange;
using blender::MutableSpan;
using blender::Span;
using blender::VArray;
using blender::attribute_math::convert_to_static_type;
using blender::bke::AttributeIDRef;
-using blender::fn::GMutableSpan;
-using blender::fn::GSpan;
-using blender::fn::GVArray;
CurveType Spline::type() const
{
@@ -100,7 +99,7 @@ void Spline::reverse()
this->attributes.foreach_attribute(
[&](const AttributeIDRef &id, const AttributeMetaData &meta_data) {
- std::optional<blender::fn::GMutableSpan> attribute = this->attributes.get_for_write(id);
+ std::optional<blender::GMutableSpan> attribute = this->attributes.get_for_write(id);
if (!attribute) {
BLI_assert_unreachable();
return false;
diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc
index e9ae51b16f8..8e207f93bf5 100644
--- a/source/blender/blenkernel/intern/spline_bezier.cc
+++ b/source/blender/blenkernel/intern/spline_bezier.cc
@@ -8,11 +8,11 @@
using blender::Array;
using blender::float3;
+using blender::GVArray;
using blender::IndexRange;
using blender::MutableSpan;
using blender::Span;
using blender::VArray;
-using blender::fn::GVArray;
void BezierSpline::copy_settings(Spline &dst) const
{
diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc
index a8a17b7aee6..9d1d5a53a43 100644
--- a/source/blender/blenkernel/intern/spline_nurbs.cc
+++ b/source/blender/blenkernel/intern/spline_nurbs.cc
@@ -9,11 +9,11 @@
using blender::Array;
using blender::float3;
+using blender::GVArray;
using blender::IndexRange;
using blender::MutableSpan;
using blender::Span;
using blender::VArray;
-using blender::fn::GVArray;
void NURBSpline::copy_settings(Spline &dst) const
{
diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc
index a5d3fd47ede..122f7f6c059 100644
--- a/source/blender/blenkernel/intern/spline_poly.cc
+++ b/source/blender/blenkernel/intern/spline_poly.cc
@@ -6,9 +6,9 @@
#include "BKE_spline.hh"
using blender::float3;
+using blender::GVArray;
using blender::MutableSpan;
using blender::Span;
-using blender::fn::GVArray;
void PolySpline::copy_settings(Spline &UNUSED(dst)) const
{
diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c
index 811b6bfe182..f17450ac3f4 100644
--- a/source/blender/blenkernel/intern/studiolight.c
+++ b/source/blender/blenkernel/intern/studiolight.c
@@ -25,13 +25,12 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "IMB_openexr.h"
#include "GPU_texture.h"
#include "MEM_guardedalloc.h"
-#include "intern/openexr/openexr_multi.h"
-
/* Statics */
static ListBase studiolights;
static int last_studiolight_id = 0;
@@ -1167,18 +1166,18 @@ static void studiolight_add_files_from_datafolder(const int folder_id,
const char *subfolder,
int flag)
{
- struct direntry *dir;
+ struct direntry *dirs;
const char *folder = BKE_appdir_folder_id(folder_id, subfolder);
if (folder) {
- uint totfile = BLI_filelist_dir_contents(folder, &dir);
+ const uint dirs_num = BLI_filelist_dir_contents(folder, &dirs);
int i;
- for (i = 0; i < totfile; i++) {
- if (dir[i].type & S_IFREG) {
- studiolight_add_file(dir[i].path, flag);
+ for (i = 0; i < dirs_num; i++) {
+ if (dirs[i].type & S_IFREG) {
+ studiolight_add_file(dirs[i].path, flag);
}
}
- BLI_filelist_free(dir, totfile);
- dir = NULL;
+ BLI_filelist_free(dirs, dirs_num);
+ dirs = NULL;
}
}
diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c
index 7b1ebd5df1f..ee1976d5946 100644
--- a/source/blender/blenkernel/intern/subdiv.c
+++ b/source/blender/blenkernel/intern/subdiv.c
@@ -106,7 +106,7 @@ Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
* The thing here is: OpenSubdiv can only deal with faces, but our
* side of subdiv also deals with loose vertices and edges. */
}
- Subdiv *subdiv = MEM_callocN(sizeof(Subdiv), "subdiv from converetr");
+ Subdiv *subdiv = MEM_callocN(sizeof(Subdiv), "subdiv from converter");
subdiv->settings = *settings;
subdiv->topology_refiner = osd_topology_refiner;
subdiv->evaluator = NULL;
diff --git a/source/blender/blenkernel/intern/subdiv_modifier.c b/source/blender/blenkernel/intern/subdiv_modifier.c
index 34dfdaf7595..83772f153d9 100644
--- a/source/blender/blenkernel/intern/subdiv_modifier.c
+++ b/source/blender/blenkernel/intern/subdiv_modifier.c
@@ -77,6 +77,10 @@ static bool is_subdivision_evaluation_possible_on_gpu(void)
return false;
}
+ if (GPU_max_shader_storage_buffer_bindings() < MAX_GPU_SUBDIV_SSBOS) {
+ return false;
+ }
+
const int available_evaluators = openSubdiv_getAvailableEvaluators();
if ((available_evaluators & OPENSUBDIV_EVALUATOR_GLSL_COMPUTE) == 0) {
return false;
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 991fd9e3aff..8759d7a0e5f 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -143,7 +143,7 @@ static void text_copy_data(Main *UNUSED(bmain),
/** Free (or release) any data used by this text (does not free the text itself). */
static void text_free_data(ID *id)
{
- /* No animdata here. */
+ /* No animation-data here. */
Text *text = (Text *)id;
BKE_text_free_lines(text);
@@ -1501,7 +1501,8 @@ char *txt_sel_to_buf(Text *text, size_t *r_buf_strlen)
if (linef == linel) {
length = charl - charf;
buf = MEM_mallocN(length + 1, "sel buffer");
- memcpy(buf, linef->line + charf, length + 1);
+ memcpy(buf, linef->line + charf, length);
+ buf[length] = '\0';
}
else {
/* Add 1 for the '\n' */
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index 21a56c44c9b..6145e51920f 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -24,6 +24,9 @@
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
#include "libmv-capi.h"
#include "tracking_private.h"
@@ -99,6 +102,12 @@ typedef struct AutoTrackContext {
/* Accessor for images of clip. Used by the autotrack context. */
TrackingImageAccessor *image_accessor;
+ /* Image buffers acquired for markers which are using keyframe pattern matching.
+ * These image buffers are user-referenced and flagged as persistent so that they don't get
+ * removed from the movie cache during tracking. */
+ int num_referenced_image_buffers;
+ ImBuf **referenced_image_buffers;
+
/* --------------------------------------------------------------------
* Variant part.
* Denotes tracing state and tracking result.
@@ -554,6 +563,59 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Context tracking start.
+ *
+ * Called from possible job once before performing tracking steps.
+ * \{ */
+
+static void reference_keyframed_image_buffers(AutoTrackContext *context)
+{
+ /* NOTE: This is potentially over-allocating, but it simplifies memory manipulation.
+ * In practice this is unlikely to be noticed in the profiler as the memory footprint of this
+ * data is way less of what the tracking process will use. */
+ context->referenced_image_buffers = MEM_calloc_arrayN(
+ context->num_autotrack_markers, sizeof(ImBuf *), __func__);
+
+ context->num_referenced_image_buffers = 0;
+
+ for (int i = 0; i < context->num_autotrack_markers; ++i) {
+ const AutoTrackMarker *autotrack_marker = &context->autotrack_markers[i];
+ const int clip_index = autotrack_marker->libmv_marker.clip;
+ const int track_index = autotrack_marker->libmv_marker.track;
+
+ const AutoTrackClip *autotrack_clip = &context->autotrack_clips[clip_index];
+ const AutoTrackTrack *autotrack_track = &context->all_autotrack_tracks[track_index];
+ const MovieTrackingTrack *track = autotrack_track->track;
+
+ if (track->pattern_match != TRACK_MATCH_KEYFRAME) {
+ continue;
+ }
+
+ const int scene_frame = BKE_movieclip_remap_clip_to_scene_frame(
+ autotrack_clip->clip, autotrack_marker->libmv_marker.reference_frame);
+
+ MovieClipUser user_at_keyframe;
+ BKE_movieclip_user_set_frame(&user_at_keyframe, scene_frame);
+ user_at_keyframe.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
+ user_at_keyframe.render_flag = 0;
+
+ /* Keep reference to the image buffer so that we can manipulate its flags later on.
+ * Also request the movie cache to not remove the image buffer from the cache. */
+ ImBuf *ibuf = BKE_movieclip_get_ibuf(autotrack_clip->clip, &user_at_keyframe);
+ ibuf->userflags |= IB_PERSISTENT;
+
+ context->referenced_image_buffers[context->num_referenced_image_buffers++] = ibuf;
+ }
+}
+
+void BKE_autotrack_context_start(AutoTrackContext *context)
+{
+ reference_keyframed_image_buffers(context);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Threaded context step (tracking process).
* \{ */
@@ -799,6 +861,20 @@ void BKE_autotrack_context_finish(AutoTrackContext *context)
}
}
+static void release_keyframed_image_buffers(AutoTrackContext *context)
+{
+ for (int i = 0; i < context->num_referenced_image_buffers; ++i) {
+ ImBuf *ibuf = context->referenced_image_buffers[i];
+
+ /* Restore flag. It is not expected that anyone else is setting this flag on image buffers from
+ * movie clip, so can simply clear the flag. */
+ ibuf->userflags &= ~IB_PERSISTENT;
+ IMB_freeImBuf(ibuf);
+ }
+
+ MEM_freeN(context->referenced_image_buffers);
+}
+
void BKE_autotrack_context_free(AutoTrackContext *context)
{
if (context->autotrack != NULL) {
@@ -809,6 +885,8 @@ void BKE_autotrack_context_free(AutoTrackContext *context)
tracking_image_accessor_destroy(context->image_accessor);
}
+ release_keyframed_image_buffers(context);
+
MEM_SAFE_FREE(context->all_autotrack_tracks);
MEM_SAFE_FREE(context->autotrack_markers);
diff --git a/source/blender/blenkernel/intern/type_conversions.cc b/source/blender/blenkernel/intern/type_conversions.cc
index 2e8b5b3433b..d10979eeee9 100644
--- a/source/blender/blenkernel/intern/type_conversions.cc
+++ b/source/blender/blenkernel/intern/type_conversions.cc
@@ -288,8 +288,7 @@ 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
+void DataTypeConversions::convert_to_initialized_n(GSpan from_span, GMutableSpan to_span) const
{
const CPPType &from_type = from_span.type();
const CPPType &to_type = to_span.type();
@@ -305,19 +304,17 @@ void DataTypeConversions::convert_to_initialized_n(fn::GSpan from_span,
fn->call_auto(IndexRange(from_span.size()), params, context);
}
-class GVArray_For_ConvertedGVArray : public fn::GVArrayImpl {
+class GVArray_For_ConvertedGVArray : public GVArrayImpl {
private:
- fn::GVArray varray_;
+ GVArray varray_;
const CPPType &from_type_;
ConversionFunctions old_to_new_conversions_;
public:
- GVArray_For_ConvertedGVArray(fn::GVArray varray,
+ GVArray_For_ConvertedGVArray(GVArray varray,
const CPPType &to_type,
const DataTypeConversions &conversions)
- : fn::GVArrayImpl(to_type, varray.size()),
- varray_(std::move(varray)),
- from_type_(varray_.type())
+ : GVArrayImpl(to_type, varray.size()), varray_(std::move(varray)), from_type_(varray_.type())
{
old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type);
}
@@ -340,18 +337,18 @@ class GVArray_For_ConvertedGVArray : public fn::GVArrayImpl {
}
};
-class GVMutableArray_For_ConvertedGVMutableArray : public fn::GVMutableArrayImpl {
+class GVMutableArray_For_ConvertedGVMutableArray : public GVMutableArrayImpl {
private:
- fn::GVMutableArray varray_;
+ GVMutableArray varray_;
const CPPType &from_type_;
ConversionFunctions old_to_new_conversions_;
ConversionFunctions new_to_old_conversions_;
public:
- GVMutableArray_For_ConvertedGVMutableArray(fn::GVMutableArray varray,
+ GVMutableArray_For_ConvertedGVMutableArray(GVMutableArray varray,
const CPPType &to_type,
const DataTypeConversions &conversions)
- : fn::GVMutableArrayImpl(to_type, varray.size()),
+ : GVMutableArrayImpl(to_type, varray.size()),
varray_(std::move(varray)),
from_type_(varray_.type())
{
@@ -384,7 +381,7 @@ class GVMutableArray_For_ConvertedGVMutableArray : public fn::GVMutableArrayImpl
}
};
-fn::GVArray DataTypeConversions::try_convert(fn::GVArray varray, const CPPType &to_type) const
+GVArray DataTypeConversions::try_convert(GVArray varray, const CPPType &to_type) const
{
const CPPType &from_type = varray.type();
if (from_type == to_type) {
@@ -393,11 +390,11 @@ fn::GVArray DataTypeConversions::try_convert(fn::GVArray varray, const CPPType &
if (!this->is_convertible(from_type, to_type)) {
return {};
}
- return fn::GVArray::For<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this);
+ return GVArray::For<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this);
}
-fn::GVMutableArray DataTypeConversions::try_convert(fn::GVMutableArray varray,
- const CPPType &to_type) const
+GVMutableArray DataTypeConversions::try_convert(GVMutableArray varray,
+ const CPPType &to_type) const
{
const CPPType &from_type = varray.type();
if (from_type == to_type) {
@@ -406,7 +403,7 @@ fn::GVMutableArray DataTypeConversions::try_convert(fn::GVMutableArray varray,
if (!this->is_convertible(from_type, to_type)) {
return {};
}
- return fn::GVMutableArray::For<GVMutableArray_For_ConvertedGVMutableArray>(
+ return GVMutableArray::For<GVMutableArray_For_ConvertedGVMutableArray>(
std::move(varray), to_type, *this);
}
diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/blenlib/BLI_cpp_type.hh
index 420e2a8d9a9..881408f460b 100644
--- a/source/blender/functions/FN_cpp_type.hh
+++ b/source/blender/blenlib/BLI_cpp_type.hh
@@ -3,28 +3,47 @@
#pragma once
/** \file
- * \ingroup fn
+ * \ingroup bli
*
- * The `CPPType` class is the core of a runtime-type-system. It allows working with arbitrary C++
- * types in a generic way. An instance of `CPPType` wraps exactly one type like `int` or
- * `std::string`.
+ * The `CPPType` class allows working with arbitrary C++ types in a generic way. An instance of
+ * #CPPType wraps exactly one type like `int` or `std::string`.
+ *
+ * With #CPPType one can write generic data structures and algorithms. That is similar to what C++
+ * templates allow. The difference is that when using templates, the types have to be known at
+ * compile time and the code has to be instantiated multiple times. On the other hand, when using
+ * #CPPType, the data type only has to be known at run-time, and the code only has to be compiled
+ * once. Whether #CPPType or classic c++ templates should be used depends on the context:
+ * - If the data type is not known at run-time, #CPPType should be used.
+ * - If the data type is known to be one of a few, it depends on how performance sensitive the code
+ * is.
+ * - If it it's a small hot loop, a template can be used to optimize for every type (at the
+ * cost of longer compile time, a larger binary and the complexity that comes from using
+ * templates).
+ * - If the code is not performance sensitive, it usually makes sense to use #CPPType instead.
+ * - Sometimes a combination can make sense. Optimized code can be be generated at compile-time for
+ * some types, while there is a fallback code path using #CPPType for all other types.
+ * #CPPType::to_static_type allows dispatching between both versions based on the type.
+ *
+ * Under some circumstances, #CPPType serves a similar role as #std::type_info. However, #CPPType
+ * has much more utility because it contains methods for actually working with instances of the
+ * type.
*
* Every type has a size and an alignment. Every function dealing with C++ types in a generic way,
- * has to make sure that alignment rules are followed. The methods provided by a CPPType instance
+ * has to make sure that alignment rules are followed. The methods provided by a #CPPType instance
* will check for correct alignment as well.
*
* Every type has a name that is for debugging purposes only. It should not be used as identifier.
*
- * To check if two instances of CPPType represent the same type, only their pointers have to be
- * compared. Any C++ type has at most one corresponding CPPType instance.
+ * To check if two instances of #CPPType represent the same type, only their pointers have to be
+ * compared. Any C++ type has at most one corresponding #CPPType instance.
*
- * A CPPType instance comes with many methods that allow dealing with types in a generic way. Most
- * methods come in three variants. Using the construct-default methods as example:
- * - default_construct(void *ptr):
+ * A #CPPType instance comes with many methods that allow dealing with types in a generic way. Most
+ * methods come in three variants. Using the default-construct methods as an example:
+ * - `default_construct(void *ptr)`:
* Constructs a single instance of that type at the given pointer.
- * - default_construct_n(void *ptr, int64_t n):
+ * - `default_construct_n(void *ptr, int64_t n)`:
* Constructs n instances of that type in an array that starts at the given pointer.
- * - default_construct_indices(void *ptr, IndexMask mask):
+ * - `default_construct_indices(void *ptr, IndexMask mask)`:
* Constructs multiple instances of that type in an array that starts at the given pointer.
* Only the indices referenced by `mask` will by constructed.
*
@@ -39,8 +58,9 @@
* Concepts like inheritance are currently not captured by this system. This is not because it is
* not possible, but because it was not necessary to add this complexity yet.
*
- * One could also implement CPPType itself using virtual inheritance. However, I found the approach
- * used now with explicit function pointers to work better. Here are some reasons:
+ * One could also implement CPPType itself using virtual methods and a child class for every
+ * wrapped type. However, the approach used now with explicit function pointers to works better.
+ * Here are some reasons:
* - If CPPType would be inherited once for every used C++ type, we would get a lot of classes
* that would only be instanced once each.
* - Methods like `default_construct` that operate on a single instance have to be fast. Even this
@@ -52,6 +72,7 @@
#include "BLI_hash.hh"
#include "BLI_index_mask.hh"
+#include "BLI_map.hh"
#include "BLI_math_base.h"
#include "BLI_string_ref.hh"
#include "BLI_utility_mixins.hh"
@@ -71,7 +92,7 @@ enum class CPPTypeFlags {
};
ENUM_OPERATORS(CPPTypeFlags, CPPTypeFlags::EqualityComparable)
-namespace blender::fn {
+namespace blender {
/** Utility class to pass template parameters to constructor of `CPPType`. */
template<typename T, CPPTypeFlags Flags> struct CPPTypeParam {
@@ -142,7 +163,7 @@ class CPPType : NonCopyable, NonMovable {
/**
* Get the `CPPType` that corresponds to a specific static type.
* This only works for types that actually implement the template specialization using
- * `MAKE_CPP_TYPE`.
+ * `BLI_CPP_TYPE_MAKE`.
*/
template<typename T> static const CPPType &get()
{
@@ -624,9 +645,80 @@ class CPPType : NonCopyable, NonMovable {
{
return this == &CPPType::get<std::decay_t<T>>();
}
+
+ /**
+ * Convert a #CPPType that is only known at run-time, to a static type that is known at
+ * compile-time. This allows the compiler to optimize a function for specific types, while all
+ * other types can still use a generic fallback function.
+ *
+ * \param Types The types that code should be generated for.
+ * \param fn The function object to call. This is expected to have a templated `operator()` and a
+ * non-templated `operator()`. The templated version will be called if the current #CPPType
+ * matches any of the given types. Otherwise, the non-templated function is called.
+ */
+ template<typename... Types, typename Fn> void to_static_type(const Fn &fn) const
+ {
+ using Callback = void (*)(const Fn &fn);
+
+ /* Build a lookup table to avoid having to compare the current #CPPType with every type in
+ * #Types one after another. */
+ static const Map<const CPPType *, Callback> callback_map = []() {
+ Map<const CPPType *, Callback> callback_map;
+ /* This adds an entry in the map for every type in #Types. */
+ (callback_map.add_new(&CPPType::get<Types>(),
+ [](const Fn &fn) {
+ /* Call the templated `operator()` of the given function object. */
+ fn.template operator()<Types>();
+ }),
+ ...);
+ return callback_map;
+ }();
+
+ const Callback callback = callback_map.lookup_default(this, nullptr);
+ if (callback != nullptr) {
+ callback(fn);
+ }
+ else {
+ /* Call the non-templated `operator()` of the given function object. */
+ fn();
+ }
+ }
+
+ template<typename T> struct type_tag {
+ using type = T;
+ };
+
+ private:
+ template<typename Fn> struct TypeTagExecutor {
+ const Fn &fn;
+
+ template<typename T> void operator()() const
+ {
+ fn(type_tag<T>{});
+ }
+
+ void operator()() const
+ {
+ fn(type_tag<void>{});
+ }
+ };
+
+ public:
+ /**
+ * Similar to #to_static_type but is easier to use with a lambda function. The function is
+ * expected to take a single `auto type_tag` parameter. To extract the static type, use:
+ * `using T = typename decltype(type_tag)::type;`
+ *
+ * If the current #CPPType is not in #Types, the type tag is `void`.
+ */
+ template<typename... Types, typename Fn> void to_static_type_tag(const Fn &fn) const
+ {
+ TypeTagExecutor<Fn> executor{fn};
+ this->to_static_type<Types...>(executor);
+ }
};
-} // namespace blender::fn
+} // namespace blender
/* Utility for allocating an uninitialized buffer for a single value of the given #CPPType. */
#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name) \
diff --git a/source/blender/functions/FN_cpp_type_make.hh b/source/blender/blenlib/BLI_cpp_type_make.hh
index ac498e40fe3..9100b2b9a0f 100644
--- a/source/blender/functions/FN_cpp_type_make.hh
+++ b/source/blender/blenlib/BLI_cpp_type_make.hh
@@ -3,13 +3,13 @@
#pragma once
/** \file
- * \ingroup fn
+ * \ingroup bli
*/
+#include "BLI_cpp_type.hh"
#include "BLI_utildefines.h"
-#include "FN_cpp_type.hh"
-namespace blender::fn::cpp_type_util {
+namespace blender::cpp_type_util {
template<typename T> void default_construct_cb(void *ptr)
{
@@ -169,9 +169,9 @@ template<typename T> uint64_t hash_cb(const void *value)
return get_default_hash(value_);
}
-} // namespace blender::fn::cpp_type_util
+} // namespace blender::cpp_type_util
-namespace blender::fn {
+namespace blender {
template<typename T, CPPTypeFlags Flags>
CPPType::CPPType(CPPTypeParam<T, Flags> /* unused */, StringRef debug_name)
@@ -240,12 +240,11 @@ CPPType::CPPType(CPPTypeParam<T, Flags> /* unused */, StringRef debug_name)
move_construct_ && move_assign_ && destruct_);
}
-} // namespace blender::fn
+} // namespace blender
-#define MAKE_CPP_TYPE(IDENTIFIER, TYPE_NAME, FLAGS) \
- template<> const blender::fn::CPPType &blender::fn::CPPType::get_impl<TYPE_NAME>() \
+#define BLI_CPP_TYPE_MAKE(IDENTIFIER, TYPE_NAME, FLAGS) \
+ template<> const blender::CPPType &blender::CPPType::get_impl<TYPE_NAME>() \
{ \
- static CPPType cpp_type{blender::fn::CPPTypeParam<TYPE_NAME, FLAGS>(), \
- STRINGIFY(IDENTIFIER)}; \
+ static CPPType cpp_type{blender::CPPTypeParam<TYPE_NAME, FLAGS>(), STRINGIFY(IDENTIFIER)}; \
return cpp_type; \
}
diff --git a/source/blender/functions/FN_generic_array.hh b/source/blender/blenlib/BLI_generic_array.hh
index 4bd0c38aa42..e1b6b29874a 100644
--- a/source/blender/functions/FN_generic_array.hh
+++ b/source/blender/blenlib/BLI_generic_array.hh
@@ -3,7 +3,7 @@
#pragma once
/** \file
- * \ingroup fn
+ * \ingroup bli
*
* This is a generic counterpart to #blender::Array, used when the type is not known at runtime.
*
@@ -14,11 +14,10 @@
*/
#include "BLI_allocator.hh"
+#include "BLI_cpp_type.hh"
+#include "BLI_generic_span.hh"
-#include "FN_cpp_type.hh"
-#include "FN_generic_span.hh"
-
-namespace blender::fn {
+namespace blender {
template<
/**
@@ -253,4 +252,4 @@ class GArray {
}
};
-} // namespace blender::fn
+} // namespace blender
diff --git a/source/blender/functions/FN_generic_pointer.hh b/source/blender/blenlib/BLI_generic_pointer.hh
index a1fb16b5ab2..226f76c3d33 100644
--- a/source/blender/functions/FN_generic_pointer.hh
+++ b/source/blender/blenlib/BLI_generic_pointer.hh
@@ -2,9 +2,9 @@
#pragma once
-#include "FN_cpp_type.hh"
+#include "BLI_cpp_type.hh"
-namespace blender::fn {
+namespace blender {
/**
* A generic non-const pointer whose type is only known at runtime.
@@ -120,4 +120,4 @@ class GPointer {
}
};
-} // namespace blender::fn
+} // namespace blender
diff --git a/source/blender/functions/FN_generic_span.hh b/source/blender/blenlib/BLI_generic_span.hh
index 2d3bfa55787..f4f93735e06 100644
--- a/source/blender/functions/FN_generic_span.hh
+++ b/source/blender/blenlib/BLI_generic_span.hh
@@ -3,14 +3,13 @@
#pragma once
/** \file
- * \ingroup fn
+ * \ingroup bli
*/
+#include "BLI_cpp_type.hh"
#include "BLI_span.hh"
-#include "FN_cpp_type.hh"
-
-namespace blender::fn {
+namespace blender {
/**
* A generic span. It behaves just like a blender::Span<T>, but the type is only known at run-time.
@@ -167,4 +166,4 @@ class GMutableSpan {
}
};
-} // namespace blender::fn
+} // namespace blender
diff --git a/source/blender/functions/FN_generic_value_map.hh b/source/blender/blenlib/BLI_generic_value_map.hh
index 3807ada1c3c..bd8408526b8 100644
--- a/source/blender/functions/FN_generic_value_map.hh
+++ b/source/blender/blenlib/BLI_generic_value_map.hh
@@ -2,12 +2,11 @@
#pragma once
+#include "BLI_generic_pointer.hh"
#include "BLI_linear_allocator.hh"
#include "BLI_map.hh"
-#include "FN_generic_pointer.hh"
-
-namespace blender::fn {
+namespace blender {
/**
* This is a map that stores key-value-pairs. What makes it special is that the type of values does
@@ -109,4 +108,4 @@ template<typename Key> class GValueMap {
}
};
-} // namespace blender::fn
+} // namespace blender
diff --git a/source/blender/functions/FN_generic_vector_array.hh b/source/blender/blenlib/BLI_generic_vector_array.hh
index d7416a0f5b9..c98817df4e3 100644
--- a/source/blender/functions/FN_generic_vector_array.hh
+++ b/source/blender/blenlib/BLI_generic_vector_array.hh
@@ -3,7 +3,7 @@
#pragma once
/** \file
- * \ingroup fn
+ * \ingroup bli
*
* A`GVectorArray` is a container for a fixed amount of dynamically growing vectors with a generic
* data type. Its main use case is to store many small vectors with few separate allocations. Using
@@ -11,11 +11,10 @@
*/
#include "BLI_array.hh"
+#include "BLI_generic_virtual_vector_array.hh"
#include "BLI_linear_allocator.hh"
-#include "FN_generic_virtual_vector_array.hh"
-
-namespace blender::fn {
+namespace blender {
/* An array of vectors containing elements of a generic type. */
class GVectorArray : NonCopyable, NonMovable {
@@ -145,4 +144,4 @@ class GVVectorArray_For_GVectorArray : public GVVectorArray {
}
};
-} // namespace blender::fn
+} // namespace blender
diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/blenlib/BLI_generic_virtual_array.hh
index ced0c2b9546..f4c9e745cf9 100644
--- a/source/blender/functions/FN_generic_virtual_array.hh
+++ b/source/blender/blenlib/BLI_generic_virtual_array.hh
@@ -3,19 +3,18 @@
#pragma once
/** \file
- * \ingroup fn
+ * \ingroup bli
*
- * A generic virtual array is the same as a virtual array from blenlib, except for the fact that
- * the data type is only known at runtime.
+ * A generic virtual array is the same as a virtual array, except for the fact that the data type
+ * is only known at runtime.
*/
+#include "BLI_generic_array.hh"
+#include "BLI_generic_span.hh"
#include "BLI_timeit.hh"
#include "BLI_virtual_array.hh"
-#include "FN_generic_array.hh"
-#include "FN_generic_span.hh"
-
-namespace blender::fn {
+namespace blender {
/* -------------------------------------------------------------------- */
/** \name #GVArrayImpl and #GVMutableArrayImpl.
@@ -875,4 +874,4 @@ template<typename T> inline VMutableArray<T> GVMutableArray::typed() const
/** \} */
-} // namespace blender::fn
+} // namespace blender
diff --git a/source/blender/functions/FN_generic_virtual_vector_array.hh b/source/blender/blenlib/BLI_generic_virtual_vector_array.hh
index 1f40366da04..364b1ab33c7 100644
--- a/source/blender/functions/FN_generic_virtual_vector_array.hh
+++ b/source/blender/blenlib/BLI_generic_virtual_vector_array.hh
@@ -3,17 +3,16 @@
#pragma once
/** \file
- * \ingroup fn
+ * \ingroup bli
*
- * A generic virtual vector array is essentially the same as a virtual vector array from blenlib,
- * but its data type is only known at runtime.
+ * A generic virtual vector array is essentially the same as a virtual vector array, but its data
+ * type is only known at runtime.
*/
-#include "FN_generic_virtual_array.hh"
-
+#include "BLI_generic_virtual_array.hh"
#include "BLI_virtual_vector_array.hh"
-namespace blender::fn {
+namespace blender {
/* A generically typed version of `VVectorArray`. */
class GVVectorArray {
@@ -171,4 +170,4 @@ template<typename T> class VVectorArray_For_GVVectorArray : public VVectorArray<
}
};
-} // namespace blender::fn
+} // namespace blender
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index 5e56eec2ec6..38f3e1ee290 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -324,3 +324,32 @@ extern const float bvhtree_kdop_axes[13][3];
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+
+# include "BLI_function_ref.hh"
+# include "BLI_math_vector.hh"
+
+namespace blender {
+
+using BVHTree_RangeQuery_CPP = FunctionRef<void(int index, const float3 &co, float dist_sq)>;
+
+inline void BLI_bvhtree_range_query_cpp(BVHTree &tree,
+ const float3 co,
+ float radius,
+ BVHTree_RangeQuery_CPP fn)
+{
+ BLI_bvhtree_range_query(
+ &tree,
+ co,
+ radius,
+ [](void *userdata, const int index, const float co[3], const float dist_sq) {
+ BVHTree_RangeQuery_CPP fn = *static_cast<BVHTree_RangeQuery_CPP *>(userdata);
+ fn(index, co, dist_sq);
+ },
+ &fn);
+}
+
+} // namespace blender
+
+#endif
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 4bba84f2e29..c31e3045c97 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -202,7 +202,7 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3]);
* \return the lowest squared distance to either of the planes.
* where `(return < 0.0)` is outside.
*
- * <pre>
+ * \code{.unparsed}
* v1
* +
* /
@@ -211,7 +211,7 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3]);
* +----+
* v2 v3
* x - also outside
- * </pre>
+ * \endcode
*/
float dist_signed_squared_to_corner_v3v3v3(const float p[3],
const float v1[3],
@@ -322,18 +322,22 @@ double closest_to_line_v2_db(double r_close[2],
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.
+ *
+ * \return A value in [0, 1] that corresponds to the position of #r_close on the line segment.
*/
-void closest_to_line_segment_v2(float r_close[2],
- const float p[2],
- const float l1[2],
- const float l2[2]);
+float 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.
+ *
+ * \return A value in [0, 1] that corresponds to the position of #r_close on the line segment.
*/
-void closest_to_line_segment_v3(float r_close[3],
- const float p[3],
- const float l1[3],
- const float l2[3]);
+float 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.
diff --git a/source/blender/blenlib/BLI_math_statistics.h b/source/blender/blenlib/BLI_math_statistics.h
index d33d4be360a..501a250e1a0 100644
--- a/source/blender/blenlib/BLI_math_statistics.h
+++ b/source/blender/blenlib/BLI_math_statistics.h
@@ -28,7 +28,7 @@ extern "C" {
*
* \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 cos_vn_num: 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
@@ -37,7 +37,7 @@ extern "C" {
*/
void BLI_covariance_m_vn_ex(int n,
const float *cos_vn,
- int nbr_cos_vn,
+ int cos_vn_num,
const float *center,
bool use_sample_correction,
float *r_covmat);
@@ -45,12 +45,12 @@ void BLI_covariance_m_vn_ex(int n,
* \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.
+ * \param cos_v3_num: 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],
- int nbr_cos_v3,
+ int cos_v3_num,
bool use_sample_correction,
float r_covmat[3][3],
float r_center[3]);
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 4689072bcce..f3283371a3c 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -389,7 +389,7 @@ void mid_v3_v3v3v3(float v[3], const float v1[3], const float v2[3], const float
void mid_v2_v2v2v2(float v[2], const float v1[2], const float v2[2], const float v3[2]);
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], unsigned int nbr);
+void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], unsigned int vec_arr_num);
/**
* Specialized function for calculating normals.
@@ -660,7 +660,10 @@ void minmax_v4v4_v4(float min[4], float max[4], const float vec[4]);
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]);
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);
+void minmax_v3v3_v3_array(float r_min[3],
+ float r_max[3],
+ const float (*vec_arr)[3],
+ int var_arr_num);
/** ensure \a v1 is \a dist from \a v2 */
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], float dist);
diff --git a/source/blender/blenlib/BLI_rand.hh b/source/blender/blenlib/BLI_rand.hh
index 069a81bb84b..2c4484bd63f 100644
--- a/source/blender/blenlib/BLI_rand.hh
+++ b/source/blender/blenlib/BLI_rand.hh
@@ -103,6 +103,12 @@ class RandomNumberGenerator {
return float3(rand1, rand2, 1.0f - rand1 - rand2);
}
+ /**
+ * Round value to the next integer randomly.
+ * 4.9f is more likely to round to 5 than 4.6f.
+ */
+ int round_probabilistic(float x);
+
float2 get_unit_float2();
float3 get_unit_float3();
/**
diff --git a/source/blender/blenlib/BLI_sort.hh b/source/blender/blenlib/BLI_sort.hh
new file mode 100644
index 00000000000..411e6a0c4df
--- /dev/null
+++ b/source/blender/blenlib/BLI_sort.hh
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+/** \file
+ * \ingroup bli
+ */
+
+#ifdef WITH_TBB
+# include <tbb/parallel_sort.h>
+#else
+# include <algorithm>
+#endif
+
+namespace blender {
+
+#ifdef WITH_TBB
+using tbb::parallel_sort;
+#else
+template<typename RandomAccessIterator>
+void parallel_sort(RandomAccessIterator begin, RandomAccessIterator end)
+{
+ std::sort<RandomAccessIterator>(begin, end);
+}
+template<typename RandomAccessIterator, typename Compare>
+void parallel_sort(RandomAccessIterator begin, RandomAccessIterator end, const Compare &comp)
+{
+ std::sort<RandomAccessIterator, Compare>(begin, end, comp);
+}
+#endif
+
+} // namespace blender
diff --git a/source/blender/blenlib/BLI_timeit.hh b/source/blender/blenlib/BLI_timeit.hh
index 31e1b5d2a03..8da0a020d99 100644
--- a/source/blender/blenlib/BLI_timeit.hh
+++ b/source/blender/blenlib/BLI_timeit.hh
@@ -38,6 +38,41 @@ class ScopedTimer {
}
};
+class ScopedTimerAveraged {
+ private:
+ std::string name_;
+ TimePoint start_;
+
+ int64_t &total_count_;
+ Nanoseconds &total_time_;
+ Nanoseconds &min_time_;
+
+ public:
+ ScopedTimerAveraged(std::string name,
+ int64_t &total_count,
+ Nanoseconds &total_time,
+ Nanoseconds &min_time)
+ : name_(std::move(name)),
+ total_count_(total_count),
+ total_time_(total_time),
+ min_time_(min_time)
+ {
+ start_ = Clock::now();
+ }
+
+ ~ScopedTimerAveraged();
+};
+
} // namespace blender::timeit
#define SCOPED_TIMER(name) blender::timeit::ScopedTimer scoped_timer(name)
+
+/**
+ * Print the average and minimum runtime of the timer's scope.
+ * \warning This uses static variables, so it is not thread-safe.
+ */
+#define SCOPED_TIMER_AVERAGED(name) \
+ static int64_t total_count_; \
+ static blender::timeit::Nanoseconds total_time_; \
+ static blender::timeit::Nanoseconds min_time_ = blender::timeit::Nanoseconds::max(); \
+ blender::timeit::ScopedTimerAveraged scoped_timer(name, total_count_, total_time_, min_time_)
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index 16fd706c99d..3aa25bf6819 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -31,10 +31,8 @@
namespace blender {
/** Forward declarations for generic virtual arrays. */
-namespace fn {
class GVArray;
class GVMutableArray;
-}; // namespace fn
/**
* Implements the specifics of how the elements of a virtual array are accessed. It contains a
@@ -154,7 +152,7 @@ template<typename T> class VArrayImpl {
* arrays in all cases.
* Return true when the virtual array was assigned and false when nothing was done.
*/
- virtual bool try_assign_GVArray(fn::GVArray &UNUSED(varray)) const
+ virtual bool try_assign_GVArray(GVArray &UNUSED(varray)) const
{
return false;
}
@@ -211,7 +209,7 @@ template<typename T> class VMutableArrayImpl : public VArrayImpl<T> {
/**
* Similar to #VArrayImpl::try_assign_GVArray but for mutable virtual arrays.
*/
- virtual bool try_assign_GVMutableArray(fn::GVMutableArray &UNUSED(varray)) const
+ virtual bool try_assign_GVMutableArray(GVMutableArray &UNUSED(varray)) const
{
return false;
}
@@ -743,7 +741,7 @@ template<typename T> class VArrayCommon {
}
/** See #GVArrayImpl::try_assign_GVArray. */
- bool try_assign_GVArray(fn::GVArray &varray) const
+ bool try_assign_GVArray(GVArray &varray) const
{
return impl_->try_assign_GVArray(varray);
}
@@ -960,7 +958,7 @@ template<typename T> class VMutableArray : public VArrayCommon<T> {
}
/** See #GVMutableArrayImpl::try_assign_GVMutableArray. */
- bool try_assign_GVMutableArray(fn::GVMutableArray &varray) const
+ bool try_assign_GVMutableArray(GVMutableArray &varray) const
{
return this->get_impl()->try_assign_GVMutableArray(varray);
}
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 6e3e84f6495..647726722b1 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -50,6 +50,7 @@ set(SRC
intern/boxpack_2d.c
intern/buffer.c
intern/convexhull_2d.c
+ intern/cpp_type.cc
intern/delaunay_2d.cc
intern/dot_export.cc
intern/dynlib.c
@@ -64,6 +65,9 @@ set(SRC
intern/filereader_memory.c
intern/filereader_zstd.c
intern/fnmatch.c
+ intern/generic_vector_array.cc
+ intern/generic_virtual_array.cc
+ intern/generic_virtual_vector_array.cc
intern/gsqueue.c
intern/hash_md5.c
intern/hash_mm2a.c
@@ -161,8 +165,8 @@ set(SRC
BLI_bitmap.h
BLI_bitmap_draw_2d.h
BLI_blenlib.h
- BLI_boxpack_2d.h
BLI_bounds.hh
+ BLI_boxpack_2d.h
BLI_buffer.h
BLI_color.hh
BLI_compiler_attrs.h
@@ -170,6 +174,8 @@ set(SRC
BLI_compiler_typecheck.h
BLI_console.h
BLI_convexhull_2d.h
+ BLI_cpp_type.hh
+ BLI_cpp_type_make.hh
BLI_delaunay_2d.h
BLI_dial_2d.h
BLI_disjoint_set.hh
@@ -192,6 +198,13 @@ set(SRC
BLI_float4x4.hh
BLI_fnmatch.h
BLI_function_ref.hh
+ BLI_generic_array.hh
+ BLI_generic_pointer.hh
+ BLI_generic_span.hh
+ BLI_generic_value_map.hh
+ BLI_generic_vector_array.hh
+ BLI_generic_virtual_array.hh
+ BLI_generic_virtual_vector_array.hh
BLI_ghash.h
BLI_gsqueue.h
BLI_hash.h
@@ -222,8 +235,8 @@ set(SRC
BLI_map.hh
BLI_map_slots.hh
BLI_math.h
- BLI_math_base.hh
BLI_math_base.h
+ BLI_math_base.hh
BLI_math_base_safe.h
BLI_math_bits.h
BLI_math_boolean.hh
@@ -272,6 +285,7 @@ set(SRC
BLI_simd.h
BLI_smallhash.h
BLI_sort.h
+ BLI_sort.hh
BLI_sort_utils.h
BLI_span.hh
BLI_stack.h
@@ -403,12 +417,16 @@ if(WITH_GTESTS)
tests/BLI_array_utils_test.cc
tests/BLI_bounds_test.cc
tests/BLI_color_test.cc
+ tests/BLI_cpp_type_test.cc
tests/BLI_delaunay_2d_test.cc
tests/BLI_disjoint_set_test.cc
tests/BLI_edgehash_test.cc
tests/BLI_expr_pylike_eval_test.cc
tests/BLI_fileops_test.cc
tests/BLI_function_ref_test.cc
+ tests/BLI_generic_array_test.cc
+ tests/BLI_generic_span_test.cc
+ tests/BLI_generic_vector_array_test.cc
tests/BLI_ghash_test.cc
tests/BLI_hash_mm2a_test.cc
tests/BLI_heap_simple_test.cc
diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c
index 9f1f8fe0448..76fc5b6342a 100644
--- a/source/blender/blenlib/intern/BLI_filelist.c
+++ b/source/blender/blenlib/intern/BLI_filelist.c
@@ -97,8 +97,8 @@ static int bli_compare(struct direntry *entry1, struct direntry *entry2)
}
struct BuildDirCtx {
- struct direntry *files; /* array[nrfiles] */
- int nrfiles;
+ struct direntry *files; /* array[files_num] */
+ int files_num;
};
/**
@@ -154,7 +154,7 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
if (newnum) {
if (dir_ctx->files) {
void *const tmp = MEM_reallocN(dir_ctx->files,
- (dir_ctx->nrfiles + newnum) * sizeof(struct direntry));
+ (dir_ctx->files_num + newnum) * sizeof(struct direntry));
if (tmp) {
dir_ctx->files = (struct direntry *)tmp;
}
@@ -171,7 +171,7 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
if (dir_ctx->files) {
struct dirlink *dlink = (struct dirlink *)dirbase.first;
- struct direntry *file = &dir_ctx->files[dir_ctx->nrfiles];
+ struct direntry *file = &dir_ctx->files[dir_ctx->files_num];
while (dlink) {
char fullname[PATH_MAX];
memset(file, 0, sizeof(struct direntry));
@@ -186,7 +186,7 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
* does not support stat on '\\SERVER\foo\..', sigh... */
file->type |= S_IFDIR;
}
- dir_ctx->nrfiles++;
+ dir_ctx->files_num++;
file++;
dlink = dlink->next;
}
@@ -199,7 +199,7 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
BLI_freelist(&dirbase);
if (dir_ctx->files) {
qsort(dir_ctx->files,
- dir_ctx->nrfiles,
+ dir_ctx->files_num,
sizeof(struct direntry),
(int (*)(const void *, const void *))bli_compare);
}
@@ -219,7 +219,7 @@ unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_
{
struct BuildDirCtx dir_ctx;
- dir_ctx.nrfiles = 0;
+ dir_ctx.files_num = 0;
dir_ctx.files = NULL;
bli_builddir(&dir_ctx, dirname);
@@ -233,7 +233,7 @@ unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_
*r_filelist = MEM_mallocN(sizeof(**r_filelist), __func__);
}
- return dir_ctx.nrfiles;
+ return dir_ctx.files_num;
}
void BLI_filelist_entry_size_to_string(const struct stat *st,
diff --git a/source/blender/blenlib/intern/cpp_type.cc b/source/blender/blenlib/intern/cpp_type.cc
new file mode 100644
index 00000000000..d6a087cf175
--- /dev/null
+++ b/source/blender/blenlib/intern/cpp_type.cc
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BLI_color.hh"
+#include "BLI_cpp_type_make.hh"
+#include "BLI_float4x4.hh"
+#include "BLI_math_vec_types.hh"
+
+BLI_CPP_TYPE_MAKE(bool, bool, CPPTypeFlags::BasicType)
+
+BLI_CPP_TYPE_MAKE(float, float, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(float2, blender::float2, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(float3, blender::float3, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(float4x4, blender::float4x4, CPPTypeFlags::BasicType)
+
+BLI_CPP_TYPE_MAKE(int8, int8_t, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(int16, int16_t, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(int32, int32_t, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(int64, int64_t, CPPTypeFlags::BasicType)
+
+BLI_CPP_TYPE_MAKE(uint8, uint8_t, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(uint16, uint16_t, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(uint32, uint32_t, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(uint64, uint64_t, CPPTypeFlags::BasicType)
+
+BLI_CPP_TYPE_MAKE(ColorGeometry4f, blender::ColorGeometry4f, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(ColorGeometry4b, blender::ColorGeometry4b, CPPTypeFlags::BasicType)
+
+BLI_CPP_TYPE_MAKE(string, std::string, CPPTypeFlags::BasicType)
diff --git a/source/blender/blenlib/intern/delaunay_2d.cc b/source/blender/blenlib/intern/delaunay_2d.cc
index b7dbd7d679c..e6164c98402 100644
--- a/source/blender/blenlib/intern/delaunay_2d.cc
+++ b/source/blender/blenlib/intern/delaunay_2d.cc
@@ -423,7 +423,7 @@ template<typename T> std::ostream &operator<<(std::ostream &os, const CDT_state<
os << " merge to " << vertname(cdt_state.cdt.verts[v->merge_to_index]) << "\n";
}
const SymEdge<T> *se = v->symedge;
- int cnt = 0;
+ int count = 0;
constexpr int print_count_limit = 25;
if (se) {
os << " edges out:\n";
@@ -440,8 +440,8 @@ template<typename T> std::ostream &operator<<(std::ostream &os, const CDT_state<
os << " " << vertname(vother) << "(e=" << trunc_ptr(se->edge)
<< ", se=" << trunc_ptr(se) << ")\n";
se = se->rot;
- cnt++;
- } while (se != v->symedge && cnt < print_count_limit);
+ count++;
+ } while (se != v->symedge && count < print_count_limit);
os << "\n";
}
}
@@ -2202,7 +2202,6 @@ void add_face_constraints(CDT_state<T> *cdt_state,
{
int nv = input.vert.size();
int nf = input.face.size();
- int fstart = 0;
SymEdge<T> *face_symedge0 = nullptr;
CDTArrangement<T> *cdt = &cdt_state->cdt;
int maxflen = 0;
@@ -2221,7 +2220,6 @@ void add_face_constraints(CDT_state<T> *cdt_state,
int flen = input.face[f].size();
if (flen <= 2) {
/* Ignore faces with fewer than 3 vertices. */
- fstart += flen;
continue;
}
int fedge_start = (f + 1) * cdt_state->face_edge_offset;
@@ -2266,7 +2264,6 @@ void add_face_constraints(CDT_state<T> *cdt_state,
add_face_ids(cdt_state, face_symedge0, f, fedge_start, fedge_end);
}
}
- fstart += flen;
}
}
diff --git a/source/blender/blenlib/intern/expr_pylike_eval.c b/source/blender/blenlib/intern/expr_pylike_eval.c
index db677cd304c..1c32336fee0 100644
--- a/source/blender/blenlib/intern/expr_pylike_eval.c
+++ b/source/blender/blenlib/intern/expr_pylike_eval.c
@@ -829,18 +829,18 @@ static bool parse_unary(ExprParseState *state)
/* Specially supported functions. */
if (STREQ(state->tokenbuf, "min")) {
- int cnt = parse_function_args(state);
- CHECK_ERROR(cnt > 0);
+ int count = parse_function_args(state);
+ CHECK_ERROR(count > 0);
- parse_add_op(state, OPCODE_MIN, 1 - cnt)->arg.ival = cnt;
+ parse_add_op(state, OPCODE_MIN, 1 - count)->arg.ival = count;
return true;
}
if (STREQ(state->tokenbuf, "max")) {
- int cnt = parse_function_args(state);
- CHECK_ERROR(cnt > 0);
+ int count = parse_function_args(state);
+ CHECK_ERROR(count > 0);
- parse_add_op(state, OPCODE_MAX, 1 - cnt)->arg.ival = cnt;
+ parse_add_op(state, OPCODE_MAX, 1 - count)->arg.ival = count;
return true;
}
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index 27f8f1d4bc8..26a0479f445 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -382,9 +382,9 @@ static bool delete_recursive(const char *dir)
{
struct direntry *filelist, *fl;
bool err = false;
- uint nbr, i;
+ uint filelist_num, i;
- i = nbr = BLI_filelist_dir_contents(dir, &filelist);
+ i = filelist_num = BLI_filelist_dir_contents(dir, &filelist);
fl = filelist;
while (i--) {
const char *file = BLI_path_basename(fl->path);
@@ -415,7 +415,7 @@ static bool delete_recursive(const char *dir)
err = true;
}
- BLI_filelist_free(filelist, nbr);
+ BLI_filelist_free(filelist, filelist_num);
return err;
}
diff --git a/source/blender/functions/intern/generic_vector_array.cc b/source/blender/blenlib/intern/generic_vector_array.cc
index b188b31b087..b32236bfada 100644
--- a/source/blender/functions/intern/generic_vector_array.cc
+++ b/source/blender/blenlib/intern/generic_vector_array.cc
@@ -1,10 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "FN_generic_vector_array.hh"
-#include "FN_multi_function_params.hh"
-#include "FN_multi_function_signature.hh"
+#include "BLI_generic_vector_array.hh"
-namespace blender::fn {
+namespace blender {
GVectorArray::GVectorArray(const CPPType &type, const int64_t array_size)
: type_(type), element_size_(type.size()), items_(array_size)
@@ -95,4 +93,4 @@ void GVectorArray::realloc_to_at_least(Item &item, int64_t min_capacity)
item.capacity = new_capacity;
}
-} // namespace blender::fn
+} // namespace blender
diff --git a/source/blender/functions/intern/generic_virtual_array.cc b/source/blender/blenlib/intern/generic_virtual_array.cc
index 4644323bd1f..8a6ef8e792f 100644
--- a/source/blender/functions/intern/generic_virtual_array.cc
+++ b/source/blender/blenlib/intern/generic_virtual_array.cc
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "FN_generic_virtual_array.hh"
+#include "BLI_generic_virtual_array.hh"
-namespace blender::fn {
+namespace blender {
/* -------------------------------------------------------------------- */
/** \name #GVArrayImpl
@@ -391,10 +391,7 @@ void GVMutableArray_GSpan::save()
if (data_ != owned_data_) {
return;
}
- const int64_t element_size = type_->size();
- for (int64_t i : IndexRange(size_)) {
- varray_.set_by_copy(i, POINTER_OFFSET(owned_data_, element_size * i));
- }
+ varray_.set_all(owned_data_);
}
void GVMutableArray_GSpan::disable_not_applied_warning()
@@ -721,4 +718,4 @@ GMutableSpan GVMutableArray::get_internal_span() const
/** \} */
-} // namespace blender::fn
+} // namespace blender
diff --git a/source/blender/functions/intern/generic_virtual_vector_array.cc b/source/blender/blenlib/intern/generic_virtual_vector_array.cc
index 7dc728a4460..8fd1fb50b72 100644
--- a/source/blender/functions/intern/generic_virtual_vector_array.cc
+++ b/source/blender/blenlib/intern/generic_virtual_vector_array.cc
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "FN_generic_virtual_vector_array.hh"
+#include "BLI_generic_virtual_vector_array.hh"
-namespace blender::fn {
+namespace blender {
void GVArray_For_GVVectorArrayIndex::get(const int64_t index_in_vector, void *r_value) const
{
@@ -50,4 +50,4 @@ bool GVVectorArray_For_SingleGSpan::is_single_vector_impl() const
return true;
}
-} // namespace blender::fn
+} // namespace blender
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index bc3ed099fd5..e1ec22063e0 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -294,46 +294,48 @@ 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));
}
-void closest_to_line_segment_v2(float r_close[2],
- const float p[2],
- const float l1[2],
- const float l2[2])
+float closest_to_line_segment_v2(float r_close[2],
+ const float p[2],
+ const float l1[2],
+ const float l2[2])
{
float lambda, cp[2];
lambda = closest_to_line_v2(cp, p, l1, l2);
/* flip checks for !finite case (when segment is a point) */
- if (!(lambda > 0.0f)) {
+ if (lambda <= 0.0f) {
copy_v2_v2(r_close, l1);
+ return 0.0f;
}
- else if (!(lambda < 1.0f)) {
+ if (lambda >= 1.0f) {
copy_v2_v2(r_close, l2);
+ return 1.0f;
}
- else {
- copy_v2_v2(r_close, cp);
- }
+ copy_v2_v2(r_close, cp);
+ return lambda;
}
-void closest_to_line_segment_v3(float r_close[3],
- const float p[3],
- const float l1[3],
- const float l2[3])
+float closest_to_line_segment_v3(float r_close[3],
+ const float p[3],
+ const float l1[3],
+ const float l2[3])
{
float lambda, cp[3];
lambda = closest_to_line_v3(cp, p, l1, l2);
/* flip checks for !finite case (when segment is a point) */
- if (!(lambda > 0.0f)) {
+ if (lambda <= 0.0f) {
copy_v3_v3(r_close, l1);
+ return 0.0f;
}
- else if (!(lambda < 1.0f)) {
+ if (lambda >= 1.0f) {
copy_v3_v3(r_close, l2);
+ return 1.0f;
}
- else {
- copy_v3_v3(r_close, cp);
- }
+ copy_v3_v3(r_close, cp);
+ return lambda;
}
void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3])
diff --git a/source/blender/blenlib/intern/math_statistics.c b/source/blender/blenlib/intern/math_statistics.c
index 14baca891c0..53fbc16f3fc 100644
--- a/source/blender/blenlib/intern/math_statistics.c
+++ b/source/blender/blenlib/intern/math_statistics.c
@@ -21,7 +21,7 @@ typedef struct CovarianceData {
float *r_covmat;
float covfac;
int n;
- int nbr_cos_vn;
+ int cos_vn_num;
} CovarianceData;
static void covariance_m_vn_ex_task_cb(void *__restrict userdata,
@@ -33,7 +33,7 @@ static void covariance_m_vn_ex_task_cb(void *__restrict userdata,
const float *center = data->center;
float *r_covmat = data->r_covmat;
const int n = data->n;
- const int nbr_cos_vn = data->nbr_cos_vn;
+ const int cos_vn_num = data->cos_vn_num;
int k;
@@ -55,12 +55,12 @@ static void covariance_m_vn_ex_task_cb(void *__restrict userdata,
}
if (center) {
- for (k = 0; k < nbr_cos_vn; k++) {
+ for (k = 0; k < cos_vn_num; k++) {
r_covmat[a] += (cos_vn[k * n + i] - center[i]) * (cos_vn[k * n + j] - center[j]);
}
}
else {
- for (k = 0; k < nbr_cos_vn; k++) {
+ for (k = 0; k < cos_vn_num; k++) {
r_covmat[a] += cos_vn[k * n + i] * cos_vn[k * n + j];
}
}
@@ -73,7 +73,7 @@ static void covariance_m_vn_ex_task_cb(void *__restrict userdata,
void BLI_covariance_m_vn_ex(const int n,
const float *cos_vn,
- const int nbr_cos_vn,
+ const int cos_vn_num,
const float *center,
const bool use_sample_correction,
float *r_covmat)
@@ -81,7 +81,7 @@ void BLI_covariance_m_vn_ex(const int n,
/* Note about that division: see https://en.wikipedia.org/wiki/Bessel%27s_correction.
* In a nutshell, it must be 1 / (n - 1) for 'sample data', and 1 / n for 'population data'...
*/
- const float covfac = 1.0f / (float)(use_sample_correction ? nbr_cos_vn - 1 : nbr_cos_vn);
+ const float covfac = 1.0f / (float)(use_sample_correction ? cos_vn_num - 1 : cos_vn_num);
memset(r_covmat, 0, sizeof(*r_covmat) * (size_t)(n * n));
@@ -91,27 +91,27 @@ void BLI_covariance_m_vn_ex(const int n,
.r_covmat = r_covmat,
.covfac = covfac,
.n = n,
- .nbr_cos_vn = nbr_cos_vn,
+ .cos_vn_num = cos_vn_num,
};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((nbr_cos_vn * n * n) >= 10000);
+ settings.use_threading = ((cos_vn_num * n * n) >= 10000);
BLI_task_parallel_range(0, n * n, &data, covariance_m_vn_ex_task_cb, &settings);
}
void BLI_covariance_m3_v3n(const float (*cos_v3)[3],
- const int nbr_cos_v3,
+ const int cos_v3_num,
const bool use_sample_correction,
float r_covmat[3][3],
float r_center[3])
{
float center[3];
- const float mean_fac = 1.0f / (float)nbr_cos_v3;
+ const float mean_fac = 1.0f / (float)cos_v3_num;
int i;
zero_v3(center);
- for (i = 0; i < nbr_cos_v3; i++) {
+ for (i = 0; i < cos_v3_num; i++) {
/* Applying mean_fac here rather than once at the end reduce compute errors... */
madd_v3_v3fl(center, cos_v3[i], mean_fac);
}
@@ -121,5 +121,5 @@ void BLI_covariance_m3_v3n(const float (*cos_v3)[3],
}
BLI_covariance_m_vn_ex(
- 3, (const float *)cos_v3, nbr_cos_v3, center, use_sample_correction, (float *)r_covmat);
+ 3, (const float *)cos_v3, cos_v3_num, center, use_sample_correction, (float *)r_covmat);
}
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index da6a6dff16f..5dcdabaf760 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -268,12 +268,12 @@ void mid_v3_v3v3v3v3(
v[2] = (v1[2] + v2[2] + v3[2] + v4[2]) / 4.0f;
}
-void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const uint nbr)
+void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const uint vec_arr_num)
{
- const float factor = 1.0f / (float)nbr;
+ const float factor = 1.0f / (float)vec_arr_num;
zero_v3(r);
- for (uint i = 0; i < nbr; i++) {
+ for (uint i = 0; i < vec_arr_num; i++) {
madd_v3_v3fl(r, vec_arr[i], factor);
}
}
@@ -904,9 +904,12 @@ 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)
+void minmax_v3v3_v3_array(float r_min[3],
+ float r_max[3],
+ const float (*vec_arr)[3],
+ int var_arr_num)
{
- while (nbr--) {
+ while (var_arr_num--) {
minmax_v3v3_v3(r_min, r_max, *vec_arr++);
}
}
diff --git a/source/blender/blenlib/intern/mesh_intersect.cc b/source/blender/blenlib/intern/mesh_intersect.cc
index 8f2c86556aa..96ae0750899 100644
--- a/source/blender/blenlib/intern/mesh_intersect.cc
+++ b/source/blender/blenlib/intern/mesh_intersect.cc
@@ -26,6 +26,7 @@
# include "BLI_math_vector.h"
# include "BLI_polyfill_2d.h"
# include "BLI_set.hh"
+# include "BLI_sort.hh"
# include "BLI_span.hh"
# include "BLI_task.h"
# include "BLI_task.hh"
@@ -37,10 +38,6 @@
# include "BLI_mesh_intersect.hh"
-# ifdef WITH_TBB
-# include <tbb/parallel_sort.h>
-# endif
-
// # define PERFDEBUG
namespace blender::meshintersect {
@@ -672,11 +669,7 @@ void IMesh::populate_vert(int max_verts)
* TODO: when all debugged, set fix_order = false. */
const bool fix_order = true;
if (fix_order) {
-# ifdef WITH_TBB
- tbb::parallel_sort(vert_.begin(), vert_.end(), [](const Vert *a, const Vert *b) {
-# else
- std::sort(vert_.begin(), vert_.end(), [](const Vert *a, const Vert *b) {
-# endif
+ blender::parallel_sort(vert_.begin(), vert_.end(), [](const Vert *a, const Vert *b) {
if (a->orig != NO_INDEX && b->orig != NO_INDEX) {
return a->orig < b->orig;
}
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index f94d49cf1dd..6c576627fa0 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -313,8 +313,8 @@ bool BLI_filename_make_safe(char *fname)
bool BLI_path_make_safe(char *path)
{
- /* Simply apply BLI_filename_make_safe() over each component of the path.
- * Luckily enough, same 'safe' rules applies to filenames and dirnames. */
+ /* Simply apply #BLI_filename_make_safe() over each component of the path.
+ * Luckily enough, same 'safe' rules applies to file & directory names. */
char *curr_slash, *curr_path = path;
bool changed = false;
bool skip_first = false;
diff --git a/source/blender/blenlib/intern/rand.cc b/source/blender/blenlib/intern/rand.cc
index 27774cad31b..17bf5585f3f 100644
--- a/source/blender/blenlib/intern/rand.cc
+++ b/source/blender/blenlib/intern/rand.cc
@@ -374,6 +374,15 @@ void RandomNumberGenerator::seed_random(uint32_t seed)
this->seed(seed + hash[seed & 255]);
}
+int RandomNumberGenerator::round_probabilistic(float x)
+{
+ /* Support for negative values can be added when necessary. */
+ BLI_assert(x >= 0.0f);
+ const float round_up_probability = fractf(x);
+ const bool round_up = round_up_probability > this->get_float();
+ return (int)x + (int)round_up;
+}
+
float2 RandomNumberGenerator::get_unit_float2()
{
float a = (float)(M_PI * 2.0) * this->get_float();
diff --git a/source/blender/blenlib/intern/timeit.cc b/source/blender/blenlib/intern/timeit.cc
index 2dcfe2e6ab1..f11f9c4ad94 100644
--- a/source/blender/blenlib/intern/timeit.cc
+++ b/source/blender/blenlib/intern/timeit.cc
@@ -2,6 +2,8 @@
#include "BLI_timeit.hh"
+#include <algorithm>
+
namespace blender::timeit {
void print_duration(Nanoseconds duration)
@@ -17,4 +19,20 @@ void print_duration(Nanoseconds duration)
}
}
+ScopedTimerAveraged::~ScopedTimerAveraged()
+{
+ const TimePoint end = Clock::now();
+ const Nanoseconds duration = end - start_;
+
+ total_count_++;
+ total_time_ += duration;
+ min_time_ = std::min(duration, min_time_);
+
+ std::cout << "Timer '" << name_ << "': (Average: ";
+ print_duration(total_time_ / total_count_);
+ std::cout << ", Min: ";
+ print_duration(min_time_);
+ std::cout << ")\n";
+}
+
} // namespace blender::timeit
diff --git a/source/blender/functions/tests/FN_cpp_type_test.cc b/source/blender/blenlib/tests/BLI_cpp_type_test.cc
index 6d9310874f5..94456e1ee28 100644
--- a/source/blender/functions/tests/FN_cpp_type_test.cc
+++ b/source/blender/blenlib/tests/BLI_cpp_type_test.cc
@@ -2,10 +2,10 @@
#include "testing/testing.h"
-#include "FN_cpp_type.hh"
-#include "FN_cpp_type_make.hh"
+#include "BLI_cpp_type.hh"
+#include "BLI_cpp_type_make.hh"
-namespace blender::fn::tests {
+namespace blender::tests {
static const int default_constructed_value = 1;
static const int copy_constructed_value = 2;
@@ -74,11 +74,11 @@ struct TestType {
}
};
-} // namespace blender::fn::tests
+} // namespace blender::tests
-MAKE_CPP_TYPE(TestType, blender::fn::tests::TestType, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(TestType, blender::tests::TestType, CPPTypeFlags::BasicType)
-namespace blender::fn::tests {
+namespace blender::tests {
static const CPPType &CPPType_TestType = CPPType::get<TestType>();
@@ -323,4 +323,28 @@ TEST(cpp_type, DebugPrint)
EXPECT_EQ(text, "42");
}
-} // namespace blender::fn::tests
+TEST(cpp_type, ToStaticType)
+{
+ Vector<const CPPType *> types;
+ bool found_unsupported_type = false;
+ auto fn = [&](auto type_tag) {
+ using T = typename decltype(type_tag)::type;
+ if constexpr (!std::is_same_v<T, void>) {
+ types.append(&CPPType::get<T>());
+ }
+ else {
+ found_unsupported_type = true;
+ }
+ };
+ CPPType::get<std::string>().to_static_type_tag<int, float, std::string>(fn);
+ CPPType::get<float>().to_static_type_tag<int, float, std::string>(fn);
+ EXPECT_FALSE(found_unsupported_type);
+ CPPType::get<int64_t>().to_static_type_tag<int, float, std::string>(fn);
+ EXPECT_TRUE(found_unsupported_type);
+
+ EXPECT_EQ(types.size(), 2);
+ EXPECT_EQ(types[0], &CPPType::get<std::string>());
+ EXPECT_EQ(types[1], &CPPType::get<float>());
+}
+
+} // namespace blender::tests
diff --git a/source/blender/functions/tests/FN_generic_array_test.cc b/source/blender/blenlib/tests/BLI_generic_array_test.cc
index 5420a809ffc..52bc7728a6a 100644
--- a/source/blender/functions/tests/FN_generic_array_test.cc
+++ b/source/blender/blenlib/tests/BLI_generic_array_test.cc
@@ -5,10 +5,9 @@
#include "MEM_guardedalloc.h"
#include "BLI_array.hh"
+#include "BLI_generic_array.hh"
-#include "FN_generic_array.hh"
-
-namespace blender::fn::tests {
+namespace blender::tests {
TEST(generic_array, TypeConstructor)
{
@@ -115,4 +114,4 @@ TEST(generic_array, InContainer)
}
}
-} // namespace blender::fn::tests
+} // namespace blender::tests
diff --git a/source/blender/functions/tests/FN_generic_span_test.cc b/source/blender/blenlib/tests/BLI_generic_span_test.cc
index 19b3ceaf44e..fe07a67d63b 100644
--- a/source/blender/functions/tests/FN_generic_span_test.cc
+++ b/source/blender/blenlib/tests/BLI_generic_span_test.cc
@@ -2,9 +2,9 @@
#include "testing/testing.h"
-#include "FN_generic_span.hh"
+#include "BLI_generic_span.hh"
-namespace blender::fn::tests {
+namespace blender::tests {
TEST(generic_span, TypeConstructor)
{
@@ -50,4 +50,4 @@ TEST(generic_mutable_span, BufferAndSizeConstructor)
EXPECT_EQ(values[2], 20);
}
-} // namespace blender::fn::tests
+} // namespace blender::tests
diff --git a/source/blender/functions/tests/FN_generic_vector_array_test.cc b/source/blender/blenlib/tests/BLI_generic_vector_array_test.cc
index 6a83e6094b4..105f3603914 100644
--- a/source/blender/functions/tests/FN_generic_vector_array_test.cc
+++ b/source/blender/blenlib/tests/BLI_generic_vector_array_test.cc
@@ -2,9 +2,9 @@
#include "testing/testing.h"
-#include "FN_generic_vector_array.hh"
+#include "BLI_generic_vector_array.hh"
-namespace blender::fn::tests {
+namespace blender::tests {
TEST(generic_vector_array, Construct)
{
@@ -40,4 +40,4 @@ TEST(generic_vector_array, Extend)
EXPECT_EQ(vector_array[2].size(), 0);
}
-} // namespace blender::fn::tests
+} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_math_vector_test.cc b/source/blender/blenlib/tests/BLI_math_vector_test.cc
index 35a111f04db..8c310645d6d 100644
--- a/source/blender/blenlib/tests/BLI_math_vector_test.cc
+++ b/source/blender/blenlib/tests/BLI_math_vector_test.cc
@@ -85,4 +85,4 @@ TEST(math_vector, Clamp)
EXPECT_EQ(result_2.z, -50);
}
-} // namespace blender::tests \ No newline at end of file
+} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
index 95cf0f17d2e..fabc2412828 100644
--- a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
+++ b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc
@@ -39,11 +39,13 @@ class IMeshBuilder {
return std::pair<int, int>(e_index / MAX_FACE_LEN, e_index % MAX_FACE_LEN);
}
- /*
+ /**
* Spec should have form:
- * #verts #faces
- * mpq_class mpq_class mpq_clas [#verts lines]
- * int int int ... [#faces lines; indices into verts for given face]
+ * <pre>
+ * #verts #faces
+ * mpq_class mpq_class mpq_clas [#verts lines]
+ * int int int ... [#faces lines; indices into verts for given face]
+ * </pre>
*/
IMeshBuilder(const char *spec)
{
diff --git a/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc b/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc
index 4ddf656ff2e..d6a7a338d13 100644
--- a/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc
+++ b/source/blender/blenlib/tests/BLI_mesh_intersect_test.cc
@@ -42,11 +42,13 @@ class IMeshBuilder {
return std::pair<int, int>(e_index / MAX_FACE_LEN, e_index % MAX_FACE_LEN);
}
- /*
+ /**
* Spec should have form:
- * #verts #faces
- * mpq_class mpq_class mpq_clas [#verts lines]
- * int int int ... [#faces lines; indices into verts for given face]
+ * <pre>
+ * #verts #faces
+ * mpq_class mpq_class mpq_clas [#verts lines]
+ * int int int ... [#faces lines; indices into verts for given face]
+ * </pre>
*/
IMeshBuilder(const char *spec)
{
diff --git a/source/blender/blenlib/tests/performance/BLI_ghash_performance_test.cc b/source/blender/blenlib/tests/performance/BLI_ghash_performance_test.cc
index eae90f130cd..0ff488202c2 100644
--- a/source/blender/blenlib/tests/performance/BLI_ghash_performance_test.cc
+++ b/source/blender/blenlib/tests/performance/BLI_ghash_performance_test.cc
@@ -177,17 +177,17 @@ TEST(ghash, TextMurmur2a)
/* Int: uniform 100M first integers. */
-static void int_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr)
+static void int_ghash_tests(GHash *ghash, const char *id, const unsigned int count)
{
printf("\n========== STARTING %s ==========\n", id);
{
- unsigned int i = nbr;
+ unsigned int i = count;
TIMEIT_START(int_insert);
#ifdef GHASH_RESERVE
- BLI_ghash_reserve(ghash, nbr);
+ BLI_ghash_reserve(ghash, count);
#endif
while (i--) {
@@ -200,7 +200,7 @@ static void int_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr
PRINTF_GHASH_STATS(ghash);
{
- unsigned int i = nbr;
+ unsigned int i = count;
TIMEIT_START(int_lookup);
@@ -266,17 +266,17 @@ TEST(ghash, IntMurmur2a100000000)
/* Int: random 50M integers. */
-static void randint_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr)
+static void randint_ghash_tests(GHash *ghash, const char *id, const unsigned int count)
{
printf("\n========== STARTING %s ==========\n", id);
- unsigned int *data = (unsigned int *)MEM_mallocN(sizeof(*data) * (size_t)nbr, __func__);
+ unsigned int *data = (unsigned int *)MEM_mallocN(sizeof(*data) * (size_t)count, __func__);
unsigned int *dt;
unsigned int i;
{
RNG *rng = BLI_rng_new(1);
- for (i = nbr, dt = data; i--; dt++) {
+ for (i = count, dt = data; i--; dt++) {
*dt = BLI_rng_get_uint(rng);
}
BLI_rng_free(rng);
@@ -286,10 +286,10 @@ static void randint_ghash_tests(GHash *ghash, const char *id, const unsigned int
TIMEIT_START(int_insert);
#ifdef GHASH_RESERVE
- BLI_ghash_reserve(ghash, nbr);
+ BLI_ghash_reserve(ghash, count);
#endif
- for (i = nbr, dt = data; i--; dt++) {
+ for (i = count, dt = data; i--; dt++) {
BLI_ghash_insert(ghash, POINTER_FROM_UINT(*dt), POINTER_FROM_UINT(*dt));
}
@@ -301,7 +301,7 @@ static void randint_ghash_tests(GHash *ghash, const char *id, const unsigned int
{
TIMEIT_START(int_lookup);
- for (i = nbr, dt = data; i--; dt++) {
+ for (i = count, dt = data; i--; dt++) {
void *v = BLI_ghash_lookup(ghash, POINTER_FROM_UINT(*dt));
EXPECT_EQ(POINTER_AS_UINT(v), *dt);
}
@@ -375,18 +375,18 @@ TEST(ghash, Int4NoHash50000000)
/* Int_v4: 20M of randomly-generated integer vectors. */
-static void int4_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr)
+static void int4_ghash_tests(GHash *ghash, const char *id, const unsigned int count)
{
printf("\n========== STARTING %s ==========\n", id);
- void *data_v = MEM_mallocN(sizeof(unsigned int[4]) * (size_t)nbr, __func__);
+ void *data_v = MEM_mallocN(sizeof(unsigned int[4]) * (size_t)count, __func__);
unsigned int(*data)[4] = (unsigned int(*)[4])data_v;
unsigned int(*dt)[4];
unsigned int i, j;
{
RNG *rng = BLI_rng_new(1);
- for (i = nbr, dt = data; i--; dt++) {
+ for (i = count, dt = data; i--; dt++) {
for (j = 4; j--;) {
(*dt)[j] = BLI_rng_get_uint(rng);
}
@@ -398,10 +398,10 @@ static void int4_ghash_tests(GHash *ghash, const char *id, const unsigned int nb
TIMEIT_START(int_v4_insert);
#ifdef GHASH_RESERVE
- BLI_ghash_reserve(ghash, nbr);
+ BLI_ghash_reserve(ghash, count);
#endif
- for (i = nbr, dt = data; i--; dt++) {
+ for (i = count, dt = data; i--; dt++) {
BLI_ghash_insert(ghash, *dt, POINTER_FROM_UINT(i));
}
@@ -413,7 +413,7 @@ static void int4_ghash_tests(GHash *ghash, const char *id, const unsigned int nb
{
TIMEIT_START(int_v4_lookup);
- for (i = nbr, dt = data; i--; dt++) {
+ for (i = count, dt = data; i--; dt++) {
void *v = BLI_ghash_lookup(ghash, (void *)(*dt));
EXPECT_EQ(POINTER_AS_UINT(v), i);
}
@@ -483,25 +483,25 @@ TEST(ghash, Int2NoHash50000000)
/* MultiSmall: create and manipulate a lot of very small ghash's
* (90% < 10 items, 9% < 100 items, 1% < 1000 items). */
-static void multi_small_ghash_tests_one(GHash *ghash, RNG *rng, const unsigned int nbr)
+static void multi_small_ghash_tests_one(GHash *ghash, RNG *rng, const unsigned int count)
{
- unsigned int *data = (unsigned int *)MEM_mallocN(sizeof(*data) * (size_t)nbr, __func__);
+ unsigned int *data = (unsigned int *)MEM_mallocN(sizeof(*data) * (size_t)count, __func__);
unsigned int *dt;
unsigned int i;
- for (i = nbr, dt = data; i--; dt++) {
+ for (i = count, dt = data; i--; dt++) {
*dt = BLI_rng_get_uint(rng);
}
#ifdef GHASH_RESERVE
- BLI_ghash_reserve(ghash, nbr);
+ BLI_ghash_reserve(ghash, count);
#endif
- for (i = nbr, dt = data; i--; dt++) {
+ for (i = count, dt = data; i--; dt++) {
BLI_ghash_insert(ghash, POINTER_FROM_UINT(*dt), POINTER_FROM_UINT(*dt));
}
- for (i = nbr, dt = data; i--; dt++) {
+ for (i = count, dt = data; i--; dt++) {
void *v = BLI_ghash_lookup(ghash, POINTER_FROM_UINT(*dt));
EXPECT_EQ(POINTER_AS_UINT(v), *dt);
}
@@ -510,7 +510,7 @@ static void multi_small_ghash_tests_one(GHash *ghash, RNG *rng, const unsigned i
MEM_freeN(data);
}
-static void multi_small_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr)
+static void multi_small_ghash_tests(GHash *ghash, const char *id, const unsigned int count)
{
printf("\n========== STARTING %s ==========\n", id);
@@ -518,22 +518,22 @@ static void multi_small_ghash_tests(GHash *ghash, const char *id, const unsigned
TIMEIT_START(multi_small_ghash);
- unsigned int i = nbr;
+ unsigned int i = count;
while (i--) {
- const int nbr = 1 + (BLI_rng_get_int(rng) % TESTCASE_SIZE_SMALL) *
- (!(i % 100) ? 100 : (!(i % 10) ? 10 : 1));
- multi_small_ghash_tests_one(ghash, rng, nbr);
+ const int count = 1 + (BLI_rng_get_int(rng) % TESTCASE_SIZE_SMALL) *
+ (!(i % 100) ? 100 : (!(i % 10) ? 10 : 1));
+ multi_small_ghash_tests_one(ghash, rng, count);
}
TIMEIT_END(multi_small_ghash);
TIMEIT_START(multi_small2_ghash);
- unsigned int i = nbr;
+ unsigned int i = count;
while (i--) {
- const int nbr = 1 + (BLI_rng_get_int(rng) % TESTCASE_SIZE_SMALL) / 2 *
- (!(i % 100) ? 100 : (!(i % 10) ? 10 : 1));
- multi_small_ghash_tests_one(ghash, rng, nbr);
+ const int count = 1 + (BLI_rng_get_int(rng) % TESTCASE_SIZE_SMALL) / 2 *
+ (!(i % 100) ? 100 : (!(i % 10) ? 10 : 1));
+ multi_small_ghash_tests_one(ghash, rng, count);
}
TIMEIT_END(multi_small2_ghash);
diff --git a/source/blender/blenlib/tests/performance/BLI_task_performance_test.cc b/source/blender/blenlib/tests/performance/BLI_task_performance_test.cc
index 33a196569e9..98fafe55d69 100644
--- a/source/blender/blenlib/tests/performance/BLI_task_performance_test.cc
+++ b/source/blender/blenlib/tests/performance/BLI_task_performance_test.cc
@@ -135,17 +135,17 @@ static void task_listbase_test_do(ListBase *list,
NUM_RUN_AVERAGED);
}
-static void task_listbase_test(const char *id, const int nbr, const bool use_threads)
+static void task_listbase_test(const char *id, const int count, const bool use_threads)
{
printf("\n========== STARTING %s ==========\n", id);
ListBase list = {nullptr, nullptr};
- LinkData *items_buffer = (LinkData *)MEM_calloc_arrayN(nbr, sizeof(*items_buffer), __func__);
+ LinkData *items_buffer = (LinkData *)MEM_calloc_arrayN(count, sizeof(*items_buffer), __func__);
BLI_threadapi_init();
int num_items = 0;
- for (int i = 0; i < nbr; i++) {
+ for (int i = 0; i < count; i++) {
BLI_addtail(&list, &items_buffer[i]);
num_items++;
}
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index 3ae26dea767..2f6f0d5c9fa 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -1510,27 +1510,6 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 292, 9)) {
- FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- if (ntree->type == NTREE_GEOMETRY) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == GEO_NODE_LEGACY_ATTRIBUTE_MATH && node->storage == NULL) {
- const int old_use_attibute_a = (1 << 0);
- const int old_use_attibute_b = (1 << 1);
- NodeAttributeMath *data = MEM_callocN(sizeof(NodeAttributeMath), "NodeAttributeMath");
- data->operation = NODE_MATH_ADD;
- data->input_type_a = (node->custom2 & old_use_attibute_a) ?
- GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE :
- GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
- data->input_type_b = (node->custom2 & old_use_attibute_b) ?
- GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE :
- GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
- node->storage = data;
- }
- }
- }
- }
- FOREACH_NODETREE_END;
-
/* Default properties editors to auto outliner sync. */
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
@@ -1668,39 +1647,6 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- if (!MAIN_VERSION_ATLEAST(bmain, 293, 3)) {
- FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- if (ntree->type != NTREE_GEOMETRY) {
- continue;
- }
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == GEO_NODE_LEGACY_POINT_INSTANCE && node->storage == NULL) {
- NodeGeometryPointInstance *data = (NodeGeometryPointInstance *)MEM_callocN(
- sizeof(NodeGeometryPointInstance), __func__);
- data->instance_type = node->custom1;
- data->flag = (node->custom2 ? 0 : GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION);
- node->storage = data;
- }
- }
- }
- FOREACH_NODETREE_END;
- }
-
- if (!MAIN_VERSION_ATLEAST(bmain, 293, 4)) {
- /* Add support for all operations to the "Attribute Math" node. */
- FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- if (ntree->type == NTREE_GEOMETRY) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == GEO_NODE_LEGACY_ATTRIBUTE_MATH) {
- NodeAttributeMath *data = (NodeAttributeMath *)node->storage;
- data->input_type_c = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
- }
- }
- }
- }
- FOREACH_NODETREE_END;
- }
-
if (!MAIN_VERSION_ATLEAST(bmain, 293, 5)) {
/* Change Nishita sky model Altitude unit. */
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
@@ -1744,24 +1690,6 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
FOREACH_NODETREE_END;
}
- if (!MAIN_VERSION_ATLEAST(bmain, 293, 8)) {
- FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- if (ntree->type != NTREE_GEOMETRY) {
- continue;
- }
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE && node->storage == NULL) {
- NodeAttributeRandomize *data = (NodeAttributeRandomize *)MEM_callocN(
- sizeof(NodeAttributeRandomize), __func__);
- data->data_type = node->custom1;
- data->operation = GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE;
- node->storage = data;
- }
- }
- }
- FOREACH_NODETREE_END;
- }
-
if (!MAIN_VERSION_ATLEAST(bmain, 293, 9)) {
if (!DNA_struct_elem_find(fd->filesdna, "SceneEEVEE", "float", "bokeh_overblur")) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
@@ -1783,24 +1711,9 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
-
- FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- if (ntree->type == NTREE_GEOMETRY) {
- version_node_socket_name(ntree, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Result", "Distance");
- }
- }
- FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_ATLEAST(bmain, 293, 10)) {
- FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- if (ntree->type == NTREE_GEOMETRY) {
- version_node_socket_name(
- ntree, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Location", "Position");
- }
- }
- FOREACH_NODETREE_END;
-
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
/* Fix old scene with too many samples that were not being used.
* Now they are properly used and might produce a huge slowdown.
@@ -1886,16 +1799,6 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
light->volume_fac = 1.0f;
}
}
-
- LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
- if (ntree->type == NTREE_GEOMETRY) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == GEO_NODE_LEGACY_ATTRIBUTE_FILL) {
- node->custom2 = ATTR_DOMAIN_AUTO;
- }
- }
- }
- }
}
if (!MAIN_VERSION_ATLEAST(bmain, 293, 15)) {
@@ -1940,13 +1843,6 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 293, 18)) {
- FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- if (ntree->type == NTREE_GEOMETRY) {
- version_node_socket_name(ntree, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Grid", "Density");
- }
- }
- FOREACH_NODETREE_END;
-
if (!DNA_struct_elem_find(fd->filesdna, "bArmature", "float", "axes_position")) {
/* Convert the axes draw position to its old default (tip of bone). */
LISTBASE_FOREACH (struct bArmature *, arm, &bmain->armatures) {
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index eead735b305..51b5cab1f7c 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -527,7 +527,6 @@ static void version_geometry_nodes_add_realize_instance_nodes(bNodeTree *ntree)
GEO_NODE_TRIM_CURVE,
GEO_NODE_REPLACE_MATERIAL,
GEO_NODE_SUBDIVIDE_MESH,
- GEO_NODE_LEGACY_ATTRIBUTE_REMOVE,
GEO_NODE_TRIANGULATE)) {
bNodeSocket *geometry_socket = node->inputs.first;
add_realize_instances_before_socket(ntree, node, geometry_socket);
@@ -600,30 +599,6 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 3)) {
- /* Use new texture socket in Attribute Sample Texture node. */
- LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
- if (ntree->type != NTREE_GEOMETRY) {
- continue;
- }
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type != GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE) {
- continue;
- }
- if (node->id == NULL) {
- continue;
- }
- LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- if (socket->type == SOCK_TEXTURE) {
- bNodeSocketValueTexture *socket_value = (bNodeSocketValueTexture *)
- socket->default_value;
- socket_value->value = (Tex *)node->id;
- break;
- }
- }
- node->id = NULL;
- }
- }
-
sort_linked_ids(bmain);
assert_sorted_ids(bmain);
}
@@ -951,141 +926,6 @@ static bNodeSocket *do_version_replace_float_size_with_vector(bNodeTree *ntree,
return new_socket;
}
-static bool geometry_node_is_293_legacy(const short node_type)
-{
- switch (node_type) {
- /* Not legacy: No attribute inputs or outputs. */
- case GEO_NODE_TRIANGULATE:
- case GEO_NODE_TRANSFORM:
- case GEO_NODE_MESH_BOOLEAN:
- case GEO_NODE_IS_VIEWPORT:
- case GEO_NODE_SUBDIVIDE_MESH:
- case GEO_NODE_MESH_PRIMITIVE_CUBE:
- case GEO_NODE_MESH_PRIMITIVE_CIRCLE:
- case GEO_NODE_MESH_PRIMITIVE_UV_SPHERE:
- case GEO_NODE_MESH_PRIMITIVE_CYLINDER:
- case GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE:
- case GEO_NODE_MESH_PRIMITIVE_CONE:
- case GEO_NODE_MESH_PRIMITIVE_LINE:
- case GEO_NODE_MESH_PRIMITIVE_GRID:
- case GEO_NODE_BOUNDING_BOX:
- case GEO_NODE_RESAMPLE_CURVE:
- case GEO_NODE_INPUT_MATERIAL:
- case GEO_NODE_REPLACE_MATERIAL:
- case GEO_NODE_CURVE_LENGTH:
- case GEO_NODE_CONVEX_HULL:
- case GEO_NODE_SEPARATE_COMPONENTS:
- case GEO_NODE_CURVE_PRIMITIVE_STAR:
- case GEO_NODE_CURVE_PRIMITIVE_SPIRAL:
- case GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER:
- case GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT:
- case GEO_NODE_CURVE_PRIMITIVE_CIRCLE:
- case GEO_NODE_VIEWER:
- case GEO_NODE_CURVE_PRIMITIVE_LINE:
- case GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL:
- case GEO_NODE_FILL_CURVE:
- case GEO_NODE_TRIM_CURVE:
- case GEO_NODE_CURVE_TO_MESH:
- return false;
-
- /* Not legacy: Newly added with fields patch. */
- case GEO_NODE_INPUT_POSITION:
- case GEO_NODE_SET_POSITION:
- case GEO_NODE_INPUT_INDEX:
- case GEO_NODE_INPUT_NORMAL:
- case GEO_NODE_CAPTURE_ATTRIBUTE:
- return false;
-
- /* Maybe legacy: Might need special attribute handling, depending on design. */
- case GEO_NODE_SWITCH:
- case GEO_NODE_JOIN_GEOMETRY:
- case GEO_NODE_LEGACY_ATTRIBUTE_REMOVE:
- case GEO_NODE_OBJECT_INFO:
- case GEO_NODE_COLLECTION_INFO:
- return false;
-
- /* Maybe legacy: Special case for grid names? Or finish patch from level set branch to
- * generate a mesh for all grids in the volume. */
- case GEO_NODE_LEGACY_VOLUME_TO_MESH:
- return false;
-
- /* Legacy: Transferred *all* attributes before, will not transfer all built-ins now. */
- case GEO_NODE_LEGACY_CURVE_ENDPOINTS:
- case GEO_NODE_LEGACY_CURVE_TO_POINTS:
- return true;
-
- /* Legacy: Attribute operation completely replaced by field nodes. */
- case GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE:
- case GEO_NODE_LEGACY_ATTRIBUTE_MATH:
- case GEO_NODE_LEGACY_ATTRIBUTE_FILL:
- case GEO_NODE_LEGACY_ATTRIBUTE_MIX:
- case GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP:
- case GEO_NODE_LEGACY_ATTRIBUTE_COMPARE:
- case GEO_NODE_LEGACY_POINT_ROTATE:
- case GEO_NODE_LEGACY_ALIGN_ROTATION_TO_VECTOR:
- case GEO_NODE_LEGACY_POINT_SCALE:
- case GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE:
- case GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_ROTATE:
- case GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP:
- case GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE:
- case GEO_NODE_LEGACY_ATTRIBUTE_CLAMP:
- case GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_MATH:
- case GEO_NODE_LEGACY_ATTRIBUTE_COMBINE_XYZ:
- case GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ:
- return true;
-
- /* Legacy: Replaced by field node depending on another geometry. */
- case GEO_NODE_LEGACY_RAYCAST:
- case GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER:
- case GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY:
- return true;
-
- /* Legacy: Simple selection attribute input. */
- case GEO_NODE_LEGACY_MESH_TO_CURVE:
- case GEO_NODE_LEGACY_POINT_SEPARATE:
- case GEO_NODE_LEGACY_CURVE_SELECT_HANDLES:
- case GEO_NODE_LEGACY_CURVE_SPLINE_TYPE:
- case GEO_NODE_LEGACY_CURVE_REVERSE:
- case GEO_NODE_LEGACY_MATERIAL_ASSIGN:
- case GEO_NODE_LEGACY_CURVE_SET_HANDLES:
- return true;
-
- /* Legacy: More complex attribute inputs or outputs. */
- case GEO_NODE_LEGACY_SUBDIVISION_SURFACE: /* Used "crease" attribute. */
- case GEO_NODE_LEGACY_EDGE_SPLIT: /* Needs selection input version. */
- case GEO_NODE_LEGACY_DELETE_GEOMETRY: /* Needs field input, domain drop-down. */
- case GEO_NODE_LEGACY_CURVE_SUBDIVIDE: /* Needs field count input. */
- case GEO_NODE_LEGACY_POINTS_TO_VOLUME: /* Needs field radius input. */
- case GEO_NODE_LEGACY_SELECT_BY_MATERIAL: /* Output anonymous attribute. */
- case GEO_NODE_LEGACY_POINT_TRANSLATE: /* Needs field inputs. */
- case GEO_NODE_LEGACY_POINT_INSTANCE: /* Needs field inputs. */
- case GEO_NODE_LEGACY_POINT_DISTRIBUTE: /* Needs field input, remove max for random mode. */
- case GEO_NODE_LEGACY_ATTRIBUTE_CONVERT: /* Attribute Capture, Store Attribute. */
- return true;
- }
- return false;
-}
-
-static void version_geometry_nodes_change_legacy_names(bNodeTree *ntree)
-{
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (geometry_node_is_293_legacy(node->type)) {
- if (strstr(node->idname, "Legacy")) {
- /* Make sure we haven't changed this idname already, better safe than sorry. */
- continue;
- }
-
- char temp_idname[sizeof(node->idname)];
- BLI_strncpy(temp_idname, node->idname, sizeof(node->idname));
-
- BLI_snprintf(node->idname,
- sizeof(node->idname),
- "GeometryNodeLegacy%s",
- temp_idname + strlen("GeometryNode"));
- }
- }
-}
-
static bool seq_transform_origin_set(Sequence *seq, void *UNUSED(user_data))
{
StripTransform *transform = seq->strip->transform;
@@ -1873,24 +1713,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 19)) {
- /* Add node storage for subdivision surface node. */
- FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- if (ntree->type == NTREE_GEOMETRY) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == GEO_NODE_LEGACY_SUBDIVISION_SURFACE) {
- if (node->storage == NULL) {
- NodeGeometrySubdivisionSurface *data = MEM_callocN(
- sizeof(NodeGeometrySubdivisionSurface), __func__);
- data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
- data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL;
- node->storage = data;
- }
- }
- }
- }
- }
- FOREACH_NODETREE_END;
-
/* Disable Fade Inactive Overlay by default as it is redundant after introducing flash on
* mode transfer. */
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
@@ -2091,30 +1913,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
-
- /* Deprecate the random float node in favor of the random value node. */
- LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
- if (ntree->type != NTREE_GEOMETRY) {
- continue;
- }
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type != FN_NODE_LEGACY_RANDOM_FLOAT) {
- continue;
- }
- if (strstr(node->idname, "Legacy")) {
- /* Make sure we haven't changed this idname already. */
- continue;
- }
-
- char temp_idname[sizeof(node->idname)];
- BLI_strncpy(temp_idname, node->idname, sizeof(node->idname));
-
- BLI_snprintf(node->idname,
- sizeof(node->idname),
- "FunctionNodeLegacy%s",
- temp_idname + strlen("FunctionNode"));
- }
- }
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 29)) {
@@ -2141,12 +1939,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
-
- LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
- if (ntree->type == NTREE_GEOMETRY) {
- version_geometry_nodes_change_legacy_names(ntree);
- }
- }
}
if (!MAIN_VERSION_ATLEAST(bmain, 300, 31)) {
@@ -2304,7 +2096,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
version_node_id(ntree, FN_NODE_SLICE_STRING, "FunctionNodeSliceString");
version_geometry_nodes_set_position_node_offset(ntree);
- version_node_id(ntree, GEO_NODE_LEGACY_VOLUME_TO_MESH, "GeometryNodeLegacyVolumeToMesh");
}
/* Add storage to viewer node. */
@@ -2638,12 +2429,32 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
/* Keep this block, even when empty. */
- /* Deprecate the attribute remove node. It was hidden and is replaced by a version without a
- * multi-input socket. */
- LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
- if (ntree->type == NTREE_GEOMETRY) {
- version_node_id(
- ntree, GEO_NODE_LEGACY_ATTRIBUTE_REMOVE, "GeometryNodeLegacyAttributeRemove");
+ /* Initialize brush curves sculpt settings. */
+ LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
+ if (brush->ob_mode != OB_MODE_SCULPT_CURVES) {
+ continue;
+ }
+ if (brush->curves_sculpt_settings != NULL) {
+ continue;
+ }
+ brush->curves_sculpt_settings = MEM_callocN(sizeof(BrushCurvesSculptSettings), __func__);
+ brush->curves_sculpt_settings->add_amount = 1;
+ }
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ if (scene->toolsettings && scene->toolsettings->curves_sculpt &&
+ scene->toolsettings->curves_sculpt->curve_length == 0.0f) {
+ scene->toolsettings->curves_sculpt->curve_length = 0.3f;
+ }
+ }
+
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_OUTLINER) {
+ SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
+ space_outliner->filter &= ~SO_FILTER_CLEARED_1;
+ }
+ }
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 5b026c1cca0..16297149cc3 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -2064,8 +2064,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
}
for (part = bmain->particles.first; part; part = part->id.next) {
- if (part->ren_child_nbr == 0) {
- part->ren_child_nbr = part->child_nbr;
+ if (part->child_render_percent == 0) {
+ part->child_render_percent = part->child_percent;
}
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index 0d16cc9dffd..a5994b52bc2 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -17,7 +17,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm);
void BM_mesh_elem_toolflags_clear(BMesh *bm);
struct BMeshCreateParams {
- uint use_toolflags : 1;
+ bool use_toolflags : true;
};
/**
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
index fd14a3416e2..118e7751cbc 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
@@ -229,7 +229,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
* work, but also accessing normals on an incomplete mesh, for example when restoring undo steps
* in edit mode. */
const float(*vert_normals)[3] = nullptr;
- if (!BKE_mesh_vertex_normals_are_dirty(me)) {
+ if (params->calc_vert_normal) {
vert_normals = BKE_mesh_vertex_normals_ensure(me);
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.h b/source/blender/bmesh/intern/bmesh_mesh_convert.h
index 0bd70749cb1..cc1ad71549d 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.h
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.h
@@ -18,11 +18,12 @@ void BM_mesh_cd_flag_apply(BMesh *bm, char cd_flag);
char BM_mesh_cd_flag_from_bmesh(BMesh *bm);
struct BMeshFromMeshParams {
- uint calc_face_normal : 1;
+ bool calc_face_normal : true;
+ bool calc_vert_normal : true;
/* add a vertex CD_SHAPE_KEYINDEX layer */
- uint add_key_index : 1;
+ bool add_key_index : true;
/* set vertex coordinates from the shapekey */
- uint use_shapekey : 1;
+ bool use_shapekey : true;
/* define the active shape key (index + 1) */
int active_shapekey;
struct CustomData_MeshMasks cd_mask_extra;
@@ -42,7 +43,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const struct Mesh *me, const struct BMeshFrom
struct BMeshToMeshParams {
/** Update object hook indices & vertex parents. */
- uint calc_object_remap : 1;
+ bool calc_object_remap : true;
/**
* This re-assigns shape-key indices. Only do if the BMesh will have continued use
* to update the mesh & shape key in the future.
@@ -52,12 +53,12 @@ struct BMeshToMeshParams {
* so a second flush or edit-mode exit doesn't run with indices
* that have become invalid from updating the shape-key, see T71865.
*/
- uint update_shapekey_indices : 1;
+ bool update_shapekey_indices : true;
/**
* Instead of copying the basis shape-key into the #MVert array,
* copy the #BMVert.co directly to #MVert.co (used for reading undo data).
*/
- uint active_shapekey_to_mvert : 1;
+ bool active_shapekey_to_mvert : true;
struct CustomData_MeshMasks cd_mask_extra;
};
/**
diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.c b/source/blender/bmesh/intern/bmesh_mesh_normals.c
index d61b2c5bb43..cd89a550279 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_normals.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_normals.c
@@ -580,7 +580,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
/* We validate clnors data on the fly - cheapest way to do! */
int clnors_avg[2] = {0, 0};
const short(*clnor_ref)[2] = NULL;
- int clnors_nbr = 0;
+ int clnors_count = 0;
bool clnors_invalid = false;
const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co;
@@ -649,7 +649,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
const short(*clnor)[2] = clnors_data ? &clnors_data[lfan_pivot_index] :
(const void *)BM_ELEM_CD_GET_VOID_P(
lfan_pivot, cd_loop_clnors_offset);
- if (clnors_nbr) {
+ if (clnors_count) {
clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]);
}
else {
@@ -657,7 +657,7 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
}
clnors_avg[0] += (*clnor)[0];
clnors_avg[1] += (*clnor)[1];
- clnors_nbr++;
+ clnors_count++;
/* We store here a pointer to all custom lnors processed. */
BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor);
}
@@ -706,8 +706,8 @@ static int bm_mesh_loops_calc_normals_for_loop(BMesh *bm,
if (clnors_invalid) {
short *clnor;
- clnors_avg[0] /= clnors_nbr;
- clnors_avg[1] /= clnors_nbr;
+ clnors_avg[0] /= clnors_count;
+ clnors_avg[1] /= clnors_count;
/* Fix/update all clnors of this fan with computed average value. */
/* Prints continuously when merge custom normals, so commenting. */
@@ -1517,7 +1517,7 @@ static void bm_mesh_loops_assign_normal_data(BMesh *bm,
BLI_BITMAP_ENABLE(done_loops, i);
}
else {
- int nbr_nors = 0;
+ int avg_nor_count = 0;
float avg_nor[3];
short clnor_data_tmp[2], *clnor_data;
@@ -1530,7 +1530,7 @@ static void bm_mesh_loops_assign_normal_data(BMesh *bm,
short *clnor = r_clnors_data ? &r_clnors_data[lidx] :
BM_ELEM_CD_GET_VOID_P(ml, cd_loop_clnors_offset);
- nbr_nors++;
+ avg_nor_count++;
add_v3_v3(avg_nor, nor);
BLI_SMALLSTACK_PUSH(clnors_data, clnor);
@@ -1538,7 +1538,7 @@ static void bm_mesh_loops_assign_normal_data(BMesh *bm,
BLI_BITMAP_ENABLE(done_loops, lidx);
}
- mul_v3_fl(avg_nor, 1.0f / (float)nbr_nors);
+ mul_v3_fl(avg_nor, 1.0f / (float)avg_nor_count);
BKE_lnor_space_custom_normal_to_data(
lnors_spacearr->lspacearr[i], avg_nor, clnor_data_tmp);
diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c
index 1bc5b70f874..8bc16324971 100644
--- a/source/blender/bmesh/intern/bmesh_query.c
+++ b/source/blender/bmesh/intern/bmesh_query.c
@@ -1869,7 +1869,7 @@ bool BM_face_exists_overlap_subset(BMVert **varr, const int len)
for (int i = 0; i < len; i++) {
BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) {
if ((f->len <= len) && (BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0)) {
- /* Check if all vers in this face are flagged. */
+ /* Check if all verts in this face are flagged. */
BMLoop *l_iter, *l_first;
if (is_init == false) {
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 5790d76936f..be5521d45ab 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -571,7 +571,7 @@ static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e)
/* Return the count of edges between e1 and e2 when going around bv CCW. */
static int count_ccw_edges_between(EdgeHalf *e1, EdgeHalf *e2)
{
- int cnt = 0;
+ int count = 0;
EdgeHalf *e = e1;
do {
@@ -579,9 +579,9 @@ static int count_ccw_edges_between(EdgeHalf *e1, EdgeHalf *e2)
break;
}
e = e->next;
- cnt++;
+ count++;
} while (e != e1);
- return cnt;
+ return count;
}
/* Assume bme1 and bme2 both share some vert. Do they share a face?
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index 07d4172d037..81a392d38a5 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -517,7 +517,6 @@ static bool bm_decim_triangulate_begin(BMesh *bm, int *r_edges_tri_tot)
{
BMIter iter;
BMFace *f;
- bool has_quad = false;
bool has_ngon = false;
bool has_cut = false;
@@ -533,7 +532,6 @@ static bool bm_decim_triangulate_begin(BMesh *bm, int *r_edges_tri_tot)
BM_elem_index_set(l_iter, -1); /* set_dirty */
} while ((l_iter = l_iter->next) != l_first);
- has_quad |= (f->len > 3);
has_ngon |= (f->len > 4);
}
diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h
index eafa6614d31..0fdd7647f8d 100644
--- a/source/blender/compositor/COM_compositor.h
+++ b/source/blender/compositor/COM_compositor.h
@@ -318,12 +318,6 @@ extern "C" {
* - output nodes can have different priorities in the WorkScheduler.
* This is implemented in the COM_execute function.
*
- * \param view_settings:
- * reference to view settings used for color management
- *
- * \param display_settings:
- * reference to display settings used for color management
- *
* OCIO_TODO: this options only used in rare cases, namely in output file node,
* so probably this settings could be passed in a nicer way.
* should be checked further, probably it'll be also needed for preview
@@ -335,8 +329,6 @@ void COM_execute(RenderData *render_data,
Scene *scene,
bNodeTree *node_tree,
int rendering,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name);
/**
diff --git a/source/blender/compositor/intern/COM_CompositorContext.cc b/source/blender/compositor/intern/COM_CompositorContext.cc
index f17a24c6b9d..2c55af1779a 100644
--- a/source/blender/compositor/intern/COM_CompositorContext.cc
+++ b/source/blender/compositor/intern/COM_CompositorContext.cc
@@ -12,8 +12,6 @@ CompositorContext::CompositorContext()
quality_ = eCompositorQuality::High;
hasActiveOpenCLDevices_ = false;
fast_calculation_ = false;
- view_settings_ = nullptr;
- display_settings_ = nullptr;
bnodetree_ = nullptr;
}
diff --git a/source/blender/compositor/intern/COM_CompositorContext.h b/source/blender/compositor/intern/COM_CompositorContext.h
index 430bab48352..480f70f4193 100644
--- a/source/blender/compositor/intern/COM_CompositorContext.h
+++ b/source/blender/compositor/intern/COM_CompositorContext.h
@@ -64,10 +64,6 @@ class CompositorContext {
*/
bool fast_calculation_;
- /* \brief color management settings */
- const ColorManagedViewSettings *view_settings_;
- const ColorManagedDisplaySettings *display_settings_;
-
/**
* \brief active rendering view name
*/
@@ -153,38 +149,6 @@ class CompositorContext {
}
/**
- * \brief set view settings of color management
- */
- void set_view_settings(const ColorManagedViewSettings *view_settings)
- {
- view_settings_ = view_settings;
- }
-
- /**
- * \brief get view settings of color management
- */
- const ColorManagedViewSettings *get_view_settings() const
- {
- return view_settings_;
- }
-
- /**
- * \brief set display settings of color management
- */
- void set_display_settings(const ColorManagedDisplaySettings *display_settings)
- {
- display_settings_ = display_settings;
- }
-
- /**
- * \brief get display settings of color management
- */
- const ColorManagedDisplaySettings *get_display_settings() const
- {
- return display_settings_;
- }
-
- /**
* \brief set the quality
*/
void set_quality(eCompositorQuality quality)
diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc
index 0d9d3b111b0..66dbabe71b5 100644
--- a/source/blender/compositor/intern/COM_Debug.cc
+++ b/source/blender/compositor/intern/COM_Debug.cc
@@ -468,8 +468,8 @@ void DebugInfo::delete_operation_exports()
const std::string dir = get_operations_export_dir();
if (BLI_exists(dir.c_str())) {
struct direntry *file_list;
- int num_files = BLI_filelist_dir_contents(dir.c_str(), &file_list);
- for (int i = 0; i < num_files; i++) {
+ int file_list_num = BLI_filelist_dir_contents(dir.c_str(), &file_list);
+ for (int i = 0; i < file_list_num; i++) {
direntry *file = &file_list[i];
const eFileAttributes file_attrs = BLI_file_attributes(file->path);
if (file_attrs & FILE_ATTR_ANY_LINK) {
@@ -480,7 +480,7 @@ void DebugInfo::delete_operation_exports()
BLI_delete(file->path, false, false);
}
}
- BLI_filelist_free(file_list, num_files);
+ BLI_filelist_free(file_list, file_list_num);
}
}
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cc b/source/blender/compositor/intern/COM_ExecutionSystem.cc
index 036e2bc8a91..c850585148a 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.cc
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.cc
@@ -23,8 +23,6 @@ ExecutionSystem::ExecutionSystem(RenderData *rd,
bNodeTree *editingtree,
bool rendering,
bool fastcalculation,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name)
{
num_work_threads_ = WorkScheduler::get_num_cpu_threads();
@@ -45,8 +43,6 @@ ExecutionSystem::ExecutionSystem(RenderData *rd,
(editingtree->flag & NTREE_COM_OPENCL));
context_.set_render_data(rd);
- context_.set_view_settings(view_settings);
- context_.set_display_settings(display_settings);
BLI_mutex_init(&work_mutex_);
BLI_condition_init(&work_finished_cond_);
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h
index 9dd20d18144..2cd9e2d9001 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.h
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.h
@@ -160,8 +160,6 @@ class ExecutionSystem {
bNodeTree *editingtree,
bool rendering,
bool fastcalculation,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name);
/**
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
index 2f27699ce9c..788686f3036 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc
@@ -221,8 +221,9 @@ PreviewOperation *NodeOperationBuilder::make_preview_operation() const
bNodeInstanceHash *previews = context_->get_preview_hash();
if (previews) {
- PreviewOperation *operation = new PreviewOperation(context_->get_view_settings(),
- context_->get_display_settings(),
+ Scene *scene = context_->get_scene();
+ PreviewOperation *operation = new PreviewOperation(&scene->view_settings,
+ &scene->display_settings,
current_node_->get_bnode()->preview_xsize,
current_node_->get_bnode()->preview_ysize);
operation->set_bnodetree(context_->get_bnodetree());
diff --git a/source/blender/compositor/intern/COM_compositor.cc b/source/blender/compositor/intern/COM_compositor.cc
index 791cc327bfb..519ad93bcaf 100644
--- a/source/blender/compositor/intern/COM_compositor.cc
+++ b/source/blender/compositor/intern/COM_compositor.cc
@@ -49,8 +49,6 @@ void COM_execute(RenderData *render_data,
Scene *scene,
bNodeTree *node_tree,
int rendering,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name)
{
/* Initialize mutex, TODO: this mutex init is actually not thread safe and
@@ -80,14 +78,8 @@ void COM_execute(RenderData *render_data,
/* Execute. */
const bool twopass = (node_tree->flag & NTREE_TWO_PASS) && !rendering;
if (twopass) {
- blender::compositor::ExecutionSystem fast_pass(render_data,
- scene,
- node_tree,
- rendering,
- true,
- view_settings,
- display_settings,
- view_name);
+ blender::compositor::ExecutionSystem fast_pass(
+ render_data, scene, node_tree, rendering, true, view_name);
fast_pass.execute();
if (node_tree->test_break(node_tree->tbh)) {
@@ -97,7 +89,7 @@ void COM_execute(RenderData *render_data,
}
blender::compositor::ExecutionSystem system(
- render_data, scene, node_tree, rendering, false, view_settings, display_settings, view_name);
+ render_data, scene, node_tree, rendering, false, view_name);
system.execute();
BLI_mutex_unlock(&g_compositor.mutex);
diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cc b/source/blender/compositor/nodes/COM_OutputFileNode.cc
index b0568dc308e..f69511d88e6 100644
--- a/source/blender/compositor/nodes/COM_OutputFileNode.cc
+++ b/source/blender/compositor/nodes/COM_OutputFileNode.cc
@@ -35,12 +35,22 @@ void OutputFileNode::map_input_sockets(NodeConverter &converter,
}
}
+void OutputFileNode::add_preview_to_first_linked_input(NodeConverter &converter) const
+{
+ NodeInput *first_socket = this->get_input_socket(0);
+ if (first_socket->is_linked()) {
+ converter.add_node_input_preview(first_socket);
+ }
+}
+
void OutputFileNode::convert_to_operations(NodeConverter &converter,
const CompositorContext &context) const
{
NodeImageMultiFile *storage = (NodeImageMultiFile *)this->get_bnode()->storage;
const bool is_multiview = (context.get_render_data()->scemode & R_MULTIVIEW) != 0;
+ add_preview_to_first_linked_input(converter);
+
if (!context.is_rendering()) {
/* only output files when rendering a sequence -
* otherwise, it overwrites the output files just
@@ -81,7 +91,6 @@ void OutputFileNode::convert_to_operations(NodeConverter &converter,
map_input_sockets(converter, *output_operation);
}
else { /* single layer format */
- bool preview_added = false;
for (NodeInput *input : inputs_) {
if (input->is_linked()) {
NodeImageMultiFileSocket *sockdata =
@@ -97,47 +106,39 @@ void OutputFileNode::convert_to_operations(NodeConverter &converter,
if (is_multiview && format->views_format == R_IMF_VIEWS_MULTIVIEW) {
output_operation = new OutputOpenExrSingleLayerMultiViewOperation(
+ context.get_scene(),
context.get_render_data(),
context.get_bnodetree(),
input->get_data_type(),
format,
path,
- context.get_view_settings(),
- context.get_display_settings(),
context.get_view_name(),
sockdata->save_as_render);
}
else if ((!is_multiview) || (format->views_format == R_IMF_VIEWS_INDIVIDUAL)) {
- output_operation = new OutputSingleLayerOperation(context.get_render_data(),
+ output_operation = new OutputSingleLayerOperation(context.get_scene(),
+ context.get_render_data(),
context.get_bnodetree(),
input->get_data_type(),
format,
path,
- context.get_view_settings(),
- context.get_display_settings(),
context.get_view_name(),
sockdata->save_as_render);
}
else { /* R_IMF_VIEWS_STEREO_3D */
- output_operation = new OutputStereoOperation(context.get_render_data(),
+ output_operation = new OutputStereoOperation(context.get_scene(),
+ context.get_render_data(),
context.get_bnodetree(),
input->get_data_type(),
format,
path,
sockdata->layer,
- context.get_view_settings(),
- context.get_display_settings(),
context.get_view_name(),
sockdata->save_as_render);
}
converter.add_operation(output_operation);
converter.map_input_socket(input, output_operation->get_input_socket(0));
-
- if (!preview_added) {
- converter.add_node_input_preview(input);
- preview_added = true;
- }
}
}
}
diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.h b/source/blender/compositor/nodes/COM_OutputFileNode.h
index be2464c1888..61d8700270e 100644
--- a/source/blender/compositor/nodes/COM_OutputFileNode.h
+++ b/source/blender/compositor/nodes/COM_OutputFileNode.h
@@ -22,6 +22,7 @@ class OutputFileNode : public Node {
const CompositorContext &context) const override;
private:
+ void add_preview_to_first_linked_input(NodeConverter &converter) const;
void add_input_sockets(OutputOpenExrMultiLayerOperation &operation) const;
void map_input_sockets(NodeConverter &converter,
OutputOpenExrMultiLayerOperation &operation) const;
diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cc b/source/blender/compositor/nodes/COM_SplitViewerNode.cc
index 0e7db05980a..d02bc6e773d 100644
--- a/source/blender/compositor/nodes/COM_SplitViewerNode.cc
+++ b/source/blender/compositor/nodes/COM_SplitViewerNode.cc
@@ -24,6 +24,7 @@ void SplitViewerNode::convert_to_operations(NodeConverter &converter,
NodeInput *image2Socket = this->get_input_socket(1);
Image *image = (Image *)this->get_bnode()->id;
ImageUser *image_user = (ImageUser *)this->get_bnode()->storage;
+ Scene *scene = context.get_scene();
SplitOperation *split_viewer_operation = new SplitOperation();
split_viewer_operation->set_split_percentage(this->get_bnode()->custom1);
@@ -36,8 +37,8 @@ void SplitViewerNode::convert_to_operations(NodeConverter &converter,
ViewerOperation *viewer_operation = new ViewerOperation();
viewer_operation->set_image(image);
viewer_operation->set_image_user(image_user);
- viewer_operation->set_view_settings(context.get_view_settings());
- viewer_operation->set_display_settings(context.get_display_settings());
+ viewer_operation->set_view_settings(&scene->view_settings);
+ viewer_operation->set_display_settings(&scene->display_settings);
viewer_operation->set_render_data(context.get_render_data());
viewer_operation->set_view_name(context.get_view_name());
diff --git a/source/blender/compositor/nodes/COM_TextureNode.cc b/source/blender/compositor/nodes/COM_TextureNode.cc
index 216df59cc47..be5f7b90e11 100644
--- a/source/blender/compositor/nodes/COM_TextureNode.cc
+++ b/source/blender/compositor/nodes/COM_TextureNode.cc
@@ -17,8 +17,7 @@ void TextureNode::convert_to_operations(NodeConverter &converter,
bNode *editor_node = this->get_bnode();
Tex *texture = (Tex *)editor_node->id;
TextureOperation *operation = new TextureOperation();
- const ColorManagedDisplaySettings *display_settings = context.get_display_settings();
- bool scene_color_manage = !STREQ(display_settings->display_device, "None");
+ bool scene_color_manage = !STREQ(context.get_scene()->display_settings.display_device, "None");
operation->set_texture(texture);
operation->set_render_data(context.get_render_data());
operation->set_scene_color_manage(scene_color_manage);
diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cc b/source/blender/compositor/nodes/COM_ViewerNode.cc
index 1b335abc4d7..ebef331c62f 100644
--- a/source/blender/compositor/nodes/COM_ViewerNode.cc
+++ b/source/blender/compositor/nodes/COM_ViewerNode.cc
@@ -37,8 +37,9 @@ void ViewerNode::convert_to_operations(NodeConverter &converter,
viewer_operation->set_render_data(context.get_render_data());
viewer_operation->set_view_name(context.get_view_name());
- viewer_operation->set_view_settings(context.get_view_settings());
- viewer_operation->set_display_settings(context.get_display_settings());
+ Scene *scene = context.get_scene();
+ viewer_operation->set_view_settings(&scene->view_settings);
+ viewer_operation->set_display_settings(&scene->display_settings);
viewer_operation->set_canvas_input_index(0);
if (!image_socket->is_linked()) {
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cc b/source/blender/compositor/operations/COM_CompositorOperation.cc
index 23520364bf0..e8b61ff229e 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.cc
+++ b/source/blender/compositor/operations/COM_CompositorOperation.cc
@@ -114,7 +114,7 @@ void CompositorOperation::deinit_execution()
void CompositorOperation::execute_region(rcti *rect, unsigned int /*tile_number*/)
{
- float color[8]; // 7 is enough
+ float color[8]; /* 7 is enough. */
float *buffer = output_buffer_;
float *zbuffer = depth_buffer_;
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
index db29a84f7da..aeaf6b659e3 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc
@@ -4,6 +4,7 @@
#include "COM_OutputFileMultiViewOperation.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_main.h"
#include "BKE_scene.h"
@@ -16,24 +17,16 @@ namespace blender::compositor {
/************************************ OpenEXR Singlelayer Multiview ******************************/
OutputOpenExrSingleLayerMultiViewOperation::OutputOpenExrSingleLayerMultiViewOperation(
+ const Scene *scene,
const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
ImageFormatData *format,
const char *path,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name,
const bool save_as_render)
- : OutputSingleLayerOperation(rd,
- tree,
- datatype,
- format,
- path,
- view_settings,
- display_settings,
- view_name,
- save_as_render)
+ : OutputSingleLayerOperation(
+ scene, rd, tree, datatype, format, path, view_name, save_as_render)
{
}
@@ -67,7 +60,7 @@ void *OutputOpenExrSingleLayerMultiViewOperation::get_handle(const char *filenam
/* prepare the file with all the channels */
- if (!IMB_exr_begin_write(exrhandle, filename, width, height, format_->exr_codec, nullptr)) {
+ if (!IMB_exr_begin_write(exrhandle, filename, width, height, format_.exr_codec, nullptr)) {
printf("Error Writing Singlelayer Multiview Openexr\n");
IMB_exr_close(exrhandle);
}
@@ -103,7 +96,7 @@ void OutputOpenExrSingleLayerMultiViewOperation::deinit_execution()
datatype_,
view_name_,
width,
- format_->depth == R_IMF_CHAN_DEPTH_16,
+ format_.depth == R_IMF_CHAN_DEPTH_16,
output_buffer_);
/* memory can only be freed after we write all views to the file */
@@ -246,25 +239,17 @@ void OutputOpenExrMultiLayerMultiViewOperation::deinit_execution()
/******************************** Stereo3D ******************************/
-OutputStereoOperation::OutputStereoOperation(const RenderData *rd,
+OutputStereoOperation::OutputStereoOperation(const Scene *scene,
+ const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
ImageFormatData *format,
const char *path,
const char *name,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name,
const bool save_as_render)
- : OutputSingleLayerOperation(rd,
- tree,
- datatype,
- format,
- path,
- view_settings,
- display_settings,
- view_name,
- save_as_render)
+ : OutputSingleLayerOperation(
+ scene, rd, tree, datatype, format, path, view_name, save_as_render)
{
BLI_strncpy(name_, name, sizeof(name_));
channels_ = get_datatype_size(datatype);
@@ -316,7 +301,7 @@ void OutputStereoOperation::deinit_execution()
1,
channels_ * width * height,
buf,
- format_->depth == R_IMF_CHAN_DEPTH_16);
+ format_.depth == R_IMF_CHAN_DEPTH_16);
image_input_ = nullptr;
output_buffer_ = nullptr;
@@ -331,7 +316,7 @@ void OutputStereoOperation::deinit_execution()
/* get rectf from EXR */
for (i = 0; i < 2; i++) {
float *rectf = IMB_exr_channel_rect(exrhandle, nullptr, name_, names[i]);
- ibuf[i] = IMB_allocImBuf(width, height, format_->planes, 0);
+ ibuf[i] = IMB_allocImBuf(width, height, format_.planes, 0);
ibuf[i]->channels = channels_;
ibuf[i]->rect_float = rectf;
@@ -339,24 +324,23 @@ void OutputStereoOperation::deinit_execution()
ibuf[i]->dither = rd_->dither_intensity;
/* do colormanagement in the individual views, so it doesn't need to do in the stereo */
- IMB_colormanagement_imbuf_for_write(
- ibuf[i], true, false, view_settings_, display_settings_, format_);
+ IMB_colormanagement_imbuf_for_write(ibuf[i], true, false, &format_);
IMB_prepare_write_ImBuf(IMB_isfloat(ibuf[i]), ibuf[i]);
}
/* create stereo buffer */
- ibuf[2] = IMB_stereo3d_ImBuf(format_, ibuf[0], ibuf[1]);
+ ibuf[2] = IMB_stereo3d_ImBuf(&format_, ibuf[0], ibuf[1]);
BKE_image_path_from_imformat(filename,
path_,
BKE_main_blendfile_path_from_global(),
rd_->cfra,
- format_,
+ &format_,
(rd_->scemode & R_EXTENSION) != 0,
true,
nullptr);
- BKE_imbuf_write(ibuf[2], filename, format_);
+ BKE_imbuf_write(ibuf[2], filename, &format_);
/* imbuf knows which rects are not part of ibuf */
for (i = 0; i < 3; i++) {
diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
index dac7a208e7e..69f4011d340 100644
--- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.h
@@ -11,20 +11,19 @@
#include "DNA_color_types.h"
-#include "intern/openexr/openexr_multi.h"
+#include "IMB_openexr.h"
namespace blender::compositor {
class OutputOpenExrSingleLayerMultiViewOperation : public OutputSingleLayerOperation {
private:
public:
- OutputOpenExrSingleLayerMultiViewOperation(const RenderData *rd,
+ OutputOpenExrSingleLayerMultiViewOperation(const Scene *scene,
+ const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
ImageFormatData *format,
const char *path,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name,
bool save_as_render);
@@ -54,14 +53,13 @@ class OutputStereoOperation : public OutputSingleLayerOperation {
size_t channels_;
public:
- OutputStereoOperation(const RenderData *rd,
+ OutputStereoOperation(const Scene *scene,
+ const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
struct ImageFormatData *format,
const char *path,
const char *name,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name,
bool save_as_render);
void *get_handle(const char *filename);
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cc b/source/blender/compositor/operations/COM_OutputFileOperation.cc
index 56fbfc570a8..cde1496546e 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cc
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cc
@@ -8,6 +8,7 @@
#include "BLI_string.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_main.h"
#include "BKE_scene.h"
@@ -199,16 +200,14 @@ static void write_buffer_rect(rcti *rect,
}
}
-OutputSingleLayerOperation::OutputSingleLayerOperation(
- const RenderData *rd,
- const bNodeTree *tree,
- DataType datatype,
- ImageFormatData *format,
- const char *path,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
- const char *view_name,
- const bool save_as_render)
+OutputSingleLayerOperation::OutputSingleLayerOperation(const Scene *scene,
+ const RenderData *rd,
+ const bNodeTree *tree,
+ DataType datatype,
+ ImageFormatData *format,
+ const char *path,
+ const char *view_name,
+ const bool save_as_render)
{
rd_ = rd;
tree_ = tree;
@@ -219,11 +218,9 @@ OutputSingleLayerOperation::OutputSingleLayerOperation(
datatype_ = datatype;
image_input_ = nullptr;
- format_ = format;
+ BKE_image_format_init_for_write(&format_, scene, format);
BLI_strncpy(path_, path, sizeof(path_));
- view_settings_ = view_settings;
- display_settings_ = display_settings;
view_name_ = view_name;
save_as_render_ = save_as_render;
}
@@ -244,7 +241,7 @@ void OutputSingleLayerOperation::deinit_execution()
if (this->get_width() * this->get_height() != 0) {
int size = get_datatype_size(datatype_);
- ImBuf *ibuf = IMB_allocImBuf(this->get_width(), this->get_height(), format_->planes, 0);
+ ImBuf *ibuf = IMB_allocImBuf(this->get_width(), this->get_height(), format_.planes, 0);
char filename[FILE_MAX];
const char *suffix;
@@ -253,8 +250,7 @@ void OutputSingleLayerOperation::deinit_execution()
ibuf->mall |= IB_rectfloat;
ibuf->dither = rd_->dither_intensity;
- IMB_colormanagement_imbuf_for_write(
- ibuf, save_as_render_, false, view_settings_, display_settings_, format_);
+ IMB_colormanagement_imbuf_for_write(ibuf, save_as_render_, false, &format_);
suffix = BKE_scene_multiview_view_suffix_get(rd_, view_name_);
@@ -262,12 +258,12 @@ void OutputSingleLayerOperation::deinit_execution()
path_,
BKE_main_blendfile_path_from_global(),
rd_->cfra,
- format_,
+ &format_,
(rd_->scemode & R_EXTENSION) != 0,
true,
suffix);
- if (0 == BKE_imbuf_write(ibuf, filename, format_)) {
+ if (0 == BKE_imbuf_write(ibuf, filename, &format_)) {
printf("Cannot save Node File Output to %s\n", filename);
}
else {
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.h b/source/blender/compositor/operations/COM_OutputFileOperation.h
index 12fc9ddf5f6..98b7e77cc21 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.h
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.h
@@ -10,7 +10,7 @@
#include "DNA_color_types.h"
-#include "intern/openexr/openexr_multi.h"
+#include "IMB_openexr.h"
namespace blender::compositor {
@@ -20,27 +20,23 @@ class OutputSingleLayerOperation : public MultiThreadedOperation {
const RenderData *rd_;
const bNodeTree *tree_;
- ImageFormatData *format_;
+ ImageFormatData format_;
char path_[FILE_MAX];
float *output_buffer_;
DataType datatype_;
SocketReader *image_input_;
- const ColorManagedViewSettings *view_settings_;
- const ColorManagedDisplaySettings *display_settings_;
-
const char *view_name_;
bool save_as_render_;
public:
- OutputSingleLayerOperation(const RenderData *rd,
+ OutputSingleLayerOperation(const Scene *scene,
+ const RenderData *rd,
const bNodeTree *tree,
DataType datatype,
ImageFormatData *format,
const char *path,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name,
bool save_as_render);
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 98f75ad6106..38ae9e86585 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -25,10 +25,10 @@ set(INC
../windowmanager
../../../intern/atomic
+ ../../../intern/clog
../../../intern/glew-mx
../../../intern/guardedalloc
../../../intern/opensubdiv
- ../../../intern/clog
# dna_type_offsets.h
${CMAKE_CURRENT_BINARY_DIR}/../makesdna/intern
@@ -129,6 +129,7 @@ set(SRC
engines/eevee/eevee_subsurface.c
engines/eevee/eevee_temporal_sampling.c
engines/eevee/eevee_volumes.c
+ engines/eevee_next/eevee_engine.cc
engines/workbench/workbench_data.c
engines/workbench/workbench_effect_antialiasing.c
engines/workbench/workbench_effect_cavity.c
@@ -210,17 +211,19 @@ set(SRC
engines/eevee/eevee_lightcache.h
engines/eevee/eevee_lut.h
engines/eevee/eevee_private.h
+ engines/eevee_next/eevee_engine.h
engines/external/external_engine.h
engines/image/image_batches.hh
+ engines/image/image_buffer_cache.hh
engines/image/image_drawing_mode.hh
engines/image/image_engine.h
engines/image/image_instance_data.hh
engines/image/image_partial_updater.hh
engines/image/image_private.hh
engines/image/image_shader_params.hh
+ engines/image/image_space.hh
engines/image/image_space_image.hh
engines/image/image_space_node.hh
- engines/image/image_space.hh
engines/image/image_texture_info.hh
engines/image/image_usage.hh
engines/image/image_wrappers.hh
@@ -362,6 +365,7 @@ set(GLSL_SRC
intern/shaders/common_colormanagement_lib.glsl
intern/shaders/common_globals_lib.glsl
+ intern/shaders/common_gpencil_lib.glsl
intern/shaders/common_pointcloud_lib.glsl
intern/shaders/common_hair_lib.glsl
intern/shaders/common_hair_refine_vert.glsl
@@ -400,6 +404,9 @@ set(GLSL_SRC
engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
engines/gpencil/shaders/gpencil_vfx_frag.glsl
+ engines/gpencil/gpencil_defines.h
+ engines/gpencil/gpencil_shader_shared.h
+
engines/select/shaders/selection_id_3D_vert.glsl
engines/select/shaders/selection_id_frag.glsl
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 99d9a0d121f..00822946fe5 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -37,6 +37,7 @@ struct bContext;
struct rcti;
void DRW_engines_register(void);
+void DRW_engines_register_experimental(void);
void DRW_engines_free(void);
bool DRW_engine_render_support(struct DrawEngineType *draw_engine_type);
diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index 253981d321b..ee70cebcfd2 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -104,10 +104,12 @@ void EEVEE_motion_blur_data_free(EEVEE_MotionBlurData *mb)
for (int i = 0; i < 2; i++) {
if (mb->position_vbo_cache[i]) {
BLI_ghash_free(mb->position_vbo_cache[i], NULL, (GHashValFreeFP)GPU_vertbuf_discard);
+ mb->position_vbo_cache[i] = NULL;
}
if (mb->hair_motion_step_cache[i]) {
BLI_ghash_free(
mb->hair_motion_step_cache[i], NULL, (GHashValFreeFP)EEVEE_motion_hair_step_free);
+ mb->hair_motion_step_cache[i] = NULL;
}
}
}
diff --git a/source/blender/draw/engines/eevee/eevee_shadows_cascade.c b/source/blender/draw/engines/eevee/eevee_shadows_cascade.c
index 96b0df5b7db..25939926cfa 100644
--- a/source/blender/draw/engines/eevee/eevee_shadows_cascade.c
+++ b/source/blender/draw/engines/eevee/eevee_shadows_cascade.c
@@ -116,7 +116,7 @@ static void eevee_shadow_cascade_setup(EEVEE_LightsInfo *linfo,
EEVEE_ShadowCascade *csm_data = linfo->shadow_cascade_data + (int)shdw_data->type_data_id;
EEVEE_ShadowCascadeRender *csm_render = linfo->shadow_cascade_render +
(int)shdw_data->type_data_id;
- int cascade_nbr = csm_render->cascade_count;
+ int cascade_count = csm_render->cascade_count;
float cascade_fade = csm_render->cascade_fade;
float cascade_max_dist = csm_render->cascade_max_dist;
float cascade_exponent = csm_render->cascade_exponent;
@@ -223,19 +223,19 @@ static void eevee_shadow_cascade_setup(EEVEE_LightsInfo *linfo,
float p[4] = {1.0f, 1.0f, csm_end, 1.0f};
/* TODO: we don't need full m4 multiply here */
mul_m4_v4(vp_projmat, p);
- splits_end_ndc[cascade_nbr - 1] = p[2];
+ splits_end_ndc[cascade_count - 1] = p[2];
if (is_persp) {
- splits_end_ndc[cascade_nbr - 1] /= p[3];
+ splits_end_ndc[cascade_count - 1] /= p[3];
}
}
csm_data->split_start[0] = csm_start;
- csm_data->split_end[cascade_nbr - 1] = csm_end;
+ csm_data->split_end[cascade_count - 1] = csm_end;
- for (int c = 1; c < cascade_nbr; c++) {
+ for (int c = 1; c < cascade_count; c++) {
/* View Space */
- float linear_split = interpf(csm_end, csm_start, c / (float)cascade_nbr);
- float exp_split = csm_start * powf(csm_end / csm_start, c / (float)cascade_nbr);
+ float linear_split = interpf(csm_end, csm_start, c / (float)cascade_count);
+ float exp_split = csm_start * powf(csm_end / csm_start, c / (float)cascade_count);
if (is_persp) {
csm_data->split_start[c] = interpf(exp_split, linear_split, cascade_exponent);
@@ -276,13 +276,13 @@ static void eevee_shadow_cascade_setup(EEVEE_LightsInfo *linfo,
}
/* Set last cascade split fade distance into the first split_start. */
- float prev_split = (cascade_nbr > 1) ? csm_data->split_end[cascade_nbr - 2] :
- csm_data->split_start[0];
+ float prev_split = (cascade_count > 1) ? csm_data->split_end[cascade_count - 2] :
+ csm_data->split_start[0];
csm_data->split_start[0] = interpf(
- prev_split, csm_data->split_end[cascade_nbr - 1], cascade_fade);
+ prev_split, csm_data->split_end[cascade_count - 1], cascade_fade);
/* For each cascade */
- for (int c = 0; c < cascade_nbr; c++) {
+ for (int c = 0; c < cascade_count; c++) {
float(*projmat)[4] = csm_render->projmat[c];
/* Given 8 frustum corners */
float corners[8][3] = {
diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
index 584aacc9e19..ddc6a0b9661 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_eval_glossy_lib.glsl
@@ -26,10 +26,13 @@ struct ClosureEvalGlossy {
#ifdef STEP_RESOLVE /* SSR */
/* Prototype. */
+# ifndef GPU_METAL
+/* MSL does not require prototypes. */
void raytrace_resolve(ClosureInputGlossy cl_in,
inout ClosureEvalGlossy cl_eval,
inout ClosureEvalCommon cl_common,
inout ClosureOutputGlossy cl_out);
+# endif
#endif
ClosureEvalGlossy closure_Glossy_eval_init(inout ClosureInputGlossy cl_in,
diff --git a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
index f66f45635f4..fefc8743691 100644
--- a/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/closure_type_lib.glsl
@@ -32,8 +32,10 @@ struct Closure {
#endif
};
+#ifndef GPU_METAL
/* Prototype */
Closure nodetree_exec(void);
+#endif
/* clang-format off */
/* Avoid multi-line defines. */
diff --git a/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl
index c6f61d1d443..bdcc0a2ba93 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_bloom_frag.glsl
@@ -50,12 +50,6 @@ out vec4 FragColor;
/* -------------- Utils ------------- */
-vec3 safe_color(vec3 c)
-{
- /* Clamp to avoid black square artifacts if a pixel goes NaN. */
- return clamp(c, vec3(0.0), vec3(1e20)); /* 1e20 arbitrary. */
-}
-
/* 3-tap median filter */
vec3 median(vec3 a, vec3 b, vec3 c)
{
@@ -156,7 +150,7 @@ vec4 step_blit(void)
float br = max_v3(m);
/* Under-threshold part: quadratic curve */
- float rq = clamp(br - curveThreshold.x, 0, curveThreshold.y);
+ float rq = clamp(br - curveThreshold.x, 0.0, curveThreshold.y);
rq = curveThreshold.z * rq * rq;
/* Combine and apply the brightness response curve. */
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl
index 57027c71156..688ae4915e1 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_resolve_frag.glsl
@@ -142,7 +142,7 @@ void dof_resolve_load_layer(sampler2D color_tex,
out float out_weight)
{
vec2 pixel_co = gl_FragCoord.xy / 2.0;
- vec2 uv = pixel_co / textureSize(color_tex, 0).xy;
+ vec2 uv = pixel_co / vec2(textureSize(color_tex, 0).xy);
out_color = textureLod(color_tex, uv, 0.0);
out_weight = textureLod(weight_tex, uv, 0.0).r;
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl
index b05223e755d..51a351babd3 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_scatter_vert.glsl
@@ -95,7 +95,7 @@ void main()
weights = dof_layer_weight(cocs) * dof_sample_weight(cocs);
/* Filter NaNs. */
- weights = mix(weights, vec4(0.0), equal(cocs, vec4(0.0)));
+ weights = select(weights, vec4(0.0), equal(cocs, vec4(0.0)));
color1 = colors[0] * weights[0];
color2 = colors[1] * weights[1];
diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_setup_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_setup_frag.glsl
index 235145b221b..178ef46862b 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_dof_setup_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_dof_setup_frag.glsl
@@ -54,12 +54,12 @@ void main()
bvec4 focus = lessThanEqual(cocs, vec4(0.5));
if (any(defocus) && any(focus)) {
/* For the same reason as in the flatten pass. This is a case we cannot optimize for. */
- cocs = mix(cocs, vec4(DOF_TILE_MIXED), focus);
- cocs = mix(cocs, vec4(DOF_TILE_MIXED), defocus);
+ cocs = select(cocs, vec4(DOF_TILE_MIXED), focus);
+ cocs = select(cocs, vec4(DOF_TILE_MIXED), defocus);
}
else {
- cocs = mix(cocs, vec4(DOF_TILE_FOCUS), focus);
- cocs = mix(cocs, vec4(DOF_TILE_DEFOCUS), defocus);
+ cocs = select(cocs, vec4(DOF_TILE_FOCUS), focus);
+ cocs = select(cocs, vec4(DOF_TILE_DEFOCUS), defocus);
}
outCoc.y = max_v4(cocs);
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
index ce455123987..aaf673eecd2 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl
@@ -38,7 +38,7 @@ uniform vec2 texelSize;
/* On some AMD card / driver combination, it is needed otherwise,
* the shader does not write anything. */
-#if defined(GPU_INTEL) || defined(GPU_ATI)
+#if (defined(GPU_INTEL) || defined(GPU_ATI)) && defined(GPU_OPENGL)
out vec4 fragColor;
#endif
@@ -68,9 +68,14 @@ void main()
float val = minmax4(samp.x, samp.y, samp.z, samp.w);
#endif
-#if defined(GPU_INTEL) || defined(GPU_ATI)
+#if (defined(GPU_INTEL) || defined(GPU_ATI)) && defined(GPU_OPENGL)
/* Use color format instead of 24bit depth texture */
fragColor = vec4(val);
#endif
+
+#if !(defined(GPU_INTEL) && defined(GPU_OPENGL))
+ /* If using Intel workaround, do not write out depth as there will be no depth target and this is
+ * invalid. */
gl_FragDepth = val;
+#endif
}
diff --git a/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl
index f4ff28eaee4..c9010749060 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_reflection_trace_frag.glsl
@@ -60,11 +60,11 @@ void main()
vec3 P = transform_point(ViewMatrixInverse, vP);
vec3 vV = viewCameraVec(vP);
vec3 V = cameraVec(P);
- vec3 vN = normal_decode(texture(normalBuffer, uvs, 0).rg, vV);
+ vec3 vN = normal_decode(textureLod(normalBuffer, uvs, 0.0).rg, vV);
vec3 N = transform_direction(ViewMatrixInverse, vN);
/* Retrieve pixel data */
- vec4 speccol_roughness = texture(specroughBuffer, uvs, 0).rgba;
+ vec4 speccol_roughness = textureLod(specroughBuffer, uvs, 0.0).rgba;
/* Early out */
if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) {
diff --git a/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl
index 300477570d0..fc8091161d7 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_velocity_tile_frag.glsl
@@ -74,7 +74,7 @@ bool neighbor_affect_this_tile(ivec2 offset, vec2 velocity)
* offset. If the offset coordinate is zero then
* velocity is irrelevant.
*/
- vec2 point = sign(offset * velocity);
+ vec2 point = sign(vec2(offset) * velocity);
float dist = (point.x + point.y);
/**
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
index 84626eac4cf..e1035af37be 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl
@@ -289,7 +289,7 @@ vec3 probe_evaluate_grid(GridData gd, vec3 P, vec3 N, vec3 localpos)
weight += prbIrradianceSmooth;
/* Trilinear weights */
- vec3 trilinear = mix(1.0 - trilinear_weight, trilinear_weight, offset);
+ vec3 trilinear = mix(1.0 - trilinear_weight, trilinear_weight, vec3(offset));
weight *= trilinear.x * trilinear.y * trilinear.z;
/* Avoid zero weight */
diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl
index cf44a04b707..5674e464f4c 100644
--- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_frag.glsl
@@ -16,11 +16,11 @@ void main()
{
#if 0
/* Reconstructing Target uvs like this avoid missing pixels if NPO2 */
- vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0));
+ vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0).xy);
FragColor = textureLod(source, vec3(uvs, layer), 0.0);
#else
- vec2 texel_size = 1.0 / vec2(textureSize(source, 0));
+ vec2 texel_size = 1.0 / vec2(textureSize(source, 0).xy);
vec2 uvs = gl_FragCoord.xy * 2.0 * texel_size;
vec4 ofs = texel_size.xyxy * vec4(0.75, 0.75, -0.75, -0.75);
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
index 25661a0d731..9f1afc4767c 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_frag.glsl
@@ -31,7 +31,7 @@ layout(location = 3) out vec4 volumePhase;
void main()
{
- ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice);
+ ivec3 volume_cell = ivec3(ivec2(gl_FragCoord.xy), slice);
vec3 ndc_cell = volume_to_ndc((vec3(volume_cell) + volJitter.xyz) * volInvTexSize.xyz);
viewPosition = get_view_space_from_depth(ndc_cell.xy, ndc_cell.z);
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
index 12b7d8acbea..11f57c0a82e 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_integration_frag.glsl
@@ -52,7 +52,7 @@ void main()
ivec2 texco = ivec2(gl_FragCoord.xy);
#endif
for (int i = 0; i <= slice; i++) {
- ivec3 volume_cell = ivec3(gl_FragCoord.xy, i);
+ ivec3 volume_cell = ivec3(ivec2(gl_FragCoord.xy), i);
vec3 Lscat = texelFetch(volumeScattering, volume_cell, 0).rgb;
vec3 s_extinction = texelFetch(volumeExtinction, volume_cell, 0).rgb;
diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
index dc755aeab8b..df3f92966e6 100644
--- a/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/volumetric_scatter_frag.glsl
@@ -22,7 +22,7 @@ layout(location = 1) out vec4 outTransmittance;
void main()
{
- ivec3 volume_cell = ivec3(gl_FragCoord.xy, slice);
+ ivec3 volume_cell = ivec3(ivec2(gl_FragCoord.xy), slice);
/* Emission */
outScattering = texelFetch(volumeEmission, volume_cell, 0);
diff --git a/source/blender/draw/engines/eevee_next/eevee_engine.cc b/source/blender/draw/engines/eevee_next/eevee_engine.cc
new file mode 100644
index 00000000000..390ab1f3e50
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_engine.cc
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2021 Blender Foundation.
+ */
+
+#include "BKE_global.h"
+#include "BLI_rect.h"
+
+#include "GPU_framebuffer.h"
+
+#include "ED_view3d.h"
+
+#include "DRW_render.h"
+
+struct EEVEE_Data {
+ DrawEngineType *engine_type;
+ DRWViewportEmptyList *fbl;
+ DRWViewportEmptyList *txl;
+ DRWViewportEmptyList *psl;
+ DRWViewportEmptyList *stl;
+ void *instance;
+};
+
+static void eevee_engine_init(void *vedata)
+{
+ UNUSED_VARS(vedata);
+}
+
+static void eevee_draw_scene(void *vedata)
+{
+ UNUSED_VARS(vedata);
+}
+
+static void eevee_cache_init(void *vedata)
+{
+ UNUSED_VARS(vedata);
+}
+
+static void eevee_cache_populate(void *vedata, Object *object)
+{
+ UNUSED_VARS(vedata, object);
+}
+
+static void eevee_cache_finish(void *vedata)
+{
+ UNUSED_VARS(vedata);
+}
+
+static void eevee_engine_free()
+{
+}
+
+static void eevee_instance_free(void *instance)
+{
+ UNUSED_VARS(instance);
+}
+
+static void eevee_render_to_image(void *UNUSED(vedata),
+ struct RenderEngine *engine,
+ struct RenderLayer *layer,
+ const struct rcti *UNUSED(rect))
+{
+ UNUSED_VARS(engine, layer);
+}
+
+static void eevee_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer)
+{
+ UNUSED_VARS(engine, scene, view_layer);
+}
+
+static const DrawEngineDataSize eevee_data_size = DRW_VIEWPORT_DATA_SIZE(EEVEE_Data);
+
+extern "C" {
+
+DrawEngineType draw_engine_eevee_next_type = {
+ nullptr,
+ nullptr,
+ N_("Eevee"),
+ &eevee_data_size,
+ &eevee_engine_init,
+ &eevee_engine_free,
+ &eevee_instance_free,
+ &eevee_cache_init,
+ &eevee_cache_populate,
+ &eevee_cache_finish,
+ &eevee_draw_scene,
+ nullptr,
+ nullptr,
+ &eevee_render_to_image,
+ nullptr,
+};
+
+RenderEngineType DRW_engine_viewport_eevee_next_type = {
+ nullptr,
+ nullptr,
+ "BLENDER_EEVEE_NEXT",
+ N_("Eevee Next"),
+ RE_INTERNAL | RE_USE_PREVIEW | RE_USE_STEREO_VIEWPORT | RE_USE_GPU_CONTEXT,
+ nullptr,
+ &DRW_render_to_image,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &eevee_render_update_passes,
+ &draw_engine_eevee_next_type,
+ {nullptr, nullptr, nullptr},
+};
+}
diff --git a/source/blender/draw/engines/eevee_next/eevee_engine.h b/source/blender/draw/engines/eevee_next/eevee_engine.h
new file mode 100644
index 00000000000..9cee11bbba8
--- /dev/null
+++ b/source/blender/draw/engines/eevee_next/eevee_engine.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2016 Blender Foundation. */
+
+/** \file
+ * \ingroup DNA
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern DrawEngineType draw_engine_eevee_next_type;
+extern RenderEngineType DRW_engine_viewport_eevee_next_type;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
index eec38f98788..be35660a4d7 100644
--- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -268,9 +268,9 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
!BLI_listbase_is_empty(&gpl->mask_layers);
float vert_col_opacity = (override_vertcol) ?
- (is_vert_col_mode ? pd->vertex_paint_opacity : 0.0f) :
- pd->is_render ? gpl->vertex_paint_opacity :
- pd->vertex_paint_opacity;
+ (is_vert_col_mode ? pd->vertex_paint_opacity : 0.0f) :
+ (pd->is_render ? gpl->vertex_paint_opacity :
+ pd->vertex_paint_opacity);
/* Negate thickness sign to tag that strokes are in screen space.
* Convert to world units (by default, 1 meter = 2000 pixels). */
float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / GPENCIL_PIXEL_FACTOR);
@@ -388,13 +388,11 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
DRW_shgroup_uniform_texture(grp, "gpSceneDepthTexture", depth_tex);
DRW_shgroup_uniform_texture_ref(grp, "gpMaskTexture", mask_tex);
DRW_shgroup_uniform_vec3_copy(grp, "gpNormal", tgp_ob->plane_normal);
- DRW_shgroup_uniform_bool_copy(grp, "strokeOrder3d", tgp_ob->is_drawmode3d);
- DRW_shgroup_uniform_float_copy(grp, "thicknessScale", tgp_ob->object_scale);
- DRW_shgroup_uniform_vec2_copy(grp, "sizeViewportInv", DRW_viewport_invert_size_get());
- DRW_shgroup_uniform_vec2_copy(grp, "sizeViewport", DRW_viewport_size_get());
- DRW_shgroup_uniform_float_copy(grp, "thicknessOffset", (float)gpl->line_change);
- DRW_shgroup_uniform_float_copy(grp, "thicknessWorldScale", thickness_scale);
- DRW_shgroup_uniform_float_copy(grp, "vertexColorOpacity", vert_col_opacity);
+ DRW_shgroup_uniform_bool_copy(grp, "gpStrokeOrder3d", tgp_ob->is_drawmode3d);
+ DRW_shgroup_uniform_float_copy(grp, "gpThicknessScale", tgp_ob->object_scale);
+ DRW_shgroup_uniform_float_copy(grp, "gpThicknessOffset", (float)gpl->line_change);
+ DRW_shgroup_uniform_float_copy(grp, "gpThicknessWorldScale", thickness_scale);
+ DRW_shgroup_uniform_float_copy(grp, "gpVertexColorOpacity", vert_col_opacity);
/* If random color type, need color by layer. */
float gpl_color[4];
@@ -403,9 +401,9 @@ GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
gpencil_layer_random_color_get(ob, gpl, gpl_color);
gpl_color[3] = 1.0f;
}
- DRW_shgroup_uniform_vec4_copy(grp, "layerTint", gpl_color);
+ DRW_shgroup_uniform_vec4_copy(grp, "gpLayerTint", gpl_color);
- DRW_shgroup_uniform_float_copy(grp, "layerOpacity", layer_alpha);
+ DRW_shgroup_uniform_float_copy(grp, "gpLayerOpacity", layer_alpha);
DRW_shgroup_stencil_mask(grp, 0xFF);
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_defines.h b/source/blender/draw/engines/gpencil/gpencil_defines.h
new file mode 100644
index 00000000000..6eb7bd23e4e
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_defines.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#define GPENCIL_MATERIAL_BUFFER_LEN 256
+
+#define GPENCIL_LIGHT_BUFFER_LEN 128
+
+/* High bits are used to pass material ID to fragment shader. */
+#define GPENCIl_MATID_SHIFT 16u
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
index c3f96ecd0a2..65ddb80ad55 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
@@ -58,7 +58,8 @@ static struct GPUTexture *gpencil_image_texture_get(Image *image, bool *r_alpha_
static void gpencil_uv_transform_get(const float ofs[2],
const float scale[2],
const float rotation,
- float r_uvmat[3][2])
+ float r_rot_scale[2][2],
+ float r_offset[2])
{
/* OPTI this could use 3x2 matrices and reduce the number of operations drastically. */
float mat[4][4];
@@ -70,9 +71,9 @@ static void gpencil_uv_transform_get(const float ofs[2],
rotate_m4(mat, 'Z', -rotation);
translate_m4(mat, ofs[0], ofs[1], 0.0f);
/* Convert to 3x2 */
- copy_v2_v2(r_uvmat[0], mat[0]);
- copy_v2_v2(r_uvmat[1], mat[1]);
- copy_v2_v2(r_uvmat[2], mat[3]);
+ copy_v2_v2(r_rot_scale[0], mat[0]);
+ copy_v2_v2(r_rot_scale[1], mat[1]);
+ copy_v2_v2(r_offset, mat[3]);
}
static void gpencil_shade_color(float color[3])
@@ -167,7 +168,7 @@ GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Obje
int mat_len = max_ii(1, BKE_object_material_count_eval(ob));
- bool reuse_matpool = matpool && ((matpool->used_count + mat_len) <= GP_MATERIAL_BUFFER_LEN);
+ bool reuse_matpool = matpool && ((matpool->used_count + mat_len) <= GPENCIL_MATERIAL_BUFFER_LEN);
if (reuse_matpool) {
/* Share the matpool with other objects. Return offset to first material. */
@@ -188,7 +189,7 @@ GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Obje
GPENCIL_MaterialPool *pool = matpool;
for (int i = 0; i < mat_len; i++) {
- if ((i > 0) && (pool->used_count == GP_MATERIAL_BUFFER_LEN)) {
+ if ((i > 0) && (pool->used_count == GPENCIL_MATERIAL_BUFFER_LEN)) {
pool->next = gpencil_material_pool_add(pd);
pool = pool->next;
}
@@ -235,8 +236,8 @@ GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Obje
gp_style = gpencil_viewport_material_overrides(pd, ob, color_type, gp_style, lighting_mode);
/* Dots or Squares rotation. */
- mat_data->alignment_rot_cos = cosf(gp_style->alignment_rotation);
- mat_data->alignment_rot_sin = sinf(gp_style->alignment_rotation);
+ mat_data->alignment_rot[0] = cosf(gp_style->alignment_rotation);
+ mat_data->alignment_rot[1] = sinf(gp_style->alignment_rotation);
/* Stroke Style */
if ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && (gp_style->sima)) {
@@ -266,7 +267,8 @@ GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Obje
gpencil_uv_transform_get(gp_style->texture_offset,
gp_style->texture_scale,
gp_style->texture_angle,
- mat_data->fill_uv_transform);
+ (float(*)[2])mat_data->fill_uv_rot_scale,
+ mat_data->fill_uv_offset);
copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba);
mat_data->fill_texture_mix = 1.0f - gp_style->mix_factor;
}
@@ -278,7 +280,8 @@ GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Obje
gpencil_uv_transform_get(gp_style->texture_offset,
gp_style->texture_scale,
gp_style->texture_angle,
- mat_data->fill_uv_transform);
+ (float(*)[2])mat_data->fill_uv_rot_scale,
+ mat_data->fill_uv_offset);
copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba);
copy_v4_v4(mat_data->fill_mix_color, gp_style->mix_rgba);
mat_data->fill_texture_mix = 1.0f - gp_style->mix_factor;
@@ -303,11 +306,11 @@ void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool,
GPUUniformBuf **r_ubo_mat)
{
GPENCIL_MaterialPool *matpool = first_pool;
- int pool_id = mat_id / GP_MATERIAL_BUFFER_LEN;
+ int pool_id = mat_id / GPENCIL_MATERIAL_BUFFER_LEN;
for (int i = 0; i < pool_id; i++) {
matpool = matpool->next;
}
- mat_id = mat_id % GP_MATERIAL_BUFFER_LEN;
+ mat_id = mat_id % GPENCIL_MATERIAL_BUFFER_LEN;
*r_ubo_mat = matpool->ubo;
if (r_tex_fill) {
*r_tex_fill = matpool->tex_fill[mat_id];
@@ -379,16 +382,16 @@ void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob)
if (la->type == LA_SPOT) {
copy_m4_m4(mat, ob->imat);
gp_light->type = GP_LIGHT_TYPE_SPOT;
- gp_light->spotsize = cosf(la->spotsize * 0.5f);
- gp_light->spotblend = (1.0f - gp_light->spotsize) * la->spotblend;
+ gp_light->spot_size = cosf(la->spotsize * 0.5f);
+ gp_light->spot_blend = (1.0f - gp_light->spot_size) * la->spotblend;
}
else if (la->type == LA_AREA) {
/* Simulate area lights using a spot light. */
normalize_m4_m4(mat, ob->obmat);
invert_m4(mat);
gp_light->type = GP_LIGHT_TYPE_SPOT;
- gp_light->spotsize = cosf(M_PI_2);
- gp_light->spotblend = (1.0f - gp_light->spotsize) * 1.0f;
+ gp_light->spot_size = cosf(M_PI_2);
+ gp_light->spot_blend = (1.0f - gp_light->spot_size) * 1.0f;
}
else if (la->type == LA_SUN) {
normalize_v3_v3(gp_light->forward, ob->obmat[2]);
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index b7bba35e298..585a508d9ce 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -276,7 +276,7 @@ void GPENCIL_cache_init(void *ved)
GPUShader *sh = GPENCIL_shader_depth_merge_get();
grp = DRW_shgroup_create(sh, psl->merge_depth_ps);
DRW_shgroup_uniform_texture_ref(grp, "depthBuf", &pd->depth_tx);
- DRW_shgroup_uniform_bool(grp, "strokeOrder3d", &pd->is_stroke_order_3d, 1);
+ DRW_shgroup_uniform_bool(grp, "gpStrokeOrder3d", &pd->is_stroke_order_3d, 1);
DRW_shgroup_uniform_vec4(grp, "gpModelMatrix", pd->object_bound_mat[0], 4);
DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
@@ -405,8 +405,8 @@ static void gpencil_sbuffer_cache_populate(gpIterPopulateData *iter)
* Remember, sbuffer stroke indices start from 0. So we add last index to avoid
* masking issues. */
iter->grp = DRW_shgroup_create_sub(iter->grp);
- DRW_shgroup_uniform_block(iter->grp, "gpMaterialBlock", iter->ubo_mat);
- DRW_shgroup_uniform_float_copy(iter->grp, "strokeIndexOffset", iter->stroke_index_last);
+ DRW_shgroup_uniform_block(iter->grp, "materials", iter->ubo_mat);
+ DRW_shgroup_uniform_float_copy(iter->grp, "gpStrokeIndexOffset", iter->stroke_index_last);
const DRWContextState *ctx = DRW_context_state_get();
ToolSettings *ts = ctx->scene->toolsettings;
@@ -453,12 +453,12 @@ static void gpencil_layer_cache_populate(bGPDlayer *gpl,
/* Iterator dependent uniforms. */
DRWShadingGroup *grp = iter->grp = tgp_layer->base_shgrp;
- DRW_shgroup_uniform_block(grp, "gpLightBlock", iter->ubo_lights);
- DRW_shgroup_uniform_block(grp, "gpMaterialBlock", iter->ubo_mat);
+ DRW_shgroup_uniform_block(grp, "lights", iter->ubo_lights);
+ DRW_shgroup_uniform_block(grp, "materials", iter->ubo_mat);
DRW_shgroup_uniform_texture(grp, "gpFillTexture", iter->tex_fill);
DRW_shgroup_uniform_texture(grp, "gpStrokeTexture", iter->tex_stroke);
DRW_shgroup_uniform_int_copy(grp, "gpMaterialOffset", iter->mat_ofs);
- DRW_shgroup_uniform_float_copy(grp, "strokeIndexOffset", iter->stroke_index_offset);
+ DRW_shgroup_uniform_float_copy(grp, "gpStrokeIndexOffset", iter->stroke_index_offset);
}
static void gpencil_stroke_cache_populate(bGPDlayer *gpl,
@@ -500,7 +500,7 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl,
iter->grp = DRW_shgroup_create_sub(iter->grp);
if (iter->ubo_mat != ubo_mat) {
- DRW_shgroup_uniform_block(iter->grp, "gpMaterialBlock", ubo_mat);
+ DRW_shgroup_uniform_block(iter->grp, "materials", ubo_mat);
iter->ubo_mat = ubo_mat;
}
if (tex_fill) {
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 9ef558c7a75..332c7f67c64 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -19,6 +19,9 @@
extern "C" {
#endif
+#include "gpencil_defines.h"
+#include "gpencil_shader_shared.h"
+
extern DrawEngineType draw_engine_gpencil_type;
struct GPENCIL_Data;
@@ -39,69 +42,17 @@ struct bGPDstroke;
#define GP_MAX_MASKBITS 256
-/* UBO structure. Watch out for padding. Must match GLSL declaration. */
-typedef struct gpMaterial {
- float stroke_color[4];
- float fill_color[4];
- float fill_mix_color[4];
- float fill_uv_transform[3][2], alignment_rot_cos, alignment_rot_sin;
- float stroke_texture_mix;
- float stroke_u_scale;
- float fill_texture_mix;
- int flag;
-} gpMaterial;
-
-/* gpMaterial->flag */
-/* WATCH Keep in sync with GLSL declaration. */
-#define GP_STROKE_ALIGNMENT_STROKE 1
-#define GP_STROKE_ALIGNMENT_OBJECT 2
-#define GP_STROKE_ALIGNMENT_FIXED 3
-#define GP_STROKE_ALIGNMENT 0x3
-#define GP_STROKE_OVERLAP (1 << 2)
-#define GP_STROKE_TEXTURE_USE (1 << 3)
-#define GP_STROKE_TEXTURE_STENCIL (1 << 4)
-#define GP_STROKE_TEXTURE_PREMUL (1 << 5)
-#define GP_STROKE_DOTS (1 << 6)
-#define GP_STROKE_HOLDOUT (1 << 7)
-#define GP_FILL_HOLDOUT (1 << 8)
-#define GP_FILL_TEXTURE_USE (1 << 10)
-#define GP_FILL_TEXTURE_PREMUL (1 << 11)
-#define GP_FILL_TEXTURE_CLIP (1 << 12)
-#define GP_FILL_GRADIENT_USE (1 << 13)
-#define GP_FILL_GRADIENT_RADIAL (1 << 14)
-
-#define GPENCIL_LIGHT_BUFFER_LEN 128
-
-/* UBO structure. Watch out for padding. Must match GLSL declaration. */
-typedef struct gpLight {
- float color[3], type;
- float right[3], spotsize;
- float up[3], spotblend;
- float forward[4];
- float position[4];
-} gpLight;
-
-/* gpLight->type */
-/* WATCH Keep in sync with GLSL declaration. */
-#define GP_LIGHT_TYPE_POINT 0.0
-#define GP_LIGHT_TYPE_SPOT 1.0
-#define GP_LIGHT_TYPE_SUN 2.0
-#define GP_LIGHT_TYPE_AMBIENT 3.0
-
-BLI_STATIC_ASSERT_ALIGN(gpMaterial, 16)
-BLI_STATIC_ASSERT_ALIGN(gpLight, 16)
-
/* *********** Draw Data *********** */
typedef struct GPENCIL_MaterialPool {
/* Single linked-list. */
struct GPENCIL_MaterialPool *next;
/* GPU representation of materials. */
- gpMaterial mat_data[GP_MATERIAL_BUFFER_LEN];
+ gpMaterial mat_data[GPENCIL_MATERIAL_BUFFER_LEN];
/* Matching ubo. */
struct GPUUniformBuf *ubo;
/* Texture per material. NULL means none. */
- struct GPUTexture *tex_fill[GP_MATERIAL_BUFFER_LEN];
- struct GPUTexture *tex_stroke[GP_MATERIAL_BUFFER_LEN];
+ struct GPUTexture *tex_fill[GPENCIL_MATERIAL_BUFFER_LEN];
+ struct GPUTexture *tex_stroke[GPENCIL_MATERIAL_BUFFER_LEN];
/* Number of material used in this pool. */
int used_count;
} GPENCIL_MaterialPool;
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader.c b/source/blender/draw/engines/gpencil/gpencil_shader.c
index d61bbe146d4..dd12fcc70d8 100644
--- a/source/blender/draw/engines/gpencil/gpencil_shader.c
+++ b/source/blender/draw/engines/gpencil/gpencil_shader.c
@@ -46,18 +46,6 @@ static struct {
GPUShader *fx_rim_sh;
GPUShader *fx_shadow_sh;
GPUShader *fx_transform_sh;
- /* general drawing shaders */
- GPUShader *gpencil_fill_sh;
- GPUShader *gpencil_stroke_sh;
- GPUShader *gpencil_point_sh;
- GPUShader *gpencil_edit_point_sh;
- GPUShader *gpencil_line_sh;
- GPUShader *gpencil_drawing_fill_sh;
- GPUShader *gpencil_fullscreen_sh;
- GPUShader *gpencil_simple_fullscreen_sh;
- GPUShader *gpencil_blend_fullscreen_sh;
- GPUShader *gpencil_background_sh;
- GPUShader *gpencil_paper_sh;
} g_shaders = {{NULL}};
void GPENCIL_shader_free(void)
@@ -78,17 +66,6 @@ void GPENCIL_shader_free(void)
DRW_SHADER_FREE_SAFE(g_shaders.fx_rim_sh);
DRW_SHADER_FREE_SAFE(g_shaders.fx_shadow_sh);
DRW_SHADER_FREE_SAFE(g_shaders.fx_transform_sh);
- DRW_SHADER_FREE_SAFE(g_shaders.gpencil_fill_sh);
- DRW_SHADER_FREE_SAFE(g_shaders.gpencil_stroke_sh);
- DRW_SHADER_FREE_SAFE(g_shaders.gpencil_point_sh);
- DRW_SHADER_FREE_SAFE(g_shaders.gpencil_edit_point_sh);
- DRW_SHADER_FREE_SAFE(g_shaders.gpencil_line_sh);
- DRW_SHADER_FREE_SAFE(g_shaders.gpencil_drawing_fill_sh);
- DRW_SHADER_FREE_SAFE(g_shaders.gpencil_fullscreen_sh);
- DRW_SHADER_FREE_SAFE(g_shaders.gpencil_simple_fullscreen_sh);
- DRW_SHADER_FREE_SAFE(g_shaders.gpencil_blend_fullscreen_sh);
- DRW_SHADER_FREE_SAFE(g_shaders.gpencil_background_sh);
- DRW_SHADER_FREE_SAFE(g_shaders.gpencil_paper_sh);
}
GPUShader *GPENCIL_shader_antialiasing(int stage)
@@ -96,40 +73,9 @@ GPUShader *GPENCIL_shader_antialiasing(int stage)
BLI_assert(stage < 3);
if (!g_shaders.antialiasing_sh[stage]) {
- char stage_define[32];
- BLI_snprintf(stage_define, sizeof(stage_define), "#define SMAA_STAGE %d\n", stage);
-
- g_shaders.antialiasing_sh[stage] = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){
- "#define SMAA_INCLUDE_VS 1\n",
- "#define SMAA_INCLUDE_PS 0\n",
- "uniform vec4 viewportMetrics;\n",
- datatoc_common_smaa_lib_glsl,
- datatoc_gpencil_antialiasing_vert_glsl,
- NULL,
- },
- .frag =
- (const char *[]){
- "#define SMAA_INCLUDE_VS 0\n",
- "#define SMAA_INCLUDE_PS 1\n",
- "uniform vec4 viewportMetrics;\n",
- datatoc_common_smaa_lib_glsl,
- datatoc_gpencil_antialiasing_frag_glsl,
- NULL,
- },
- .defs =
- (const char *[]){
- "uniform float lumaWeight;\n",
- "#define SMAA_GLSL_3\n",
- "#define SMAA_RT_METRICS viewportMetrics\n",
- "#define SMAA_PRESET_HIGH\n",
- "#define SMAA_LUMA_WEIGHT float4(lumaWeight, lumaWeight, lumaWeight, 0.0)\n",
- "#define SMAA_NO_DISCARD\n",
- stage_define,
- NULL,
- },
- });
+ char stage_info_name[32];
+ SNPRINTF(stage_info_name, "gpencil_antialiasing_stage_%d", stage);
+ g_shaders.antialiasing_sh[stage] = GPU_shader_create_from_info_name(stage_info_name);
}
return g_shaders.antialiasing_sh[stage];
}
@@ -137,29 +83,7 @@ GPUShader *GPENCIL_shader_antialiasing(int stage)
GPUShader *GPENCIL_shader_geometry_get(void)
{
if (!g_shaders.gpencil_sh) {
- g_shaders.gpencil_sh = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){
- datatoc_common_view_lib_glsl,
- datatoc_gpencil_common_lib_glsl,
- datatoc_gpencil_vert_glsl,
- NULL,
- },
- .frag =
- (const char *[]){
- datatoc_common_colormanagement_lib_glsl,
- datatoc_gpencil_common_lib_glsl,
- datatoc_gpencil_frag_glsl,
- NULL,
- },
- .defs =
- (const char *[]){
- "#define GP_MATERIAL_BUFFER_LEN " STRINGIFY(GP_MATERIAL_BUFFER_LEN) "\n",
- "#define GPENCIL_LIGHT_BUFFER_LEN " STRINGIFY(GPENCIL_LIGHT_BUFFER_LEN) "\n",
- "#define UNIFORM_RESOURCE_ID\n",
- NULL,
- },
- });
+ g_shaders.gpencil_sh = GPU_shader_create_from_info_name("gpencil_geometry");
}
return g_shaders.gpencil_sh;
}
@@ -167,19 +91,7 @@ GPUShader *GPENCIL_shader_geometry_get(void)
GPUShader *GPENCIL_shader_layer_blend_get(void)
{
if (!g_shaders.layer_blend_sh) {
- g_shaders.layer_blend_sh = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){
- datatoc_common_fullscreen_vert_glsl,
- NULL,
- },
- .frag =
- (const char *[]){
- datatoc_gpencil_common_lib_glsl,
- datatoc_gpencil_layer_blend_frag_glsl,
- NULL,
- },
- });
+ g_shaders.layer_blend_sh = GPU_shader_create_from_info_name("gpencil_layer_blend");
}
return g_shaders.layer_blend_sh;
}
@@ -187,8 +99,7 @@ GPUShader *GPENCIL_shader_layer_blend_get(void)
GPUShader *GPENCIL_shader_mask_invert_get(void)
{
if (!g_shaders.mask_invert_sh) {
- g_shaders.mask_invert_sh = DRW_shader_create_fullscreen(datatoc_gpencil_mask_invert_frag_glsl,
- NULL);
+ g_shaders.mask_invert_sh = GPU_shader_create_from_info_name("gpencil_mask_invert");
}
return g_shaders.mask_invert_sh;
}
@@ -196,19 +107,7 @@ GPUShader *GPENCIL_shader_mask_invert_get(void)
GPUShader *GPENCIL_shader_depth_merge_get(void)
{
if (!g_shaders.depth_merge_sh) {
- g_shaders.depth_merge_sh = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){
- datatoc_common_view_lib_glsl,
- datatoc_gpencil_depth_merge_vert_glsl,
- NULL,
- },
- .frag =
- (const char *[]){
- datatoc_gpencil_depth_merge_frag_glsl,
- NULL,
- },
- });
+ g_shaders.depth_merge_sh = GPU_shader_create_from_info_name("gpencil_depth_merge");
}
return g_shaders.depth_merge_sh;
}
@@ -218,8 +117,7 @@ GPUShader *GPENCIL_shader_depth_merge_get(void)
GPUShader *GPENCIL_shader_fx_blur_get(void)
{
if (!g_shaders.fx_blur_sh) {
- g_shaders.fx_blur_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
- "#define BLUR\n");
+ g_shaders.fx_blur_sh = GPU_shader_create_from_info_name("gpencil_fx_blur");
}
return g_shaders.fx_blur_sh;
}
@@ -227,8 +125,7 @@ GPUShader *GPENCIL_shader_fx_blur_get(void)
GPUShader *GPENCIL_shader_fx_colorize_get(void)
{
if (!g_shaders.fx_colorize_sh) {
- g_shaders.fx_colorize_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
- "#define COLORIZE\n");
+ g_shaders.fx_colorize_sh = GPU_shader_create_from_info_name("gpencil_fx_colorize");
}
return g_shaders.fx_colorize_sh;
}
@@ -236,8 +133,7 @@ GPUShader *GPENCIL_shader_fx_colorize_get(void)
GPUShader *GPENCIL_shader_fx_composite_get(void)
{
if (!g_shaders.fx_composite_sh) {
- g_shaders.fx_composite_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
- "#define COMPOSITE\n");
+ g_shaders.fx_composite_sh = GPU_shader_create_from_info_name("gpencil_fx_composite");
}
return g_shaders.fx_composite_sh;
}
@@ -245,24 +141,7 @@ GPUShader *GPENCIL_shader_fx_composite_get(void)
GPUShader *GPENCIL_shader_fx_glow_get(void)
{
if (!g_shaders.fx_glow_sh) {
- g_shaders.fx_glow_sh = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){
- datatoc_common_fullscreen_vert_glsl,
- NULL,
- },
- .frag =
- (const char *[]){
- datatoc_gpencil_common_lib_glsl,
- datatoc_gpencil_vfx_frag_glsl,
- NULL,
- },
- .defs =
- (const char *[]){
- "#define GLOW\n",
- NULL,
- },
- });
+ g_shaders.fx_glow_sh = GPU_shader_create_from_info_name("gpencil_fx_glow");
}
return g_shaders.fx_glow_sh;
}
@@ -270,8 +149,7 @@ GPUShader *GPENCIL_shader_fx_glow_get(void)
GPUShader *GPENCIL_shader_fx_pixelize_get(void)
{
if (!g_shaders.fx_pixel_sh) {
- g_shaders.fx_pixel_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
- "#define PIXELIZE\n");
+ g_shaders.fx_pixel_sh = GPU_shader_create_from_info_name("gpencil_fx_pixelize");
}
return g_shaders.fx_pixel_sh;
}
@@ -279,24 +157,7 @@ GPUShader *GPENCIL_shader_fx_pixelize_get(void)
GPUShader *GPENCIL_shader_fx_rim_get(void)
{
if (!g_shaders.fx_rim_sh) {
- g_shaders.fx_rim_sh = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){
- datatoc_common_fullscreen_vert_glsl,
- NULL,
- },
- .frag =
- (const char *[]){
- datatoc_gpencil_common_lib_glsl,
- datatoc_gpencil_vfx_frag_glsl,
- NULL,
- },
- .defs =
- (const char *[]){
- "#define RIM\n",
- NULL,
- },
- });
+ g_shaders.fx_rim_sh = GPU_shader_create_from_info_name("gpencil_fx_rim");
}
return g_shaders.fx_rim_sh;
}
@@ -304,8 +165,7 @@ GPUShader *GPENCIL_shader_fx_rim_get(void)
GPUShader *GPENCIL_shader_fx_shadow_get(void)
{
if (!g_shaders.fx_shadow_sh) {
- g_shaders.fx_shadow_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
- "#define SHADOW\n");
+ g_shaders.fx_shadow_sh = GPU_shader_create_from_info_name("gpencil_fx_shadow");
}
return g_shaders.fx_shadow_sh;
}
@@ -313,8 +173,7 @@ GPUShader *GPENCIL_shader_fx_shadow_get(void)
GPUShader *GPENCIL_shader_fx_transform_get(void)
{
if (!g_shaders.fx_transform_sh) {
- g_shaders.fx_transform_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
- "#define TRANSFORM\n");
+ g_shaders.fx_transform_sh = GPU_shader_create_from_info_name("gpencil_fx_transform");
}
return g_shaders.fx_transform_sh;
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_shared.h b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h
new file mode 100644
index 00000000000..889652c739b
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_shader_shared.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef GPU_SHADER
+# include "GPU_shader_shared_utils.h"
+
+typedef struct gpMaterial gpMaterial;
+typedef struct gpLight gpLight;
+typedef enum gpMaterialFlag gpMaterialFlag;
+typedef enum gpLightType gpLightType;
+#endif
+
+enum gpMaterialFlag {
+ GP_STROKE_ALIGNMENT_STROKE = 1u,
+ GP_STROKE_ALIGNMENT_OBJECT = 2u,
+ GP_STROKE_ALIGNMENT_FIXED = 3u,
+ GP_STROKE_ALIGNMENT = 0x3u,
+ GP_STROKE_OVERLAP = (1u << 2u),
+ GP_STROKE_TEXTURE_USE = (1u << 3u),
+ GP_STROKE_TEXTURE_STENCIL = (1u << 4u),
+ GP_STROKE_TEXTURE_PREMUL = (1u << 5u),
+ GP_STROKE_DOTS = (1u << 6u),
+ GP_STROKE_HOLDOUT = (1u << 7u),
+ GP_FILL_HOLDOUT = (1u << 8u),
+ GP_FILL_TEXTURE_USE = (1u << 10u),
+ GP_FILL_TEXTURE_PREMUL = (1u << 11u),
+ GP_FILL_TEXTURE_CLIP = (1u << 12u),
+ GP_FILL_GRADIENT_USE = (1u << 13u),
+ GP_FILL_GRADIENT_RADIAL = (1u << 14u),
+ GP_FILL_FLAGS = (GP_FILL_TEXTURE_USE | GP_FILL_TEXTURE_PREMUL | GP_FILL_TEXTURE_CLIP |
+ GP_FILL_GRADIENT_USE | GP_FILL_GRADIENT_RADIAL | GP_FILL_HOLDOUT),
+};
+
+enum gpLightType {
+ GP_LIGHT_TYPE_POINT = 0u,
+ GP_LIGHT_TYPE_SPOT = 1u,
+ GP_LIGHT_TYPE_SUN = 2u,
+ GP_LIGHT_TYPE_AMBIENT = 3u,
+};
+
+/* Avoid compiler funkiness with enum types not being strongly typed in C. */
+#ifndef GPU_SHADER
+# define gpMaterialFlag uint
+# define gpLightType uint
+#endif
+
+struct gpMaterial {
+ float4 stroke_color;
+ float4 fill_color;
+ float4 fill_mix_color;
+ float4 fill_uv_rot_scale;
+#ifndef GPU_SHADER
+ float2 fill_uv_offset;
+ float2 alignment_rot;
+ float stroke_texture_mix;
+ float stroke_u_scale;
+ float fill_texture_mix;
+ gpMaterialFlag flag;
+#else
+ /* Some drivers are completely messing the alignment or the fetches here.
+ * We are forced to pack these into vec4 otherwise we only get 0.0 as value. */
+ /* NOTE(@fclem): This was the case on MacOS OpenGL implementation.
+ * This might be fixed in newer APIs. */
+ float4 packed1;
+ float4 packed2;
+# define _fill_uv_offset packed1.xy
+# define _alignment_rot packed1.zw
+# define _stroke_texture_mix packed2.x
+# define _stroke_u_scale packed2.y
+# define _fill_texture_mix packed2.z
+ /** NOTE(@fclem): Needs floatBitsToUint(). */
+# define _flag packed2.w
+#endif
+};
+BLI_STATIC_ASSERT_ALIGN(gpMaterial, 16)
+
+struct gpLight {
+#ifndef GPU_SHADER
+ float3 color;
+ gpLightType type;
+ float3 right;
+ float spot_size;
+ float3 up;
+ float spot_blend;
+ float3 forward;
+ float _pad0;
+ float3 position;
+ float _pad1;
+#else
+ /* Some drivers are completely messing the alignment or the fetches here.
+ * We are forced to pack these into vec4 otherwise we only get 0.0 as value. */
+ /* NOTE(@fclem): This was the case on MacOS OpenGL implementation.
+ * This might be fixed in newer APIs. */
+ float4 packed0;
+ float4 packed1;
+ float4 packed2;
+ float4 packed3;
+ float4 packed4;
+# define _color packed0.xyz
+# define _type packed0.w
+# define _right packed1.xyz
+# define _spot_size packed1.w
+# define _up packed2.xyz
+# define _spot_blend packed2.w
+# define _forward packed3.xyz
+# define _position packed4.xyz
+#endif
+};
+BLI_STATIC_ASSERT_ALIGN(gpLight, 16)
+
+#ifndef GPU_SHADER
+# undef gpMaterialFlag
+# undef gpLightType
+#endif
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl
index 7758fdceb46..bbea8747ed0 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl
@@ -1,64 +1,43 @@
-uniform sampler2D edgesTex;
-uniform sampler2D areaTex;
-uniform sampler2D searchTex;
-uniform sampler2D blendTex;
-uniform sampler2D colorTex;
-uniform sampler2D revealTex;
-uniform bool onlyAlpha;
-uniform bool doAntiAliasing;
-
-in vec2 uvs;
-in vec2 pixcoord;
-in vec4 offset[3];
-
-#if SMAA_STAGE == 0
-out vec2 fragColor;
-#elif SMAA_STAGE == 1
-out vec4 fragColor;
-#elif SMAA_STAGE == 2
-/* Reminder: Blending func is `fragRevealage * DST + fragColor`. */
-layout(location = 0, index = 0) out vec4 outColor;
-layout(location = 0, index = 1) out vec4 outReveal;
-#endif
+#pragma BLENDER_REQUIRE(common_smaa_lib.glsl)
void main()
{
#if SMAA_STAGE == 0
/* Detect edges in color and revealage buffer. */
- fragColor = SMAALumaEdgeDetectionPS(uvs, offset, colorTex);
- fragColor = max(fragColor, SMAALumaEdgeDetectionPS(uvs, offset, revealTex));
+ out_edges = SMAALumaEdgeDetectionPS(uvs, offset, colorTex);
+ out_edges = max(out_edges, SMAALumaEdgeDetectionPS(uvs, offset, revealTex));
/* Discard if there is no edge. */
- if (dot(fragColor, float2(1.0, 1.0)) == 0.0) {
+ if (dot(out_edges, float2(1.0, 1.0)) == 0.0) {
discard;
}
#elif SMAA_STAGE == 1
- fragColor = SMAABlendingWeightCalculationPS(
+ out_weights = SMAABlendingWeightCalculationPS(
uvs, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0));
#elif SMAA_STAGE == 2
/* Resolve both buffers. */
if (doAntiAliasing) {
- outColor = SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex);
- outReveal = SMAANeighborhoodBlendingPS(uvs, offset[0], revealTex, blendTex);
+ out_color = SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex);
+ out_reveal = SMAANeighborhoodBlendingPS(uvs, offset[0], revealTex, blendTex);
}
else {
- outColor = texture(colorTex, uvs);
- outReveal = texture(revealTex, uvs);
+ out_color = texture(colorTex, uvs);
+ out_reveal = texture(revealTex, uvs);
}
/* Revealage, how much light passes through. */
/* Average for alpha channel. */
- outReveal.a = clamp(dot(outReveal.rgb, vec3(0.333334)), 0.0, 1.0);
+ out_reveal.a = clamp(dot(out_reveal.rgb, vec3(0.333334)), 0.0, 1.0);
/* Color buf is already premultiplied. Just add it to the color. */
/* Add the alpha. */
- outColor.a = 1.0 - outReveal.a;
+ out_color.a = 1.0 - out_reveal.a;
if (onlyAlpha) {
/* Special case in wireframe xray mode. */
- outColor = vec4(0.0);
- outReveal.rgb = outReveal.aaa;
+ out_color = vec4(0.0);
+ out_reveal.rgb = out_reveal.aaa;
}
#endif
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl
index 07734d19972..b76433a23e5 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl
@@ -1,7 +1,5 @@
-out vec2 uvs;
-out vec2 pixcoord;
-out vec4 offset[3];
+#pragma BLENDER_REQUIRE(common_smaa_lib.glsl)
void main()
{
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
index b4a26ec8103..cf38c1fc12c 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
@@ -149,6 +149,8 @@ void blend_mode_output(
}
}
+#ifndef USE_GPU_SHADER_CREATE_INFO
+
IN_OUT ShaderStageInterface
{
vec4 finalColorMul;
@@ -165,6 +167,8 @@ IN_OUT ShaderStageInterface
flat float depth;
};
+#endif
+
#ifdef GPU_FRAGMENT_SHADER
# define linearstep(p0, p1, v) (clamp(((v) - (p0)) / abs((p1) - (p0)), 0.0, 1.0))
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl
index 2f711f6a2c5..9723ea307c3 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl
@@ -1,7 +1,4 @@
-uniform sampler2D depthBuf;
-uniform bool strokeOrder3d;
-
void main()
{
float depth = textureLod(depthBuf, gl_FragCoord.xy / vec2(textureSize(depthBuf, 0)), 0).r;
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
index 0c5260a9ec4..e162c5bf45e 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
@@ -1,6 +1,4 @@
-uniform vec4 gpModelMatrix[4];
-
void main()
{
mat4 model_matrix = mat4(gpModelMatrix[0], gpModelMatrix[1], gpModelMatrix[2], gpModelMatrix[3]);
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
index 87365c2844d..d0dcea34c6e 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
@@ -1,12 +1,6 @@
-uniform sampler2D gpFillTexture;
-uniform sampler2D gpStrokeTexture;
-uniform sampler2D gpSceneDepthTexture;
-uniform sampler2D gpMaskTexture;
-uniform vec3 gpNormal;
-
-layout(location = 0) out vec4 fragColor;
-layout(location = 1) out vec4 revealColor;
+#pragma BLENDER_REQUIRE(common_gpencil_lib.glsl)
+#pragma BLENDER_REQUIRE(common_colormanagement_lib.glsl)
float length_squared(vec2 v)
{
@@ -21,36 +15,37 @@ vec3 gpencil_lighting(void)
{
vec3 light_accum = vec3(0.0);
for (int i = 0; i < GPENCIL_LIGHT_BUFFER_LEN; i++) {
- if (lights[i].color_type.x == -1.0) {
+ if (lights[i]._color.x == -1.0) {
break;
}
- vec3 L = lights[i].position.xyz - finalPos;
+ vec3 L = lights[i]._position - gp_interp.pos;
float vis = 1.0;
+ gpLightType type = floatBitsToUint(lights[i]._type);
/* Spot Attenuation. */
- if (lights[i].color_type.w == GP_LIGHT_TYPE_SPOT) {
- mat3 rot_scale = mat3(lights[i].right.xyz, lights[i].up.xyz, lights[i].forward.xyz);
+ if (type == GP_LIGHT_TYPE_SPOT) {
+ mat3 rot_scale = mat3(lights[i]._right, lights[i]._up, lights[i]._forward);
vec3 local_L = rot_scale * L;
local_L /= abs(local_L.z);
float ellipse = inversesqrt(length_squared(local_L));
- vis *= smoothstep(0.0, 1.0, (ellipse - lights[i].spot_size) / lights[i].spot_blend);
+ vis *= smoothstep(0.0, 1.0, (ellipse - lights[i]._spot_size) / lights[i]._spot_blend);
/* Also mask +Z cone. */
vis *= step(0.0, local_L.z);
}
/* Inverse square decay. Skip for suns. */
float L_len_sqr = length_squared(L);
- if (lights[i].color_type.w < GP_LIGHT_TYPE_SUN) {
+ if (type < GP_LIGHT_TYPE_SUN) {
vis /= L_len_sqr;
}
else {
- L = lights[i].forward.xyz;
+ L = lights[i]._forward;
L_len_sqr = 1.0;
}
/* Lambertian falloff */
- if (lights[i].color_type.w != GP_LIGHT_TYPE_AMBIENT) {
+ if (type != GP_LIGHT_TYPE_AMBIENT) {
L /= sqrt(L_len_sqr);
vis *= clamp(dot(gpNormal, L), 0.0, 1.0);
}
- light_accum += vis * lights[i].color_type.rgb;
+ light_accum += vis * lights[i]._color;
}
/* Clamp to avoid NaNs. */
return clamp(light_accum, 0.0, 1e10);
@@ -59,21 +54,21 @@ vec3 gpencil_lighting(void)
void main()
{
vec4 col;
- if (GP_FLAG_TEST(matFlag, GP_STROKE_TEXTURE_USE)) {
- bool premul = GP_FLAG_TEST(matFlag, GP_STROKE_TEXTURE_PREMUL);
- col = texture_read_as_linearrgb(gpStrokeTexture, premul, finalUvs);
+ if (flag_test(gp_interp.mat_flag, GP_STROKE_TEXTURE_USE)) {
+ bool premul = flag_test(gp_interp.mat_flag, GP_STROKE_TEXTURE_PREMUL);
+ col = texture_read_as_linearrgb(gpStrokeTexture, premul, gp_interp.uv);
}
- else if (GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_USE)) {
- bool use_clip = GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_CLIP);
- vec2 uvs = (use_clip) ? clamp(finalUvs, 0.0, 1.0) : finalUvs;
- bool premul = GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_PREMUL);
+ else if (flag_test(gp_interp.mat_flag, GP_FILL_TEXTURE_USE)) {
+ bool use_clip = flag_test(gp_interp.mat_flag, GP_FILL_TEXTURE_CLIP);
+ vec2 uvs = (use_clip) ? clamp(gp_interp.uv, 0.0, 1.0) : gp_interp.uv;
+ bool premul = flag_test(gp_interp.mat_flag, GP_FILL_TEXTURE_PREMUL);
col = texture_read_as_linearrgb(gpFillTexture, premul, uvs);
}
- else if (GP_FLAG_TEST(matFlag, GP_FILL_GRADIENT_USE)) {
- bool radial = GP_FLAG_TEST(matFlag, GP_FILL_GRADIENT_RADIAL);
- float fac = clamp(radial ? length(finalUvs * 2.0 - 1.0) : finalUvs.x, 0.0, 1.0);
- int matid = matFlag >> GP_MATID_SHIFT;
- col = mix(MATERIAL(matid).fill_color, MATERIAL(matid).fill_mix_color, fac);
+ else if (flag_test(gp_interp.mat_flag, GP_FILL_GRADIENT_USE)) {
+ bool radial = flag_test(gp_interp.mat_flag, GP_FILL_GRADIENT_RADIAL);
+ float fac = clamp(radial ? length(gp_interp.uv * 2.0 - 1.0) : gp_interp.uv.x, 0.0, 1.0);
+ uint matid = gp_interp.mat_flag >> GPENCIl_MATID_SHIFT;
+ col = mix(materials[matid].fill_color, materials[matid].fill_mix_color, fac);
}
else /* SOLID */ {
col = vec4(1.0);
@@ -82,18 +77,21 @@ void main()
/* Composite all other colors on top of texture color.
* Everything is premult by col.a to have the stencil effect. */
- fragColor = col * finalColorMul + col.a * finalColorAdd;
+ fragColor = col * gp_interp.color_mul + col.a * gp_interp.color_add;
fragColor.rgb *= gpencil_lighting();
- fragColor *= stroke_round_cap_mask(
- strokePt1, strokePt2, strokeAspect, strokeThickness, strokeHardeness);
+ fragColor *= gpencil_stroke_round_cap_mask(gp_interp.sspos.xy,
+ gp_interp.sspos.zw,
+ gp_interp.aspect,
+ gp_interp.thickness.x,
+ gp_interp.hardness);
/* To avoid aliasing artifacts, we reduce the opacity of small strokes. */
- fragColor *= smoothstep(0.0, 1.0, unclampedThickness);
+ fragColor *= smoothstep(0.0, 1.0, gp_interp.thickness.y);
/* Holdout materials. */
- if (GP_FLAG_TEST(matFlag, GP_STROKE_HOLDOUT | GP_FILL_HOLDOUT)) {
+ if (flag_test(gp_interp.mat_flag, GP_STROKE_HOLDOUT | GP_FILL_HOLDOUT)) {
revealColor = fragColor.aaaa;
}
else {
@@ -129,8 +127,8 @@ void main()
* This has a cost as the depth test cannot happen early.
* We could do this in the vertex shader but then perspective interpolation of uvs and
* fragment clipping gets really complicated. */
- if (depth >= 0.0) {
- gl_FragDepth = depth;
+ if (gp_interp.depth >= 0.0) {
+ gl_FragDepth = gp_interp.depth;
}
else {
gl_FragDepth = gl_FragCoord.z;
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl
index 6fbc7f47dac..805aec940d8 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl
@@ -1,16 +1,5 @@
-uniform sampler2D colorBuf;
-uniform sampler2D revealBuf;
-uniform sampler2D maskBuf;
-uniform int blendMode;
-uniform float blendOpacity;
-
-in vec4 uvcoordsvar;
-
-/* Reminder: This is considered SRC color in blend equations.
- * Same operation on all buffers. */
-layout(location = 0) out vec4 fragColor;
-layout(location = 1) out vec4 fragRevealage;
+#pragma BLENDER_REQUIRE(gpencil_common_lib.glsl)
void main()
{
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_mask_invert_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_mask_invert_frag.glsl
index b21b4147087..7b95ea1d8b2 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_mask_invert_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_mask_invert_frag.glsl
@@ -1,9 +1,4 @@
-in vec4 uvcoordsvar;
-
-layout(location = 0) out vec4 fragColor;
-layout(location = 1) out vec4 fragRevealage;
-
void main()
{
/* Blend mode does the inversion. */
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
index 225601eb9ba..c0ff8d945f2 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
@@ -1,5 +1,141 @@
+#pragma BLENDER_REQUIRE(common_gpencil_lib.glsl)
+
+void gpencil_color_output(vec4 stroke_col, vec4 vert_col, float vert_strength, float mix_tex)
+{
+ /* Mix stroke with other colors. */
+ vec4 mixed_col = stroke_col;
+ mixed_col.rgb = mix(mixed_col.rgb, vert_col.rgb, vert_col.a * gpVertexColorOpacity);
+ mixed_col.rgb = mix(mixed_col.rgb, gpLayerTint.rgb, gpLayerTint.a);
+ mixed_col.a *= vert_strength * gpLayerOpacity;
+ /**
+ * This is what the fragment shader looks like.
+ * out = col * gp_interp.color_mul + col.a * gp_interp.color_add.
+ * gp_interp.color_mul is how much of the texture color to keep.
+ * gp_interp.color_add is how much of the mixed color to add.
+ * Note that we never add alpha. This is to keep the texture act as a stencil.
+ * We do however, modulate the alpha (reduce it).
+ */
+ /* We add the mixed color. This is 100% mix (no texture visible). */
+ gp_interp.color_mul = vec4(mixed_col.aaa, mixed_col.a);
+ gp_interp.color_add = vec4(mixed_col.rgb * mixed_col.a, 0.0);
+ /* Then we blend according to the texture mix factor.
+ * Note that we keep the alpha modulation. */
+ gp_interp.color_mul.rgb *= mix_tex;
+ gp_interp.color_add.rgb *= 1.0 - mix_tex;
+}
+
void main()
{
- gpencil_vertex();
+ float vert_strength;
+ vec4 vert_color;
+ vec3 vert_N;
+
+ gpMaterial gp_mat = materials[ma1.x + gpMaterialOffset];
+ gpMaterialFlag gp_flag = floatBitsToInt(gp_mat._flag);
+
+ gl_Position = gpencil_vertex(ma,
+ ma1,
+ ma2,
+ ma3,
+ pos,
+ pos1,
+ pos2,
+ pos3,
+ uv1,
+ uv2,
+ col1,
+ col2,
+ fcol1,
+ vec4(drw_view.viewport_size, drw_view.viewport_size_inverse),
+ gp_flag,
+ gp_mat._alignment_rot,
+ gp_interp.pos,
+ vert_N,
+ vert_color,
+ vert_strength,
+ gp_interp.uv,
+ gp_interp.sspos,
+ gp_interp.aspect,
+ gp_interp.thickness,
+ gp_interp.hardness);
+
+ if (GPENCIL_IS_STROKE_VERTEX) {
+ gp_interp.uv.x *= gp_mat._stroke_u_scale;
+
+ /* Special case: We don't use vertex color if material Holdout. */
+ if (flag_test(gp_flag, GP_STROKE_HOLDOUT)) {
+ vert_color = vec4(0.0);
+ }
+
+ gpencil_color_output(
+ gp_mat.stroke_color, vert_color, vert_strength, gp_mat._stroke_texture_mix);
+
+ gp_interp.mat_flag = gp_flag & ~GP_FILL_FLAGS;
+
+ if (gpStrokeOrder3d) {
+ /* Use the fragment depth (see fragment shader). */
+ gp_interp.depth = -1.0;
+ }
+ else if (flag_test(gp_flag, GP_STROKE_OVERLAP)) {
+ /* Use the index of the point as depth.
+ * This means the stroke can overlap itself. */
+ float point_index = float(ma1.z);
+ gp_interp.depth = (point_index + gpStrokeIndexOffset + 1.0) * 0.0000002;
+ }
+ else {
+ /* Use the index of first point of the stroke as depth.
+ * We render using a greater depth test this means the stroke
+ * cannot overlap itself.
+ * We offset by one so that the fill can be overlapped by its stroke.
+ * The offset is ok since we pad the strokes data because of adjacency infos. */
+ float stroke_index = float(ma1.y);
+ gp_interp.depth = (stroke_index + gpStrokeIndexOffset + 1.0) * 0.0000002;
+ }
+ }
+ else {
+ vec4 fill_col = gp_mat.fill_color;
+
+ /* Special case: We don't modulate alpha in gradient mode. */
+ if (flag_test(gp_flag, GP_FILL_GRADIENT_USE)) {
+ fill_col.a = 1.0;
+ }
+
+ /* Decode fill opacity. */
+ vec4 fcol_decode = vec4(fcol1.rgb, floor(fcol1.a / 10.0));
+ float fill_opacity = fcol1.a - (fcol_decode.a * 10);
+ fcol_decode.a /= 10000.0;
+
+ /* Special case: We don't use vertex color if material Holdout. */
+ if (flag_test(gp_flag, GP_FILL_HOLDOUT)) {
+ fcol_decode = vec4(0.0);
+ }
+
+ /* Apply opacity. */
+ fill_col.a *= fill_opacity;
+ /* If factor is > 1 force opacity. */
+ if (fill_opacity > 1.0) {
+ fill_col.a += fill_opacity - 1.0;
+ }
+
+ fill_col.a = clamp(fill_col.a, 0.0, 1.0);
+
+ gpencil_color_output(fill_col, fcol_decode, 1.0, gp_mat._fill_texture_mix);
+
+ gp_interp.mat_flag = gp_flag & GP_FILL_FLAGS;
+ gp_interp.mat_flag |= uint(ma1.x) << GPENCIl_MATID_SHIFT;
+
+ gp_interp.uv = mat2(gp_mat.fill_uv_rot_scale.xy, gp_mat.fill_uv_rot_scale.zw) * uv1.xy +
+ gp_mat._fill_uv_offset;
+
+ if (gpStrokeOrder3d) {
+ /* Use the fragment depth (see fragment shader). */
+ gp_interp.depth = -1.0;
+ }
+ else {
+ /* Use the index of first point of the stroke as depth. */
+ float stroke_index = float(ma1.y);
+ gp_interp.depth = (stroke_index + gpStrokeIndexOffset) * 0.0000002;
+ }
+ }
}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl
index 269ed49c4d0..5bae00b070f 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl
@@ -1,13 +1,5 @@
-uniform sampler2D colorBuf;
-uniform sampler2D revealBuf;
-
-in vec4 uvcoordsvar;
-
-/* Reminder: This is considered SRC color in blend equations.
- * Same operation on all buffers. */
-layout(location = 0) out vec4 fragColor;
-layout(location = 1) out vec4 fragRevealage;
+#pragma BLENDER_REQUIRE(gpencil_common_lib.glsl)
float gaussian_weight(float x)
{
@@ -16,8 +8,6 @@ float gaussian_weight(float x)
#if defined(COMPOSITE)
-uniform bool isFirstPass;
-
void main()
{
if (isFirstPass) {
@@ -35,11 +25,6 @@ void main()
#elif defined(COLORIZE)
-uniform vec3 lowColor;
-uniform vec3 highColor;
-uniform float factor;
-uniform int mode;
-
const mat3 sepia_mat = mat3(
vec3(0.393, 0.349, 0.272), vec3(0.769, 0.686, 0.534), vec3(0.189, 0.168, 0.131));
@@ -80,9 +65,6 @@ void main()
#elif defined(BLUR)
-uniform vec2 offset;
-uniform int sampCount;
-
void main()
{
vec2 pixel_size = 1.0 / vec2(textureSize(revealBuf, 0).xy);
@@ -108,14 +90,6 @@ void main()
#elif defined(TRANSFORM)
-uniform vec2 axisFlip = vec2(1.0);
-uniform vec2 waveDir = vec2(0.0);
-uniform vec2 waveOffset = vec2(0.0);
-uniform float wavePhase = 0.0;
-uniform vec2 swirlCenter = vec2(0.0);
-uniform float swirlAngle = 0.0;
-uniform float swirlRadius = 0.0;
-
void main()
{
vec2 uv = (uvcoordsvar.xy - 0.5) * axisFlip + 0.5;
@@ -142,14 +116,6 @@ void main()
#elif defined(GLOW)
-uniform vec4 glowColor;
-uniform vec2 offset;
-uniform int sampCount;
-uniform vec4 threshold;
-uniform bool firstPass;
-uniform bool glowUnder;
-uniform int blendMode;
-
void main()
{
vec2 pixel_size = 1.0 / vec2(textureSize(revealBuf, 0).xy);
@@ -210,14 +176,6 @@ void main()
#elif defined(RIM)
-uniform vec2 blurDir;
-uniform vec2 uvOffset;
-uniform vec3 rimColor;
-uniform vec3 maskColor;
-uniform int sampCount;
-uniform int blendMode;
-uniform bool isFirstPass;
-
void main()
{
/* Blur revealage buffer. */
@@ -260,17 +218,6 @@ void main()
#elif defined(SHADOW)
-uniform vec4 shadowColor;
-uniform vec2 uvRotX;
-uniform vec2 uvRotY;
-uniform vec2 uvOffset;
-uniform vec2 blurDir;
-uniform vec2 waveDir;
-uniform vec2 waveOffset;
-uniform float wavePhase;
-uniform int sampCount;
-uniform bool isFirstPass;
-
vec2 compute_uvs(float x)
{
vec2 uv = uvcoordsvar.xy;
@@ -327,11 +274,6 @@ void main()
#elif defined(PIXELIZE)
-uniform vec2 targetPixelSize;
-uniform vec2 targetPixelOffset;
-uniform vec2 accumOffset;
-uniform int sampCount;
-
void main()
{
vec2 pixel = floor((uvcoordsvar.xy - targetPixelOffset) / targetPixelSize);
diff --git a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh
new file mode 100644
index 00000000000..3b4de704c00
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_info.hh
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name GPencil Object rendering
+ * \{ */
+
+GPU_SHADER_INTERFACE_INFO(gpencil_geometry_iface, "gp_interp")
+ .smooth(Type::VEC4, "color_mul")
+ .smooth(Type::VEC4, "color_add")
+ .smooth(Type::VEC3, "pos")
+ .smooth(Type::VEC2, "uv")
+ .no_perspective(Type::VEC2, "thickness")
+ .no_perspective(Type::FLOAT, "hardness")
+ .flat(Type::VEC2, "aspect")
+ .flat(Type::VEC4, "sspos")
+ .flat(Type::UINT, "mat_flag")
+ .flat(Type::FLOAT, "depth");
+
+GPU_SHADER_CREATE_INFO(gpencil_geometry)
+ .do_static_compilation(true)
+ .typedef_source("gpencil_defines.h")
+ .typedef_source("gpencil_shader_shared.h")
+ .sampler(0, ImageType::FLOAT_2D, "gpFillTexture")
+ .sampler(1, ImageType::FLOAT_2D, "gpStrokeTexture")
+ .sampler(2, ImageType::DEPTH_2D, "gpSceneDepthTexture")
+ .sampler(3, ImageType::FLOAT_2D, "gpMaskTexture")
+ .uniform_buf(2, "gpMaterial", "materials[GPENCIL_MATERIAL_BUFFER_LEN]", Frequency::BATCH)
+ .uniform_buf(3, "gpLight", "lights[GPENCIL_LIGHT_BUFFER_LEN]", Frequency::BATCH)
+ /* Per Object */
+ .push_constant(Type::VEC3, "gpNormal")
+ .push_constant(Type::BOOL, "gpStrokeOrder3d")
+ .push_constant(Type::INT, "gpMaterialOffset")
+ /* Per Layer */
+ .push_constant(Type::FLOAT, "gpVertexColorOpacity")
+ .push_constant(Type::VEC4, "gpLayerTint")
+ .push_constant(Type::FLOAT, "gpLayerOpacity")
+ .push_constant(Type::FLOAT, "gpStrokeIndexOffset")
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .fragment_out(1, Type::VEC4, "revealColor")
+ .vertex_out(gpencil_geometry_iface)
+ .vertex_source("gpencil_vert.glsl")
+ .fragment_source("gpencil_frag.glsl")
+ .additional_info("draw_gpencil");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Fullscreen shaders
+ * \{ */
+
+GPU_SHADER_CREATE_INFO(gpencil_layer_blend)
+ .do_static_compilation(true)
+ .sampler(0, ImageType::FLOAT_2D, "colorBuf")
+ .sampler(1, ImageType::FLOAT_2D, "revealBuf")
+ .sampler(2, ImageType::FLOAT_2D, "maskBuf")
+ .push_constant(Type::INT, "blendMode")
+ .push_constant(Type::FLOAT, "blendOpacity")
+ /* Reminder: This is considered SRC color in blend equations.
+ * Same operation on all buffers. */
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .fragment_out(1, Type::VEC4, "fragRevealage")
+ .fragment_source("gpencil_layer_blend_frag.glsl")
+ .additional_info("draw_fullscreen");
+
+GPU_SHADER_CREATE_INFO(gpencil_mask_invert)
+ .do_static_compilation(true)
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .fragment_out(1, Type::VEC4, "fragRevealage")
+ .fragment_source("gpencil_mask_invert_frag.glsl")
+ .additional_info("draw_fullscreen");
+
+GPU_SHADER_CREATE_INFO(gpencil_depth_merge)
+ .do_static_compilation(true)
+ .push_constant(Type::VEC4, "gpModelMatrix", 4)
+ .push_constant(Type::BOOL, "strokeOrder3d")
+ .sampler(0, ImageType::DEPTH_2D, "depthBuf")
+ .vertex_source("gpencil_depth_merge_vert.glsl")
+ .fragment_source("gpencil_depth_merge_frag.glsl")
+ .additional_info("draw_view");
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Anti-Aliasing
+ * \{ */
+
+GPU_SHADER_INTERFACE_INFO(gpencil_antialiasing_iface, "")
+ .smooth(Type::VEC2, "uvs")
+ .smooth(Type::VEC2, "pixcoord")
+ .smooth(Type::VEC4, "offset[3]");
+
+GPU_SHADER_CREATE_INFO(gpencil_antialiasing)
+ .define("SMAA_GLSL_3")
+ .define("SMAA_RT_METRICS", "viewportMetrics")
+ .define("SMAA_PRESET_HIGH")
+ .define("SMAA_LUMA_WEIGHT", "float4(lumaWeight, lumaWeight, lumaWeight, 0.0)")
+ .define("SMAA_NO_DISCARD")
+ .vertex_out(gpencil_antialiasing_iface)
+ .push_constant(Type::VEC4, "viewportMetrics")
+ .push_constant(Type::FLOAT, "lumaWeight")
+ .vertex_source("gpencil_antialiasing_vert.glsl")
+ .fragment_source("gpencil_antialiasing_frag.glsl");
+
+GPU_SHADER_CREATE_INFO(gpencil_antialiasing_stage_0)
+ .define("SMAA_STAGE", "0")
+ .sampler(0, ImageType::FLOAT_2D, "colorTex")
+ .sampler(1, ImageType::FLOAT_2D, "revealTex")
+ .fragment_out(0, Type::VEC2, "out_edges")
+ .additional_info("gpencil_antialiasing")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpencil_antialiasing_stage_1)
+ .define("SMAA_STAGE", "1")
+ .sampler(0, ImageType::FLOAT_2D, "edgesTex")
+ .sampler(1, ImageType::FLOAT_2D, "areaTex")
+ .sampler(2, ImageType::FLOAT_2D, "searchTex")
+ .fragment_out(0, Type::VEC4, "out_weights")
+ .additional_info("gpencil_antialiasing")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(gpencil_antialiasing_stage_2)
+ .define("SMAA_STAGE", "2")
+ .sampler(0, ImageType::FLOAT_2D, "colorTex")
+ .sampler(1, ImageType::FLOAT_2D, "revealTex")
+ .sampler(2, ImageType::FLOAT_2D, "blendTex")
+ .push_constant(Type::FLOAT, "mixFactor")
+ .push_constant(Type::FLOAT, "taaAccumulatedWeight")
+ .push_constant(Type::BOOL, "doAntiAliasing")
+ .push_constant(Type::BOOL, "onlyAlpha")
+ /* Reminder: Blending func is `fragRevealage * DST + fragColor`. */
+ .fragment_out(0, Type::VEC4, "out_color", DualBlend::SRC_0)
+ .fragment_out(0, Type::VEC4, "out_reveal", DualBlend::SRC_1)
+ .additional_info("gpencil_antialiasing")
+ .do_static_compilation(true);
+
+/** \} */
diff --git a/source/blender/draw/engines/gpencil/shaders/infos/gpencil_vfx_info.hh b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_vfx_info.hh
new file mode 100644
index 00000000000..165b47f82f8
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/infos/gpencil_vfx_info.hh
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(gpencil_fx_common)
+ .sampler(0, ImageType::FLOAT_2D, "colorBuf")
+ .sampler(1, ImageType::FLOAT_2D, "revealBuf")
+ /* Reminder: This is considered SRC color in blend equations.
+ * Same operation on all buffers. */
+ .fragment_out(0, Type::VEC4, "fragColor")
+ .fragment_out(1, Type::VEC4, "fragRevealage")
+ .fragment_source("gpencil_vfx_frag.glsl");
+
+GPU_SHADER_CREATE_INFO(gpencil_fx_composite)
+ .do_static_compilation(true)
+ .define("COMPOSITE")
+ .push_constant(Type::BOOL, "isFirstPass")
+ .additional_info("gpencil_fx_common", "draw_fullscreen");
+
+GPU_SHADER_CREATE_INFO(gpencil_fx_colorize)
+ .do_static_compilation(true)
+ .define("COLORIZE")
+ .push_constant(Type::VEC3, "lowColor")
+ .push_constant(Type::VEC3, "highColor")
+ .push_constant(Type::FLOAT, "factor")
+ .push_constant(Type::INT, "mode")
+ .additional_info("gpencil_fx_common", "draw_fullscreen");
+
+GPU_SHADER_CREATE_INFO(gpencil_fx_blur)
+ .do_static_compilation(true)
+ .define("BLUR")
+ .push_constant(Type::VEC2, "offset")
+ .push_constant(Type::INT, "sampCount")
+ .additional_info("gpencil_fx_common", "draw_fullscreen");
+
+GPU_SHADER_CREATE_INFO(gpencil_fx_transform)
+ .do_static_compilation(true)
+ .define("TRANSFORM")
+ .push_constant(Type::VEC2, "axisFlip")
+ .push_constant(Type::VEC2, "waveDir")
+ .push_constant(Type::VEC2, "waveOffset")
+ .push_constant(Type::FLOAT, "wavePhase")
+ .push_constant(Type::VEC2, "swirlCenter")
+ .push_constant(Type::FLOAT, "swirlAngle")
+ .push_constant(Type::FLOAT, "swirlRadius")
+ .additional_info("gpencil_fx_common", "draw_fullscreen");
+
+GPU_SHADER_CREATE_INFO(gpencil_fx_glow)
+ .do_static_compilation(true)
+ .define("GLOW")
+ .push_constant(Type::VEC4, "glowColor")
+ .push_constant(Type::VEC2, "offset")
+ .push_constant(Type::INT, "sampCount")
+ .push_constant(Type::VEC4, "threshold")
+ .push_constant(Type::BOOL, "firstPass")
+ .push_constant(Type::BOOL, "glowUnder")
+ .push_constant(Type::INT, "blendMode")
+ .additional_info("gpencil_fx_common", "draw_fullscreen");
+
+GPU_SHADER_CREATE_INFO(gpencil_fx_rim)
+ .do_static_compilation(true)
+ .define("RIM")
+ .push_constant(Type::VEC2, "blurDir")
+ .push_constant(Type::VEC2, "uvOffset")
+ .push_constant(Type::VEC3, "rimColor")
+ .push_constant(Type::VEC3, "maskColor")
+ .push_constant(Type::INT, "sampCount")
+ .push_constant(Type::INT, "blendMode")
+ .push_constant(Type::BOOL, "isFirstPass")
+ .additional_info("gpencil_fx_common", "draw_fullscreen");
+
+GPU_SHADER_CREATE_INFO(gpencil_fx_shadow)
+ .do_static_compilation(true)
+ .define("SHADOW")
+ .push_constant(Type::VEC4, "shadowColor")
+ .push_constant(Type::VEC2, "uvRotX")
+ .push_constant(Type::VEC2, "uvRotY")
+ .push_constant(Type::VEC2, "uvOffset")
+ .push_constant(Type::VEC2, "blurDir")
+ .push_constant(Type::VEC2, "waveDir")
+ .push_constant(Type::VEC2, "waveOffset")
+ .push_constant(Type::FLOAT, "wavePhase")
+ .push_constant(Type::INT, "sampCount")
+ .push_constant(Type::BOOL, "isFirstPass")
+ .additional_info("gpencil_fx_common", "draw_fullscreen");
+
+GPU_SHADER_CREATE_INFO(gpencil_fx_pixelize)
+ .do_static_compilation(true)
+ .define("PIXELIZE")
+ .push_constant(Type::VEC2, "targetPixelSize")
+ .push_constant(Type::VEC2, "targetPixelOffset")
+ .push_constant(Type::VEC2, "accumOffset")
+ .push_constant(Type::INT, "sampCount")
+ .additional_info("gpencil_fx_common", "draw_fullscreen");
diff --git a/source/blender/draw/engines/image/image_drawing_mode.hh b/source/blender/draw/engines/image/image_drawing_mode.hh
index 46482ab6668..f43bbadfa91 100644
--- a/source/blender/draw/engines/image/image_drawing_mode.hh
+++ b/source/blender/draw/engines/image/image_drawing_mode.hh
@@ -154,16 +154,15 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
* bug or a feature. For now we just acquire to determine if there is a texture. */
void *lock;
ImBuf *tile_buffer = BKE_image_acquire_ibuf(image, &tile_user, &lock);
- if (tile_buffer == nullptr) {
- continue;
+ if (tile_buffer != nullptr) {
+ instance_data.float_buffers.mark_used(tile_buffer);
+
+ DRWShadingGroup *shsub = DRW_shgroup_create_sub(shgrp);
+ float4 min_max_uv(tile_x, tile_y, tile_x + 1, tile_y + 1);
+ DRW_shgroup_uniform_vec4_copy(shsub, "min_max_uv", min_max_uv);
+ DRW_shgroup_call_obmat(shsub, info.batch, image_mat);
}
- instance_data.float_buffers.mark_used(tile_buffer);
BKE_image_release_ibuf(image, tile_buffer, lock);
-
- DRWShadingGroup *shsub = DRW_shgroup_create_sub(shgrp);
- float4 min_max_uv(tile_x, tile_y, tile_x + 1, tile_y + 1);
- DRW_shgroup_uniform_vec4_copy(shsub, "min_max_uv", min_max_uv);
- DRW_shgroup_call_obmat(shsub, info.batch, image_mat);
}
}
}
@@ -387,11 +386,9 @@ template<typename TextureMethod> class ScreenSpaceDrawingMode : public AbstractD
tile_user.tile = image_tile.get_tile_number();
ImBuf *tile_buffer = BKE_image_acquire_ibuf(image, &tile_user, &lock);
- if (tile_buffer == nullptr) {
- /* Couldn't load the image buffer of the tile. */
- continue;
+ if (tile_buffer != nullptr) {
+ do_full_update_texture_slot(instance_data, info, texture_buffer, *tile_buffer, image_tile);
}
- do_full_update_texture_slot(instance_data, info, texture_buffer, *tile_buffer, image_tile);
BKE_image_release_ibuf(image, tile_buffer, lock);
}
GPU_texture_update(info.texture, GPU_DATA_FLOAT, texture_buffer.rect_float);
diff --git a/source/blender/draw/engines/overlay/overlay_metaball.c b/source/blender/draw/engines/overlay/overlay_metaball.c
index b747000abc4..7805b63993e 100644
--- a/source/blender/draw/engines/overlay/overlay_metaball.c
+++ b/source/blender/draw/engines/overlay/overlay_metaball.c
@@ -92,6 +92,11 @@ void OVERLAY_edit_metaball_cache_populate(OVERLAY_Data *vedata, Object *ob)
select_id += 0x10000;
}
+
+ /* Needed so object centers and geometry are not detected as meta-elements. */
+ if (is_select) {
+ DRW_select_load_id(-1);
+ }
}
void OVERLAY_metaball_cache_populate(OVERLAY_Data *vedata, Object *ob)
diff --git a/source/blender/draw/engines/overlay/shaders/background_frag.glsl b/source/blender/draw/engines/overlay/shaders/background_frag.glsl
index 52052d414f8..19313c0415b 100644
--- a/source/blender/draw/engines/overlay/shaders/background_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/background_frag.glsl
@@ -38,8 +38,8 @@ void main()
* This removes the alpha channel and put the background behind reference images
* while masking the reference images by the render alpha.
*/
- float alpha = texture(colorBuffer, uvcoordsvar.st).a;
- float depth = texture(depthBuffer, uvcoordsvar.st).r;
+ float alpha = texture(colorBuffer, uvcoordsvar.xy).a;
+ float depth = texture(depthBuffer, uvcoordsvar.xy).r;
vec3 bg_col;
vec3 col_high;
diff --git a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
index 0e4757f8ea8..19d54a57479 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_detect_frag.glsl
@@ -169,7 +169,7 @@ void diag_dir(bvec4 edges1, bvec4 edges2, out vec2 line_start, out vec2 line_end
void main()
{
- uint ref = textureLod(outlineId, uvcoordsvar.st, 0.0).r;
+ uint ref = textureLod(outlineId, uvcoordsvar.xy, 0.0).r;
uint ref_col = ref;
vec2 uvs = gl_FragCoord.xy * sizeViewportInv.xy;
diff --git a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl b/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl
index f714646fe40..507beb8a418 100644
--- a/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/volume_gridlines_vert.glsl
@@ -53,7 +53,7 @@ vec4 flag_to_color(uint flag)
if (bool(flag & uint(16))) {
color.rgb += vec3(0.9, 0.3, 0.0); /* orange */
}
- if (color.rgb == vec3(0.0)) {
+ if (is_zero(color.rgb)) {
color.rgb += vec3(0.5, 0.0, 0.0); /* medium red */
}
return color;
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
index 59222b588a0..7704e7ed0b7 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl
@@ -9,11 +9,11 @@ void main()
float cavity = 0.0, edges = 0.0, curvature = 0.0;
#ifdef USE_CAVITY
- cavity_compute(uvcoordsvar.st, depthBuffer, normalBuffer, cavity, edges);
+ cavity_compute(uvcoordsvar.xy, depthBuffer, normalBuffer, cavity, edges);
#endif
#ifdef USE_CURVATURE
- curvature_compute(uvcoordsvar.st, objectIdBuffer, normalBuffer, curvature);
+ curvature_compute(uvcoordsvar.xy, objectIdBuffer, normalBuffer, curvature);
#endif
float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0);
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
index ae564435258..30daca6b7e3 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl
@@ -1,7 +1,7 @@
void main()
{
- float depth = texture(depthBuffer, uvcoordsvar.st).r;
+ float depth = texture(depthBuffer, uvcoordsvar.xy).r;
/* Fix issues with Intel drivers (see T80023). */
fragColor = vec4(0.0);
/* Discard background pixels. */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
index a2c45d2f8e3..35bea830bac 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl
@@ -9,8 +9,8 @@ void main()
/* Revealage is actually stored in transparentAccum alpha channel.
* This is a workaround to older hardware not having separate blend equation per render target.
*/
- vec4 trans_accum = texture(transparentAccum, uvcoordsvar.st);
- float trans_weight = texture(transparentRevealage, uvcoordsvar.st).r;
+ vec4 trans_accum = texture(transparentAccum, uvcoordsvar.xy);
+ float trans_weight = texture(transparentRevealage, uvcoordsvar.xy).r;
float trans_reveal = trans_accum.a;
/* Listing 4 */
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
index 076f6e80104..4ff281ccd29 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl
@@ -94,7 +94,7 @@ vec4 flag_to_color(uint flag)
if (bool(flag & uint(16))) {
color.rgb += vec3(0.9, 0.3, 0.0); /* orange */
}
- if (color.rgb == vec3(0.0)) {
+ if (is_zero(color.rgb)) {
color.rgb += vec3(0.5, 0.0, 0.0); /* medium red */
}
return color;
diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh
index bce001659b2..ed94c485b32 100644
--- a/source/blender/draw/intern/DRW_gpu_wrapper.hh
+++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh
@@ -16,39 +16,39 @@
*
* All types are not copyable and Buffers are not Movable.
*
- * `drw::UniformArrayBuffer<T, len>`
+ * `draw::UniformArrayBuffer<T, len>`
* Uniform buffer object containing an array of T with len elements.
* Data can be accessed using the [] operator.
*
- * `drw::UniformBuffer<T>`
+ * `draw::UniformBuffer<T>`
* A uniform buffer object class inheriting from T.
* Data can be accessed just like a normal T object.
*
- * `drw::StorageArrayBuffer<T, len>`
+ * `draw::StorageArrayBuffer<T, len>`
* Storage buffer object containing an array of T with len elements.
* The item count can be changed after creation using `resize()`.
* However, this requires the invalidation of the whole buffer and
* discarding all data inside it.
* Data can be accessed using the [] operator.
*
- * `drw::StorageBuffer<T>`
+ * `draw::StorageBuffer<T>`
* A storage buffer object class inheriting from T.
* Data can be accessed just like a normal T object.
*
- * `drw::Texture`
- * A simple wrapper to #GPUTexture. A #drw::Texture can be created without allocation.
+ * `draw::Texture`
+ * A simple wrapper to #GPUTexture. A #draw::Texture can be created without allocation.
* The `ensure_[1d|2d|3d|cube][_array]()` method is here to make sure the underlying texture
* will meet the requirements and create (or recreate) the #GPUTexture if needed.
*
- * `drw::TextureFromPool`
+ * `draw::TextureFromPool`
* A GPUTexture from the viewport texture pool. This texture can be shared with other engines
* and its content is undefined when acquiring it.
- * A #drw::TextureFromPool is acquired for rendering using `acquire()` and released once the
+ * A #draw::TextureFromPool is acquired for rendering using `acquire()` and released once the
* rendering is done using `release()`. The same texture can be acquired & released multiple
* time in one draw loop.
* The `sync()` method *MUST* be called once during the cache populate (aka: Sync) phase.
*
- * `drw::Framebuffer`
+ * `draw::Framebuffer`
* Simple wrapper to #GPUFramebuffer that can be moved.
*
*/
@@ -63,9 +63,9 @@
#include "BLI_utility_mixins.hh"
#include "GPU_framebuffer.h"
+#include "GPU_storage_buffer.h"
#include "GPU_texture.h"
#include "GPU_uniform_buffer.h"
-#include "GPU_vertex_buffer.h"
namespace blender::draw {
@@ -165,7 +165,7 @@ class UniformCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable
#ifdef DEBUG
const char *name_ = typeid(T).name();
#else
- constexpr static const char *name_ = "UniformBuffer";
+ const char *name_ = "UniformBuffer";
#endif
public:
@@ -200,41 +200,49 @@ class UniformCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable
template<typename T, int64_t len, bool device_only>
class StorageCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable {
protected:
- /* Use vertex buffer for now. Until there is a complete GPUStorageBuf implementation. */
- GPUVertBuf *ssbo_;
+ GPUStorageBuf *ssbo_;
#ifdef DEBUG
const char *name_ = typeid(T).name();
#else
- constexpr static const char *name_ = "StorageBuffer";
+ const char *name_ = "StorageBuffer";
#endif
public:
- StorageCommon()
+ StorageCommon(const char *name = nullptr)
{
+ if (name) {
+ name_ = name;
+ }
init(len);
}
~StorageCommon()
{
- GPU_vertbuf_discard(ssbo_);
+ GPU_storagebuf_free(ssbo_);
}
void resize(int64_t new_size)
{
BLI_assert(new_size > 0);
if (new_size != this->len_) {
- GPU_vertbuf_discard(ssbo_);
+ GPU_storagebuf_free(ssbo_);
this->init(new_size);
}
}
- operator GPUVertBuf *() const
+ void push_update(void)
+ {
+ BLI_assert(device_only == false);
+ GPU_storagebuf_update(ssbo_, this->data_);
+ }
+
+ operator GPUStorageBuf *() const
{
return ssbo_;
}
/* To be able to use it with DRW_shgroup_*_ref(). */
- GPUVertBuf **operator&()
+ GPUStorageBuf **operator&()
{
return &ssbo_;
}
@@ -243,17 +251,8 @@ class StorageCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable
void init(int64_t new_size)
{
this->len_ = new_size;
-
- GPUVertFormat format = {0};
- GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
-
GPUUsageType usage = device_only ? GPU_USAGE_DEVICE_ONLY : GPU_USAGE_DYNAMIC;
- ssbo_ = GPU_vertbuf_create_with_format_ex(&format, usage);
- GPU_vertbuf_data_alloc(ssbo_, divide_ceil_u(sizeof(T) * this->len_, 4));
- if (!device_only) {
- this->data_ = (T *)GPU_vertbuf_get_data(ssbo_);
- GPU_vertbuf_use(ssbo_);
- }
+ ssbo_ = GPU_storagebuf_create_ex(sizeof(T) * this->len_, nullptr, usage, this->name_);
}
};
@@ -322,13 +321,14 @@ template<
bool device_only = false>
class StorageArrayBuffer : public detail::StorageCommon<T, len, device_only> {
public:
- void push_update(void)
+ StorageArrayBuffer(const char *name = nullptr) : detail::StorageCommon<T, len, device_only>(name)
{
- BLI_assert(!device_only);
- /* Get the data again to tag for update. The actual pointer should not
- * change. */
- this->data_ = (T *)GPU_vertbuf_get_data(this->ssbo_);
- GPU_vertbuf_use(this->ssbo_);
+ /* TODO(@fclem): We should map memory instead. */
+ this->data_ = (T *)MEM_mallocN_aligned(len * sizeof(T), 16, this->name_);
+ }
+ ~StorageArrayBuffer()
+ {
+ MEM_freeN(this->data_);
}
};
@@ -339,14 +339,10 @@ template<
bool device_only = false>
class StorageBuffer : public T, public detail::StorageCommon<T, 1, device_only> {
public:
- void push_update(void)
+ StorageBuffer(const char *name = nullptr) : detail::StorageCommon<T, 1, device_only>(name)
{
- BLI_assert(!device_only);
- /* TODO(fclem): Avoid a full copy. */
- T &vert_data = *(T *)GPU_vertbuf_get_data(this->ssbo_);
- vert_data = *this;
-
- GPU_vertbuf_use(this->ssbo_);
+ /* TODO(@fclem): How could we map this? */
+ this->data_ = static_cast<T *>(this);
}
StorageBuffer<T> &operator=(const T &other)
@@ -365,6 +361,9 @@ class StorageBuffer : public T, public detail::StorageCommon<T, 1, device_only>
class Texture : NonCopyable {
protected:
GPUTexture *tx_ = nullptr;
+ GPUTexture *stencil_view_ = nullptr;
+ Vector<GPUTexture *, 0> mip_views_;
+ Vector<GPUTexture *, 0> layer_views_;
const char *name_;
public:
@@ -515,6 +514,68 @@ class Texture : NonCopyable {
}
/**
+ * Ensure the availability of mipmap views.
+ * MIP view covers all layers of array textures.
+ */
+ bool ensure_mip_views(bool cube_as_array = false)
+ {
+ int mip_len = GPU_texture_mip_count(tx_);
+ if (mip_views_.size() != mip_len) {
+ for (GPUTexture *&view : mip_views_) {
+ GPU_TEXTURE_FREE_SAFE(view);
+ }
+ eGPUTextureFormat format = GPU_texture_format(tx_);
+ for (auto i : IndexRange(mip_len)) {
+ mip_views_.append(
+ GPU_texture_create_view(name_, tx_, format, i, 1, 0, 9999, cube_as_array));
+ }
+ return true;
+ }
+ return false;
+ }
+
+ GPUTexture *mip_view(int miplvl)
+ {
+ return mip_views_[miplvl];
+ }
+
+ /**
+ * Ensure the availability of mipmap views.
+ * Layer views covers all layers of array textures.
+ */
+ bool ensure_layer_views(bool cube_as_array = false)
+ {
+ int layer_len = GPU_texture_layer_count(tx_);
+ if (layer_views_.size() != layer_len) {
+ for (GPUTexture *&view : layer_views_) {
+ GPU_TEXTURE_FREE_SAFE(view);
+ }
+ eGPUTextureFormat format = GPU_texture_format(tx_);
+ for (auto i : IndexRange(layer_len)) {
+ layer_views_.append(
+ GPU_texture_create_view(name_, tx_, format, 0, 9999, i, 1, cube_as_array));
+ }
+ return true;
+ }
+ return false;
+ }
+
+ GPUTexture *layer_view(int layer)
+ {
+ return layer_views_[layer];
+ }
+
+ GPUTexture *stencil_view(bool cube_as_array = false)
+ {
+ if (stencil_view_ == nullptr) {
+ eGPUTextureFormat format = GPU_texture_format(tx_);
+ stencil_view_ = GPU_texture_create_view(name_, tx_, format, 0, 9999, 0, 9999, cube_as_array);
+ GPU_texture_stencil_texture_mode_set(stencil_view_, true);
+ }
+ return stencil_view_;
+ }
+
+ /**
* Returns true if the texture has been allocated or acquired from the pool.
*/
bool is_valid(void) const
@@ -603,11 +664,19 @@ class Texture : NonCopyable {
}
/**
- * Free the internal texture but not the #drw::Texture itself.
+ * Free the internal texture but not the #draw::Texture itself.
*/
void free()
{
GPU_TEXTURE_FREE_SAFE(tx_);
+ for (GPUTexture *&view : mip_views_) {
+ GPU_TEXTURE_FREE_SAFE(view);
+ }
+ for (GPUTexture *&view : layer_views_) {
+ GPU_TEXTURE_FREE_SAFE(view);
+ }
+ GPU_TEXTURE_FREE_SAFE(stencil_view_);
+ mip_views_.clear();
}
/**
@@ -692,23 +761,35 @@ class TextureFromPool : public Texture, NonMovable {
public:
TextureFromPool(const char *name = "gpu::Texture") : Texture(name){};
- /* Always use `release()` after rendering. */
+ /* Always use `release()` after rendering and `sync()` in sync phase. */
void acquire(int2 extent, eGPUTextureFormat format, void *owner_)
{
- if (this->tx_ == nullptr) {
- if (tx_tmp_saved_ != nullptr) {
+ BLI_assert(this->tx_ == nullptr);
+ if (this->tx_ != nullptr) {
+ return;
+ }
+ if (tx_tmp_saved_ != nullptr) {
+ if (GPU_texture_width(tx_tmp_saved_) != extent.x ||
+ GPU_texture_height(tx_tmp_saved_) != extent.y ||
+ GPU_texture_format(tx_tmp_saved_) != format) {
+ this->tx_tmp_saved_ = nullptr;
+ }
+ else {
this->tx_ = tx_tmp_saved_;
return;
}
- DrawEngineType *owner = (DrawEngineType *)owner_;
- this->tx_ = DRW_texture_pool_query_2d(UNPACK2(extent), format, owner);
}
+ DrawEngineType *owner = (DrawEngineType *)owner_;
+ this->tx_ = DRW_texture_pool_query_2d(UNPACK2(extent), format, owner);
}
void release(void)
{
- tx_tmp_saved_ = this->tx_;
- this->tx_ = nullptr;
+ /* Allows multiple release. */
+ if (this->tx_ != nullptr) {
+ tx_tmp_saved_ = this->tx_;
+ this->tx_ = nullptr;
+ }
}
/**
@@ -730,6 +811,9 @@ class TextureFromPool : public Texture, NonMovable {
bool ensure_cube_array(int, int, int, eGPUTextureFormat, float *) = delete;
void filter_mode(bool) = delete;
void free() = delete;
+ GPUTexture *mip_view(int) = delete;
+ GPUTexture *layer_view(int) = delete;
+ GPUTexture *stencil_view() = delete;
};
/** \} */
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 37c1365a5f2..8dbf5483d47 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -30,6 +30,7 @@
#include "GPU_framebuffer.h"
#include "GPU_primitive.h"
#include "GPU_shader.h"
+#include "GPU_storage_buffer.h"
#include "GPU_texture.h"
#include "GPU_uniform_buffer.h"
@@ -466,6 +467,10 @@ void DRW_shgroup_call_compute(DRWShadingGroup *shgroup,
* \warning this keeps the ref to groups_ref until it actually dispatch.
*/
void DRW_shgroup_call_compute_ref(DRWShadingGroup *shgroup, int groups_ref[3]);
+/**
+ * \note No need for a barrier. \a indirect_buf is internally synchronized.
+ */
+void DRW_shgroup_call_compute_indirect(DRWShadingGroup *shgroup, GPUStorageBuf *indirect_buf);
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);
@@ -568,6 +573,12 @@ void DRW_shgroup_uniform_block_ex(DRWShadingGroup *shgroup,
void DRW_shgroup_uniform_block_ref_ex(DRWShadingGroup *shgroup,
const char *name,
struct GPUUniformBuf **ubo DRW_DEBUG_FILE_LINE_ARGS);
+void DRW_shgroup_storage_block_ex(DRWShadingGroup *shgroup,
+ const char *name,
+ const struct GPUStorageBuf *ssbo DRW_DEBUG_FILE_LINE_ARGS);
+void DRW_shgroup_storage_block_ref_ex(DRWShadingGroup *shgroup,
+ const char *name,
+ struct GPUStorageBuf **ssbo DRW_DEBUG_FILE_LINE_ARGS);
void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup,
const char *name,
const float *value,
@@ -643,6 +654,10 @@ void DRW_shgroup_vertex_buffer_ref_ex(DRWShadingGroup *shgroup,
DRW_shgroup_uniform_block_ex(shgroup, name, ubo, __FILE__, __LINE__)
# define DRW_shgroup_uniform_block_ref(shgroup, name, ubo) \
DRW_shgroup_uniform_block_ref_ex(shgroup, name, ubo, __FILE__, __LINE__)
+# define DRW_shgroup_storage_block(shgroup, name, ubo) \
+ DRW_shgroup_storage_block_ex(shgroup, name, ubo, __FILE__, __LINE__)
+# define DRW_shgroup_storage_block_ref(shgroup, name, ubo) \
+ DRW_shgroup_storage_block_ref_ex(shgroup, name, ubo, __FILE__, __LINE__)
#else
# define DRW_shgroup_vertex_buffer(shgroup, name, vert) \
DRW_shgroup_vertex_buffer_ex(shgroup, name, vert)
@@ -652,6 +667,10 @@ void DRW_shgroup_vertex_buffer_ref_ex(DRWShadingGroup *shgroup,
DRW_shgroup_uniform_block_ex(shgroup, name, ubo)
# define DRW_shgroup_uniform_block_ref(shgroup, name, ubo) \
DRW_shgroup_uniform_block_ref_ex(shgroup, name, ubo)
+# define DRW_shgroup_storage_block(shgroup, name, ubo) \
+ DRW_shgroup_storage_block_ex(shgroup, name, ubo)
+# define DRW_shgroup_storage_block_ref(shgroup, name, ubo) \
+ DRW_shgroup_storage_block_ref_ex(shgroup, name, ubo)
#endif
bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup);
diff --git a/source/blender/draw/intern/draw_cache_impl_curves.cc b/source/blender/draw/intern/draw_cache_impl_curves.cc
index aea71d965d1..a21a6409ca5 100644
--- a/source/blender/draw/intern/draw_cache_impl_curves.cc
+++ b/source/blender/draw/intern/draw_cache_impl_curves.cc
@@ -138,20 +138,20 @@ static void curves_batch_cache_fill_segments_proc_pos(Curves *curves,
Span<float3> positions = geometry.positions();
for (const int i : IndexRange(curve_size)) {
- const IndexRange curve_range = geometry.range_for_curve(i);
+ const IndexRange curve_range = geometry.points_for_curve(i);
- Span<float3> spline_positions = positions.slice(curve_range);
+ Span<float3> curve_positions = positions.slice(curve_range);
float total_len = 0.0f;
float *seg_data_first;
- for (const int i_spline : spline_positions.index_range()) {
+ for (const int i_curve : curve_positions.index_range()) {
float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step);
- copy_v3_v3(seg_data, spline_positions[i_spline]);
- if (i_spline == 0) {
+ copy_v3_v3(seg_data, curve_positions[i_curve]);
+ if (i_curve == 0) {
seg_data_first = seg_data;
}
else {
- total_len += blender::math::distance(spline_positions[i_spline - 1],
- spline_positions[i_spline]);
+ total_len += blender::math::distance(curve_positions[i_curve - 1],
+ curve_positions[i_curve]);
}
seg_data[3] = total_len;
}
@@ -159,7 +159,7 @@ static void curves_batch_cache_fill_segments_proc_pos(Curves *curves,
*(float *)GPU_vertbuf_raw_step(length_step) = total_len;
if (total_len > 0.0f) {
/* Divide by total length to have a [0-1] number. */
- for ([[maybe_unused]] const int i_spline : spline_positions.index_range()) {
+ for ([[maybe_unused]] const int i_curve : curve_positions.index_range()) {
seg_data_first[3] /= total_len;
seg_data_first += 4;
}
@@ -218,8 +218,8 @@ static void curves_batch_cache_fill_strands_data(Curves *curves,
const blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap(
curves->geometry);
- for (const int i : IndexRange(geometry.curves_size())) {
- const IndexRange curve_range = geometry.range_for_curve(i);
+ for (const int i : IndexRange(geometry.curves_num())) {
+ const IndexRange curve_range = geometry.points_for_curve(i);
*(uint *)GPU_vertbuf_raw_step(data_step) = curve_range.start();
*(ushort *)GPU_vertbuf_raw_step(seg_step) = curve_range.size() - 1;
diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c
index 08c33555b71..a4465b9aed4 100644
--- a/source/blender/draw/intern/draw_cache_impl_gpencil.c
+++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c
@@ -28,6 +28,8 @@
#include "draw_cache.h"
#include "draw_cache_impl.h"
+#include "../engines/gpencil/gpencil_defines.h"
+
#define BEZIER_HANDLE (1 << 3)
#define COLOR_SHIFT 5
@@ -321,7 +323,7 @@ static void gpencil_buffer_add_point(gpStrokeVert *verts,
vert->point_id = v;
vert->thickness = max_ff(0.0f, gps->thickness * pt->pressure) * (round_cap1 ? 1.0f : -1.0f);
/* Tag endpoint material to -1 so they get discarded by vertex shader. */
- vert->mat = (is_endpoint) ? -1 : (gps->mat_nr % GP_MATERIAL_BUFFER_LEN);
+ vert->mat = (is_endpoint) ? -1 : (gps->mat_nr % GPENCIL_MATERIAL_BUFFER_LEN);
float aspect_ratio = gps->aspect_ratio[0] / max_ff(gps->aspect_ratio[1], 1e-8);
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index 8682a15feba..8aa7ff66d65 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -1244,15 +1244,17 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, GPUVertBuf *pos_no
GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION);
GPU_shader_bind(shader);
- GPU_vertbuf_bind_as_ssbo(src_buffer, 0);
- GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, 1);
- GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, 2);
- GPU_vertbuf_bind_as_ssbo(cache->patch_coords, 3);
- GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, 4);
- GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, 5);
- GPU_vertbuf_bind_as_ssbo(patch_index_buffer, 6);
- GPU_vertbuf_bind_as_ssbo(patch_param_buffer, 7);
- GPU_vertbuf_bind_as_ssbo(pos_nor, 8);
+ int binding_point = 0;
+ GPU_vertbuf_bind_as_ssbo(src_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->patch_coords, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(patch_index_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(patch_param_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+ BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
@@ -1308,15 +1310,17 @@ void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION_FVAR);
GPU_shader_bind(shader);
- GPU_vertbuf_bind_as_ssbo(src_buffer, 0);
- GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, 1);
- GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, 2);
- GPU_vertbuf_bind_as_ssbo(cache->patch_coords, 3);
- GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, 4);
- GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, 5);
- GPU_vertbuf_bind_as_ssbo(patch_index_buffer, 6);
- GPU_vertbuf_bind_as_ssbo(patch_param_buffer, 7);
- GPU_vertbuf_bind_as_ssbo(uvs, 8);
+ int binding_point = 0;
+ GPU_vertbuf_bind_as_ssbo(src_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->patch_coords, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(patch_index_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(patch_param_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(uvs, binding_point++);
+ BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
/* The buffer offset has the stride baked in (which is 2 as we have UVs) so remove the stride by
* dividing by 2 */
@@ -1380,13 +1384,15 @@ void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
GPU_shader_bind(shader);
+ int binding_point = 0;
/* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
- GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0);
- GPU_vertbuf_bind_as_ssbo(src_data, 1);
- GPU_vertbuf_bind_as_ssbo(cache->face_ptex_offset_buffer, 2);
- GPU_vertbuf_bind_as_ssbo(cache->patch_coords, 3);
- GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, 4);
- GPU_vertbuf_bind_as_ssbo(dst_data, 5);
+ GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(src_data, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->face_ptex_offset_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->patch_coords, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(dst_data, binding_point++);
+ BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, dst_offset, cache->num_subdiv_quads);
@@ -1406,12 +1412,15 @@ void draw_subdiv_build_sculpt_data_buffer(const DRWSubdivCache *cache,
GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_SCULPT_DATA, nullptr);
GPU_shader_bind(shader);
+ /* Mask VBO is always at binding point 0. */
if (mask_vbo) {
GPU_vertbuf_bind_as_ssbo(mask_vbo, 0);
}
- GPU_vertbuf_bind_as_ssbo(face_set_vbo, 1);
- GPU_vertbuf_bind_as_ssbo(sculpt_data, 2);
+ int binding_point = 1;
+ GPU_vertbuf_bind_as_ssbo(face_set_vbo, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(sculpt_data, binding_point++);
+ BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads, mask_vbo != nullptr);
@@ -1439,6 +1448,7 @@ void draw_subdiv_accumulate_normals(const DRWSubdivCache *cache,
GPU_vertbuf_bind_as_ssbo(face_adjacency_lists, binding_point++);
GPU_vertbuf_bind_as_ssbo(vertex_loop_map, binding_point++);
GPU_vertbuf_bind_as_ssbo(vertex_normals, binding_point++);
+ BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_verts);
@@ -1463,6 +1473,7 @@ void draw_subdiv_finalize_normals(const DRWSubdivCache *cache,
GPU_vertbuf_bind_as_ssbo(vertex_normals, binding_point++);
GPU_vertbuf_bind_as_ssbo(subdiv_loop_subdiv_vert_index, binding_point++);
GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+ BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
@@ -1482,9 +1493,12 @@ void draw_subdiv_finalize_custom_normals(const DRWSubdivCache *cache,
GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_NORMALS_FINALIZE, "#define CUSTOM_NORMALS");
GPU_shader_bind(shader);
- GPU_vertbuf_bind_as_ssbo(src_custom_normals, 0);
+ int binding_point = 0;
+ GPU_vertbuf_bind_as_ssbo(src_custom_normals, binding_point++);
/* outputPosNor is bound at index 2 in the base shader. */
- GPU_vertbuf_bind_as_ssbo(pos_nor, 2);
+ binding_point = 2;
+ GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+ BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
@@ -1519,15 +1533,22 @@ void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache,
do_single_material ? SHADER_BUFFER_TRIS : SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS, defines);
GPU_shader_bind(shader);
- /* Outputs */
- GPU_indexbuf_bind_as_ssbo(subdiv_tris, 1);
-
if (!do_single_material) {
- GPU_vertbuf_bind_as_ssbo(cache->polygon_mat_offset, 2);
/* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0);
}
+ int binding_point = 1;
+
+ /* Outputs */
+ GPU_indexbuf_bind_as_ssbo(subdiv_tris, binding_point++);
+
+ if (!do_single_material) {
+ GPU_vertbuf_bind_as_ssbo(cache->polygon_mat_offset, binding_point++);
+ }
+
+ BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
+
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
/* This generates an index buffer, so we need to put a barrier on the element array. */
@@ -1574,18 +1595,20 @@ void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION_FACE_DOTS);
GPU_shader_bind(shader);
- GPU_vertbuf_bind_as_ssbo(src_buffer, 0);
- GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, 1);
- GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, 2);
- GPU_vertbuf_bind_as_ssbo(cache->fdots_patch_coords, 3);
- GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, 4);
- GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, 5);
- GPU_vertbuf_bind_as_ssbo(patch_index_buffer, 6);
- GPU_vertbuf_bind_as_ssbo(patch_param_buffer, 7);
- GPU_vertbuf_bind_as_ssbo(fdots_pos, 8);
- GPU_vertbuf_bind_as_ssbo(fdots_nor, 9);
- GPU_indexbuf_bind_as_ssbo(fdots_indices, 10);
- GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, 11);
+ int binding_point = 0;
+ GPU_vertbuf_bind_as_ssbo(src_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->fdots_patch_coords, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(patch_index_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(patch_param_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(fdots_pos, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(fdots_nor, binding_point++);
+ GPU_indexbuf_bind_as_ssbo(fdots_indices, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
+ BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_coarse_poly);
@@ -1607,8 +1630,10 @@ void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache, GPUIndexBuf *li
GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LINES, nullptr);
GPU_shader_bind(shader);
- GPU_vertbuf_bind_as_ssbo(cache->edges_orig_index, 0);
- GPU_indexbuf_bind_as_ssbo(lines_indices, 1);
+ int binding_point = 0;
+ GPU_vertbuf_bind_as_ssbo(cache->edges_orig_index, binding_point++);
+ GPU_indexbuf_bind_as_ssbo(lines_indices, binding_point++);
+ BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
@@ -1648,9 +1673,11 @@ void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache,
GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_EDGE_FAC, defines);
GPU_shader_bind(shader);
- GPU_vertbuf_bind_as_ssbo(pos_nor, 0);
- GPU_vertbuf_bind_as_ssbo(edge_idx, 1);
- GPU_vertbuf_bind_as_ssbo(edge_fac, 2);
+ int binding_point = 0;
+ GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(edge_idx, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(edge_fac, binding_point++);
+ BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
@@ -1673,14 +1700,16 @@ void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache,
GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LNOR, "#define SUBDIV_POLYGON_OFFSET\n");
GPU_shader_bind(shader);
+ int binding_point = 0;
/* Inputs */
- GPU_vertbuf_bind_as_ssbo(pos_nor, 1);
- GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, 2);
/* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
- GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0);
+ GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, binding_point++);
/* Outputs */
- GPU_vertbuf_bind_as_ssbo(lnor, 3);
+ GPU_vertbuf_bind_as_ssbo(lnor, binding_point++);
+ BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
@@ -1699,13 +1728,15 @@ void draw_subdiv_build_edituv_stretch_area_buffer(const DRWSubdivCache *cache,
"#define SUBDIV_POLYGON_OFFSET\n");
GPU_shader_bind(shader);
+ int binding_point = 0;
/* Inputs */
- GPU_vertbuf_bind_as_ssbo(coarse_data, 1);
/* subdiv_polygon_offset is always at binding point 0 for each shader using it. */
- GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0);
+ GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(coarse_data, binding_point++);
/* Outputs */
- GPU_vertbuf_bind_as_ssbo(subdiv_data, 2);
+ GPU_vertbuf_bind_as_ssbo(subdiv_data, binding_point++);
+ BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
@@ -1725,12 +1756,14 @@ void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache *cache,
GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_UV_STRETCH_ANGLE, nullptr);
GPU_shader_bind(shader);
+ int binding_point = 0;
/* Inputs */
- GPU_vertbuf_bind_as_ssbo(pos_nor, 0);
- GPU_vertbuf_bind_as_ssbo(uvs, 1);
+ GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(uvs, binding_point++);
/* Outputs */
- GPU_vertbuf_bind_as_ssbo(stretch_angles, 2);
+ GPU_vertbuf_bind_as_ssbo(stretch_angles, binding_point++);
+ BLI_assert(binding_point <= MAX_GPU_SUBDIV_SSBOS);
drw_subdiv_compute_dispatch(cache, shader, uvs_offset, 0, cache->num_subdiv_quads);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 2886fe53879..39ae01697a1 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -85,6 +85,7 @@
#include "engines/basic/basic_engine.h"
#include "engines/eevee/eevee_engine.h"
+#include "engines/eevee_next/eevee_engine.h"
#include "engines/external/external_engine.h"
#include "engines/gpencil/gpencil_engine.h"
#include "engines/image/image_engine.h"
@@ -615,7 +616,7 @@ static void drw_manager_init(DRWManager *dst, GPUViewport *viewport, const int s
}
if (G_draw.view_ubo == NULL) {
- G_draw.view_ubo = GPU_uniformbuf_create_ex(sizeof(DRWViewUboStorage), NULL, "G_draw.view_ubo");
+ G_draw.view_ubo = GPU_uniformbuf_create_ex(sizeof(ViewInfos), NULL, "G_draw.view_ubo");
}
if (dst->draw_list == NULL) {
@@ -2898,6 +2899,13 @@ void DRW_engine_register(DrawEngineType *draw_engine_type)
g_registered_engines.len = BLI_listbase_count(&g_registered_engines.engines);
}
+void DRW_engines_register_experimental(void)
+{
+ if (U.experimental.enable_eevee_next) {
+ RE_engines_register(&DRW_engine_viewport_eevee_next_type);
+ }
+}
+
void DRW_engines_register(void)
{
RE_engines_register(&DRW_engine_viewport_eevee_type);
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index 06643439bbc..832897b7040 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -27,6 +27,7 @@
#include "GPU_viewport.h"
#include "draw_instance_data.h"
+#include "draw_shader_shared.h"
#ifdef __cplusplus
extern "C" {
@@ -191,6 +192,7 @@ typedef enum {
/* Compute Commands. */
DRW_CMD_COMPUTE = 8,
DRW_CMD_COMPUTE_REF = 9,
+ DRW_CMD_COMPUTE_INDIRECT = 10,
/* Other Commands */
DRW_CMD_BARRIER = 11,
@@ -240,6 +242,10 @@ typedef struct DRWCommandComputeRef {
int *groups_ref;
} DRWCommandComputeRef;
+typedef struct DRWCommandComputeIndirect {
+ GPUStorageBuf *indirect_buf;
+} DRWCommandComputeIndirect;
+
typedef struct DRWCommandBarrier {
eGPUBarrier type;
} DRWCommandBarrier;
@@ -282,6 +288,7 @@ typedef union DRWCommand {
DRWCommandDrawProcedural procedural;
DRWCommandCompute compute;
DRWCommandComputeRef compute_ref;
+ DRWCommandComputeIndirect compute_indirect;
DRWCommandBarrier barrier;
DRWCommandSetMutableState state;
DRWCommandSetStencil stencil;
@@ -309,6 +316,8 @@ typedef enum {
DRW_UNIFORM_IMAGE_REF,
DRW_UNIFORM_BLOCK,
DRW_UNIFORM_BLOCK_REF,
+ DRW_UNIFORM_STORAGE_BLOCK,
+ DRW_UNIFORM_STORAGE_BLOCK_REF,
DRW_UNIFORM_TFEEDBACK_TARGET,
DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE,
DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE_REF,
@@ -343,6 +352,11 @@ struct DRWUniform {
GPUUniformBuf *block;
GPUUniformBuf **block_ref;
};
+ /* DRW_UNIFORM_STORAGE_BLOCK */
+ union {
+ GPUStorageBuf *ssbo;
+ GPUStorageBuf **ssbo_ref;
+ };
/* DRW_UNIFORM_VERTEX_BUFFER_AS_STORAGE */
union {
GPUVertBuf *vertbuf;
@@ -411,32 +425,14 @@ struct DRWPass {
char name[MAX_PASS_NAME];
};
-/* keep in sync with viewBlock */
-typedef struct DRWViewUboStorage {
- /* View matrices */
- float persmat[4][4];
- float persinv[4][4];
- float viewmat[4][4];
- float viewinv[4][4];
- float winmat[4][4];
- float wininv[4][4];
-
- float clipplanes[6][4];
- float viewvecs[2][4];
- /* Should not be here. Not view dependent (only main view). */
- float viewcamtexcofac[4];
-} DRWViewUboStorage;
-
-BLI_STATIC_ASSERT_ALIGN(DRWViewUboStorage, 16)
-
#define MAX_CULLED_VIEWS 32
struct DRWView {
/** Parent view if this is a sub view. NULL otherwise. */
struct DRWView *parent;
- DRWViewUboStorage storage;
- /** Number of active clipplanes. */
+ ViewInfos storage;
+ /** Number of active clip planes. */
int clip_planes_len;
/** Does culling result needs to be updated. */
bool is_dirty;
@@ -620,7 +616,7 @@ typedef struct DRWManager {
uint primary_view_ct;
/** TODO(@fclem): Remove this. Only here to support
* shaders without common_view_lib.glsl */
- DRWViewUboStorage view_storage_cpy;
+ ViewInfos view_storage_cpy;
#ifdef USE_GPU_SELECT
uint select_id;
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 95691a0df68..b01c901c77f 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -216,6 +216,8 @@ static void drw_shgroup_uniform(DRWShadingGroup *shgroup,
BLI_assert(arraysize > 0 && arraysize <= 16);
BLI_assert(length >= 0 && length <= 16);
BLI_assert(!ELEM(type,
+ DRW_UNIFORM_STORAGE_BLOCK,
+ DRW_UNIFORM_STORAGE_BLOCK_REF,
DRW_UNIFORM_BLOCK,
DRW_UNIFORM_BLOCK_REF,
DRW_UNIFORM_TEXTURE,
@@ -310,6 +312,50 @@ void DRW_shgroup_uniform_block_ref_ex(DRWShadingGroup *shgroup,
drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_BLOCK_REF, ubo, 0, 0, 1);
}
+void DRW_shgroup_storage_block_ex(DRWShadingGroup *shgroup,
+ const char *name,
+ const GPUStorageBuf *ssbo DRW_DEBUG_FILE_LINE_ARGS)
+{
+ BLI_assert(ssbo != NULL);
+ /* TODO(@fclem): Fix naming inconsistency. */
+ int loc = GPU_shader_get_ssbo(shgroup->shader, name);
+ if (loc == -1) {
+#ifdef DRW_UNUSED_RESOURCE_TRACKING
+ printf("%s:%d: Unable to locate binding of shader storage buffer object: %s.\n",
+ file,
+ line,
+ name);
+#else
+ /* TODO(@fclem): Would be good to have, but eevee has too much of this for the moment. */
+ // BLI_assert_msg(0, "Unable to locate binding of shader storage buffer objects.");
+#endif
+ return;
+ }
+ drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_STORAGE_BLOCK, ssbo, 0, 0, 1);
+}
+
+void DRW_shgroup_storage_block_ref_ex(DRWShadingGroup *shgroup,
+ const char *name,
+ GPUStorageBuf **ssbo DRW_DEBUG_FILE_LINE_ARGS)
+{
+ BLI_assert(ssbo != NULL);
+ /* TODO(@fclem): Fix naming inconsistency. */
+ int loc = GPU_shader_get_ssbo(shgroup->shader, name);
+ if (loc == -1) {
+#ifdef DRW_UNUSED_RESOURCE_TRACKING
+ printf("%s:%d: Unable to locate binding of shader storage buffer object: %s.\n",
+ file,
+ line,
+ name);
+#else
+ /* TODO(@fclem): Would be good to have, but eevee has too much of this for the moment. */
+ // BLI_assert_msg(0, "Unable to locate binding of shader storage buffer objects.");
+#endif
+ return;
+ }
+ drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_STORAGE_BLOCK_REF, ssbo, 0, 0, 1);
+}
+
void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup,
const char *name,
const int *value,
@@ -774,6 +820,12 @@ static void drw_command_compute_ref(DRWShadingGroup *shgroup, int groups_ref[3])
cmd->groups_ref = groups_ref;
}
+static void drw_command_compute_indirect(DRWShadingGroup *shgroup, GPUStorageBuf *indirect_buf)
+{
+ DRWCommandComputeIndirect *cmd = drw_command_create(shgroup, DRW_CMD_COMPUTE_INDIRECT);
+ cmd->indirect_buf = indirect_buf;
+}
+
static void drw_command_barrier(DRWShadingGroup *shgroup, eGPUBarrier type)
{
DRWCommandBarrier *cmd = drw_command_create(shgroup, DRW_CMD_BARRIER);
@@ -912,6 +964,12 @@ void DRW_shgroup_call_compute_ref(DRWShadingGroup *shgroup, int groups_ref[3])
drw_command_compute_ref(shgroup, groups_ref);
}
+void DRW_shgroup_call_compute_indirect(DRWShadingGroup *shgroup, GPUStorageBuf *indirect_buf)
+{
+ BLI_assert(GPU_compute_shader_support());
+
+ drw_command_compute_indirect(shgroup, indirect_buf);
+}
void DRW_shgroup_barrier(DRWShadingGroup *shgroup, eGPUBarrier type)
{
BLI_assert(GPU_compute_shader_support());
@@ -1767,7 +1825,7 @@ static void draw_frustum_bound_sphere_calc(const BoundBox *bbox,
}
}
-static void draw_view_matrix_state_update(DRWViewUboStorage *storage,
+static void draw_view_matrix_state_update(ViewInfos *storage,
const float viewmat[4][4],
const float winmat[4][4])
{
@@ -1979,7 +2037,7 @@ void DRW_view_clip_planes_set(DRWView *view, float (*planes)[4], int plane_len)
BLI_assert(plane_len <= MAX_CLIP_PLANES);
view->clip_planes_len = plane_len;
if (plane_len > 0) {
- memcpy(view->storage.clipplanes, planes, sizeof(float[4]) * plane_len);
+ memcpy(view->storage.clip_planes, planes, sizeof(float[4]) * plane_len);
}
}
@@ -2031,21 +2089,21 @@ float DRW_view_far_distance_get(const DRWView *view)
void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse)
{
view = (view) ? view : DST.view_default;
- const DRWViewUboStorage *storage = &view->storage;
+ const ViewInfos *storage = &view->storage;
copy_m4_m4(mat, (inverse) ? storage->viewinv : storage->viewmat);
}
void DRW_view_winmat_get(const DRWView *view, float mat[4][4], bool inverse)
{
view = (view) ? view : DST.view_default;
- const DRWViewUboStorage *storage = &view->storage;
+ const ViewInfos *storage = &view->storage;
copy_m4_m4(mat, (inverse) ? storage->wininv : storage->winmat);
}
void DRW_view_persmat_get(const DRWView *view, float mat[4][4], bool inverse)
{
view = (view) ? view : DST.view_default;
- const DRWViewUboStorage *storage = &view->storage;
+ const ViewInfos *storage = &view->storage;
copy_m4_m4(mat, (inverse) ? storage->persinv : storage->persmat);
}
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 07e47a0c691..7d6ce51ff35 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -319,6 +319,7 @@ void DRW_state_reset(void)
GPU_texture_unbind_all();
GPU_uniformbuf_unbind_all();
+ GPU_storagebuf_unbind_all();
/* Should stay constant during the whole rendering. */
GPU_point_size(5);
@@ -621,6 +622,12 @@ static void draw_update_uniforms(DRWShadingGroup *shgroup,
case DRW_UNIFORM_BLOCK_REF:
GPU_uniformbuf_bind(*uni->block_ref, uni->location);
break;
+ case DRW_UNIFORM_STORAGE_BLOCK:
+ GPU_storagebuf_bind(uni->ssbo, uni->location);
+ break;
+ case DRW_UNIFORM_STORAGE_BLOCK_REF:
+ GPU_storagebuf_bind(*uni->ssbo_ref, uni->location);
+ break;
case DRW_UNIFORM_BLOCK_OBMATS:
state->obmats_loc = uni->location;
GPU_uniformbuf_bind(DST.vmempool->matrices_ubo[0], uni->location);
@@ -915,6 +922,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
if (G.debug & G_DEBUG_GPU) {
GPU_texture_unbind_all();
GPU_uniformbuf_unbind_all();
+ GPU_storagebuf_unbind_all();
}
}
GPU_shader_bind(shgroup->shader);
@@ -1043,6 +1051,9 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
cmd->compute_ref.groups_ref[1],
cmd->compute_ref.groups_ref[2]);
break;
+ case DRW_CMD_COMPUTE_INDIRECT:
+ GPU_compute_dispatch_indirect(shgroup->shader, cmd->compute_indirect.indirect_buf);
+ break;
case DRW_CMD_BARRIER:
GPU_memory_barrier(cmd->barrier.type);
break;
@@ -1057,8 +1068,13 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
}
}
-static void drw_update_view(void)
+static void drw_update_view(const float viewport_size[2])
{
+ ViewInfos *storage = &DST.view_active->storage;
+ copy_v2_v2(storage->viewport_size, viewport_size);
+ copy_v2_v2(storage->viewport_size_inverse, viewport_size);
+ invert_v2(storage->viewport_size_inverse);
+
/* TODO(fclem): update a big UBO and only bind ranges here. */
GPU_uniformbuf_update(G_draw.view_ubo, &DST.view_active->storage);
@@ -1086,8 +1102,11 @@ static void drw_draw_pass_ex(DRWPass *pass,
BLI_assert(DST.buffer_finish_called &&
"DRW_render_instance_buffer_finish had not been called before drawing");
- if (DST.view_previous != DST.view_active || DST.view_active->is_dirty) {
- drw_update_view();
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ if (DST.view_previous != DST.view_active || DST.view_active->is_dirty ||
+ !equals_v2v2(DST.view_active->storage.viewport_size, &viewport[2])) {
+ drw_update_view(&viewport[2]);
DST.view_active->is_dirty = false;
DST.view_previous = DST.view_active;
}
diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h
index 687cf8bd2fb..5fc76bc25e6 100644
--- a/source/blender/draw/intern/draw_shader_shared.h
+++ b/source/blender/draw/intern/draw_shader_shared.h
@@ -2,6 +2,10 @@
#ifndef GPU_SHADER
# include "GPU_shader_shared_utils.h"
+
+typedef struct ViewInfos ViewInfos;
+typedef struct ObjectMatrices ObjectMatrices;
+typedef struct ObjectInfos ObjectInfos;
#endif
#define DRW_SHADER_SHARED_H
@@ -21,6 +25,14 @@ struct ViewInfos {
float4 viewvecs[2];
/* Should not be here. Not view dependent (only main view). */
float4 viewcamtexcofac;
+
+ float2 viewport_size;
+ float2 viewport_size_inverse;
+
+ /** Frustum culling data. */
+ /** NOTE: vec3 arrays are padded to vec4. */
+ float4 frustum_corners[8];
+ float4 frustum_planes[6];
};
BLI_STATIC_ASSERT_ALIGN(ViewInfos, 16)
diff --git a/source/blender/draw/intern/draw_texture_pool.cc b/source/blender/draw/intern/draw_texture_pool.cc
index b54df928418..b36cb5c809e 100644
--- a/source/blender/draw/intern/draw_texture_pool.cc
+++ b/source/blender/draw/intern/draw_texture_pool.cc
@@ -23,6 +23,10 @@ struct DRWTexturePool {
Vector<DRWTexturePoolHandle> handles;
/* Cache last result to avoid linear search each time. */
int last_user_id = -1;
+
+ Vector<GPUTexture *> tmp_tex_pruned;
+ Vector<GPUTexture *> tmp_tex_released;
+ Vector<GPUTexture *> tmp_tex_acquired;
};
DRWTexturePool *DRW_texture_pool_create()
@@ -94,6 +98,68 @@ GPUTexture *DRW_texture_pool_query(
return handle.texture;
}
+GPUTexture *DRW_texture_pool_texture_acquire(DRWTexturePool *pool,
+ int width,
+ int height,
+ eGPUTextureFormat format)
+{
+ GPUTexture *tmp_tex = nullptr;
+ int64_t found_index = 0;
+
+ auto texture_match = [&](GPUTexture *tex) -> bool {
+ /* TODO(@fclem): We could reuse texture using texture views if the formats are compatible. */
+ return (GPU_texture_format(tex) == format) && (GPU_texture_width(tex) == width) &&
+ (GPU_texture_height(tex) == height);
+ };
+
+ /* Search released texture first. */
+ for (auto i : pool->tmp_tex_released.index_range()) {
+ if (texture_match(pool->tmp_tex_released[i])) {
+ tmp_tex = pool->tmp_tex_released[i];
+ found_index = i;
+ break;
+ }
+ }
+
+ if (tmp_tex) {
+ pool->tmp_tex_released.remove_and_reorder(found_index);
+ }
+ else {
+ /* Then search pruned texture. */
+ for (auto i : pool->tmp_tex_pruned.index_range()) {
+ if (texture_match(pool->tmp_tex_pruned[i])) {
+ tmp_tex = pool->tmp_tex_pruned[i];
+ found_index = i;
+ break;
+ }
+ }
+
+ if (tmp_tex) {
+ pool->tmp_tex_pruned.remove_and_reorder(found_index);
+ }
+ }
+
+ if (!tmp_tex) {
+ /* Create a new texture in last resort. */
+ char name[16] = "DRW_tex_pool";
+ if (G.debug & G_DEBUG_GPU) {
+ int texture_id = pool->handles.size();
+ SNPRINTF(name, "DRW_tex_pool_%d", texture_id);
+ }
+ tmp_tex = GPU_texture_create_2d(name, width, height, 1, format, nullptr);
+ }
+
+ pool->tmp_tex_acquired.append(tmp_tex);
+
+ return tmp_tex;
+}
+
+void DRW_texture_pool_texture_release(DRWTexturePool *pool, GPUTexture *tmp_tex)
+{
+ pool->tmp_tex_acquired.remove_first_occurrence_and_reorder(tmp_tex);
+ pool->tmp_tex_released.append(tmp_tex);
+}
+
void DRW_texture_pool_reset(DRWTexturePool *pool)
{
pool->last_user_id = -1;
@@ -117,4 +183,11 @@ void DRW_texture_pool_reset(DRWTexturePool *pool)
pool->handles.remove_and_reorder(i);
}
}
+
+ BLI_assert(pool->tmp_tex_acquired.is_empty());
+ for (GPUTexture *tmp_tex : pool->tmp_tex_pruned) {
+ GPU_texture_free(tmp_tex);
+ }
+ pool->tmp_tex_pruned = pool->tmp_tex_released;
+ pool->tmp_tex_released.clear();
}
diff --git a/source/blender/draw/intern/draw_texture_pool.h b/source/blender/draw/intern/draw_texture_pool.h
index 5a7915e15e7..1c30ea88552 100644
--- a/source/blender/draw/intern/draw_texture_pool.h
+++ b/source/blender/draw/intern/draw_texture_pool.h
@@ -30,6 +30,17 @@ void DRW_texture_pool_free(DRWTexturePool *pool);
GPUTexture *DRW_texture_pool_query(
DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user);
/**
+ * Returns a temporary texture that needs to be released after use. Texture content is undefined.
+ */
+GPUTexture *DRW_texture_pool_texture_acquire(DRWTexturePool *pool,
+ int width,
+ int height,
+ eGPUTextureFormat format);
+/**
+ * Releases a previously acquired texture.
+ */
+void DRW_texture_pool_texture_release(DRWTexturePool *pool, GPUTexture *tmp_tex);
+/**
* Resets the user bits for each texture in the pool and delete unused ones.
*/
void DRW_texture_pool_reset(DRWTexturePool *pool);
diff --git a/source/blender/draw/intern/draw_view_data.cc b/source/blender/draw/intern/draw_view_data.cc
index 682728eb22b..0e55d28f6df 100644
--- a/source/blender/draw/intern/draw_view_data.cc
+++ b/source/blender/draw/intern/draw_view_data.cc
@@ -37,7 +37,10 @@ struct DRWViewData {
DRWViewData *DRW_view_data_create(ListBase *engine_types)
{
+ const int engine_types_len = BLI_listbase_count(engine_types);
+
DRWViewData *view_data = new DRWViewData();
+ view_data->engines.reserve(engine_types_len);
LISTBASE_FOREACH (DRWRegisteredDrawEngine *, type, engine_types) {
ViewportEngineData engine = {};
engine.engine_type = type;
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 ae536f0b87c..27149a80f9b 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
@@ -419,7 +419,7 @@ static void extract_edituv_points_init_subdiv(const DRWSubdivCache *subdiv_cache
}
static void extract_edituv_points_iter_subdiv_bm(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *mr,
+ const MeshRenderData *UNUSED(mr),
void *_data,
uint subdiv_quad_index,
const BMFace *coarse_quad)
@@ -431,11 +431,8 @@ static void extract_edituv_points_iter_subdiv_bm(const DRWSubdivCache *subdiv_ca
uint end_loop_idx = (subdiv_quad_index + 1) * 4;
for (uint i = start_loop_idx; i < end_loop_idx; i++) {
const int vert_origindex = subdiv_loop_vert_index[i];
- const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) &&
- vert_origindex != -1 &&
- mr->v_origindex[vert_origindex] != ORIGINDEX_NONE);
edituv_point_add(data,
- (BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN)) || !real_vert,
+ (BM_elem_flag_test(coarse_quad, BM_ELEM_HIDDEN) || vert_origindex == -1),
BM_elem_flag_test(coarse_quad, BM_ELEM_SELECT) != 0,
i);
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
index 2dfd2cd43dc..f79fe345f5a 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc
@@ -137,7 +137,7 @@ static void extract_edituv_data_iter_subdiv_bm(const DRWSubdivCache *subdiv_cach
uint end_loop_idx = (subdiv_quad_index + 1) * 4;
for (uint i = start_loop_idx; i < end_loop_idx; i++) {
const int vert_origindex = subdiv_loop_vert_index[i];
- const int edge_origindex = subdiv_loop_edge_index[i];
+ int edge_origindex = subdiv_loop_edge_index[i];
EditLoopData *edit_loop_data = &data->vbo_data[i];
memset(edit_loop_data, 0, sizeof(EditLoopData));
@@ -149,6 +149,22 @@ static void extract_edituv_data_iter_subdiv_bm(const DRWSubdivCache *subdiv_cach
mesh_render_data_loop_flag(mr, l, data->cd_ofs, edit_loop_data);
mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, edit_loop_data);
}
+ else {
+ if (edge_origindex == -1) {
+ /* Find if the loop's vert is not part of an edit edge.
+ * For this, we check if the previous loop was on an edge. */
+ const uint loop_index_last = (i == start_loop_idx) ? end_loop_idx - 1 : i - 1;
+ edge_origindex = subdiv_loop_edge_index[loop_index_last];
+ }
+ if (edge_origindex != -1) {
+ /* Mapped points on an edge between two edit verts. */
+ BMEdge *eed = BM_edge_at_index(mr->bm, edge_origindex);
+ BMLoop *l = BM_face_edge_share_loop(const_cast<BMFace *>(coarse_quad), eed);
+ mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, edit_loop_data);
+ }
+ }
+
+ mesh_render_data_face_flag(mr, coarse_quad, data->cd_ofs, edit_loop_data);
}
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
index b532ff0080e..4532f3c3710 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc
@@ -134,7 +134,7 @@ static void extract_uv_init_subdiv(const DRWSubdivCache *subdiv_cache,
uint uv_layers;
if (!mesh_extract_uv_format_init(
&format, cache, &coarse_mesh->ldata, MR_EXTRACT_MESH, uv_layers)) {
- // TODO(kevindietrich): handle this more gracefully.
+ /* TODO(kevindietrich): handle this more gracefully. */
v_len = 1;
}
diff --git a/source/blender/draw/intern/shaders/common_gpencil_lib.glsl b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl
new file mode 100644
index 00000000000..9e3c219a30b
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_gpencil_lib.glsl
@@ -0,0 +1,409 @@
+
+#pragma BLENDER_REQUIRE(common_view_lib.glsl)
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+
+#ifndef DRW_GPENCIL_INFO
+# error "Missing additional info draw_gpencil"
+#endif
+
+#ifdef GPU_FRAGMENT_SHADER
+float gpencil_stroke_round_cap_mask(vec2 p1, vec2 p2, vec2 aspect, float thickness, float hardfac)
+{
+ /* We create our own uv space to avoid issues with triangulation and linear
+ * interpolation artifacts. */
+ vec2 line = p2.xy - p1.xy;
+ vec2 pos = gl_FragCoord.xy - p1.xy;
+ float line_len = length(line);
+ float half_line_len = line_len * 0.5;
+ /* Normalize */
+ line = (line_len > 0.0) ? (line / line_len) : vec2(1.0, 0.0);
+ /* Create a uv space that englobe the whole segment into a capsule. */
+ vec2 uv_end;
+ uv_end.x = max(abs(dot(line, pos) - half_line_len) - half_line_len, 0.0);
+ uv_end.y = dot(vec2(-line.y, line.x), pos);
+ /* Divide by stroke radius. */
+ uv_end /= thickness;
+ uv_end *= aspect;
+
+ float dist = clamp(1.0 - length(uv_end) * 2.0, 0.0, 1.0);
+ if (hardfac > 0.999) {
+ return step(1e-8, dist);
+ }
+ else {
+ /* Modulate the falloff profile */
+ float hardness = 1.0 - hardfac;
+ dist = pow(dist, mix(0.01, 10.0, hardness));
+ return smoothstep(0.0, 1.0, dist);
+ }
+}
+#endif
+
+vec2 gpencil_decode_aspect(int packed_data)
+{
+ float asp = float(uint(packed_data) & 0x1FFu) * (1.0 / 255.0);
+ return (asp > 1.0) ? vec2(1.0, (asp - 1.0)) : vec2(asp, 1.0);
+}
+
+float gpencil_decode_uvrot(int packed_data)
+{
+ uint udata = uint(packed_data);
+ float uvrot = 1e-8 + float((udata & 0x1FE00u) >> 9u) * (1.0 / 255.0);
+ return ((udata & 0x20000u) != 0u) ? -uvrot : uvrot;
+}
+
+float gpencil_decode_hardness(int packed_data)
+{
+ return float((uint(packed_data) & 0x3FC0000u) >> 18u) * (1.0 / 255.0);
+}
+
+vec2 gpencil_project_to_screenspace(vec4 v, vec4 viewport_size)
+{
+ return ((v.xy / v.w) * 0.5 + 0.5) * viewport_size.xy;
+}
+
+float gpencil_stroke_thickness_modulate(float thickness, vec4 ndc_pos, vec4 viewport_size)
+{
+ /* Modify stroke thickness by object and layer factors. */
+ thickness = max(1.0, thickness * gpThicknessScale + gpThicknessOffset);
+
+ if (gpThicknessIsScreenSpace) {
+ /* Multiply offset by view Z so that offset is constant in screenspace.
+ * (e.i: does not change with the distance to camera) */
+ thickness *= ndc_pos.w;
+ }
+ else {
+ /* World space point size. */
+ thickness *= gpThicknessWorldScale * ProjectionMatrix[1][1] * viewport_size.y;
+ }
+ return thickness;
+}
+
+float gpencil_clamp_small_stroke_thickness(float thickness, vec4 ndc_pos)
+{
+ /* To avoid aliasing artifacts, we clamp the line thickness and
+ * reduce its opacity in the fragment shader.*/
+ float min_thickness = ndc_pos.w * 1.3;
+ thickness = max(min_thickness, thickness);
+
+ return thickness;
+}
+
+#ifdef GPU_VERTEX_SHADER
+
+/* Trick to detect if a drawcall is stroke or fill.
+ * This does mean that we need to draw an empty stroke segment before starting
+ * to draw the real stroke segments. */
+# define GPENCIL_IS_STROKE_VERTEX (gl_InstanceID != 0)
+
+/**
+ * Returns value of gl_Position.
+ *
+ * To declare in vertex shader.
+ * in ivec4 ma, ma1, ma2, ma3;
+ * in vec4 pos, pos1, pos2, pos3, uv1, uv2, col1, col2, fcol1;
+ *
+ * All of these attributes are quad loaded the same way
+ * as GL_LINES_ADJACENCY would feed a geometry shader:
+ * - ma reference the previous adjacency point.
+ * - ma1 reference the current line first point.
+ * - ma2 reference the current line second point.
+ * - ma3 reference the next adjacency point.
+ * Note that we are rendering quad instances and not using any index buffer
+ *(except for fills).
+ *
+ * Material : x is material index, y is stroke_id, z is point_id,
+ * w is aspect & rotation & hardness packed.
+ * Position : contains thickness in 4th component.
+ * UV : xy is UV for fills, z is U of stroke, w is strength.
+ *
+ *
+ * WARNING: Max attribute count is actually 14 because OSX OpenGL implementation
+ * considers gl_VertexID and gl_InstanceID as vertex attribute. (see T74536)
+ */
+vec4 gpencil_vertex(ivec4 ma,
+ ivec4 ma1,
+ ivec4 ma2,
+ ivec4 ma3,
+ vec4 pos,
+ vec4 pos1,
+ vec4 pos2,
+ vec4 pos3,
+ vec4 uv1,
+ vec4 uv2,
+ vec4 col1,
+ vec4 col2,
+ vec4 fcol1,
+ vec4 viewport_size,
+ gpMaterialFlag material_flags,
+ vec2 alignment_rot,
+ /* World Position. */
+ out vec3 out_P,
+ /* World Normal. */
+ out vec3 out_N,
+ /* Vertex Color. */
+ out vec4 out_color,
+ /* Stroke Strength. */
+ out float out_strength,
+ /* UV coordinates. */
+ out vec2 out_uv,
+ /* Screen-Space segment endpoints. */
+ out vec4 out_sspos,
+ /* Stroke aspect ratio. */
+ out vec2 out_aspect,
+ /* Stroke thickness (x: clamped, y: unclamped). */
+ out vec2 out_thickness,
+ /* Stroke hardness. */
+ out float out_hardness)
+{
+# define thickness1 pos1.w
+# define thickness2 pos2.w
+# define strength1 uv1.w
+# define strength2 uv2.w
+/* Packed! need to be decoded. */
+# define hardness1 ma1.w
+# define hardness2 ma2.w
+# define uvrot1 ma1.w
+# define aspect1 ma1.w
+
+ vec4 out_ndc;
+
+ if (GPENCIL_IS_STROKE_VERTEX) {
+ bool is_dot = flag_test(material_flags, GP_STROKE_ALIGNMENT);
+ bool is_squares = !flag_test(material_flags, GP_STROKE_ALIGNMENT);
+
+ /* Special Case. Stroke with single vert are rendered as dots. Do not discard them. */
+ if (!is_dot && ma.x == -1 && ma2.x == -1) {
+ is_dot = true;
+ is_squares = false;
+ }
+
+ /* Endpoints, we discard the vertices. */
+ if (ma1.x == -1 || (!is_dot && ma2.x == -1)) {
+ /* We set the vertex at the camera origin to generate 0 fragments. */
+ out_ndc = vec4(0.0, 0.0, -3e36, 0.0);
+ return out_ndc;
+ }
+
+ /* Avoid using a vertex attribute for quad positioning. */
+ float x = float(gl_VertexID & 1) * 2.0 - 1.0; /* [-1..1] */
+ float y = float(gl_VertexID & 2) - 1.0; /* [-1..1] */
+
+ bool use_curr = is_dot || (x == -1.0);
+
+ vec3 wpos_adj = transform_point(ModelMatrix, (use_curr) ? pos.xyz : pos3.xyz);
+ vec3 wpos1 = transform_point(ModelMatrix, pos1.xyz);
+ vec3 wpos2 = transform_point(ModelMatrix, pos2.xyz);
+
+ vec3 T;
+ if (is_dot) {
+ /* Shade as facing billboards. */
+ T = ViewMatrixInverse[0].xyz;
+ }
+ else if (use_curr && ma.x != -1) {
+ T = wpos1 - wpos_adj;
+ }
+ else {
+ T = wpos2 - wpos1;
+ }
+ T = safe_normalize(T);
+
+ vec3 B = cross(T, ViewMatrixInverse[2].xyz);
+ out_N = normalize(cross(B, T));
+
+ vec4 ndc_adj = point_world_to_ndc(wpos_adj);
+ vec4 ndc1 = point_world_to_ndc(wpos1);
+ vec4 ndc2 = point_world_to_ndc(wpos2);
+
+ out_ndc = (use_curr) ? ndc1 : ndc2;
+ out_P = (use_curr) ? wpos1 : wpos2;
+ out_strength = abs((use_curr) ? strength1 : strength2);
+
+ vec2 ss_adj = gpencil_project_to_screenspace(ndc_adj, viewport_size);
+ vec2 ss1 = gpencil_project_to_screenspace(ndc1, viewport_size);
+ vec2 ss2 = gpencil_project_to_screenspace(ndc2, viewport_size);
+ /* Screenspace Lines tangents. */
+ float line_len;
+ vec2 line = safe_normalize_len(ss2 - ss1, line_len);
+ vec2 line_adj = safe_normalize((use_curr) ? (ss1 - ss_adj) : (ss_adj - ss2));
+
+ float thickness = abs((use_curr) ? thickness1 : thickness2);
+ thickness = gpencil_stroke_thickness_modulate(thickness, out_ndc, viewport_size);
+ float clamped_thickness = gpencil_clamp_small_stroke_thickness(thickness, out_ndc);
+
+ out_uv = vec2(x, y) * 0.5 + 0.5;
+ out_hardness = gpencil_decode_hardness(use_curr ? hardness1 : hardness2);
+
+ if (is_dot) {
+ uint alignement_mode = material_flags & GP_STROKE_ALIGNMENT;
+
+ /* For one point strokes use object alignment. */
+ if (alignement_mode == GP_STROKE_ALIGNMENT_STROKE && ma.x == -1 && ma2.x == -1) {
+ alignement_mode = GP_STROKE_ALIGNMENT_OBJECT;
+ }
+
+ vec2 x_axis;
+ if (alignement_mode == GP_STROKE_ALIGNMENT_STROKE) {
+ x_axis = (ma2.x == -1) ? line_adj : line;
+ }
+ else if (alignement_mode == GP_STROKE_ALIGNMENT_FIXED) {
+ /* Default for no-material drawing. */
+ x_axis = vec2(1.0, 0.0);
+ }
+ else { /* GP_STROKE_ALIGNMENT_OBJECT */
+ vec4 ndc_x = point_world_to_ndc(wpos1 + ModelMatrix[0].xyz);
+ vec2 ss_x = gpencil_project_to_screenspace(ndc_x, viewport_size);
+ x_axis = safe_normalize(ss_x - ss1);
+ }
+
+ /* Rotation: Encoded as Cos + Sin sign. */
+ float uv_rot = gpencil_decode_uvrot(uvrot1);
+ float rot_sin = sqrt(max(0.0, 1.0 - uv_rot * uv_rot)) * sign(uv_rot);
+ float rot_cos = abs(uv_rot);
+ /* TODO(@fclem): Optimize these 2 matrix mul into one by only having one rotation angle and
+ * using a cosine approximation. */
+ x_axis = mat2(rot_cos, -rot_sin, rot_sin, rot_cos) * x_axis;
+ x_axis = mat2(alignment_rot.x, -alignment_rot.y, alignment_rot.y, alignment_rot.x) * x_axis;
+ /* Rotate 90° Counter-Clockwise. */
+ vec2 y_axis = vec2(-x_axis.y, x_axis.x);
+
+ out_aspect = gpencil_decode_aspect(aspect1);
+
+ x *= out_aspect.x;
+ y *= out_aspect.y;
+
+ /* Invert for vertex shader. */
+ out_aspect = 1.0 / out_aspect;
+
+ out_ndc.xy += (x * x_axis + y * y_axis) * viewport_size.zw * clamped_thickness;
+
+ out_sspos.xy = ss1;
+ out_sspos.zw = ss1 + x_axis * 0.5;
+ out_thickness.x = (is_squares) ? 1e18 : (clamped_thickness / out_ndc.w);
+ out_thickness.y = (is_squares) ? 1e18 : (thickness / out_ndc.w);
+ }
+ else {
+ bool is_stroke_start = (ma.x == -1 && x == -1);
+ bool is_stroke_end = (ma3.x == -1 && x == 1);
+
+ /* Mitter tangent vector. */
+ vec2 miter_tan = safe_normalize(line_adj + line);
+ float miter_dot = dot(miter_tan, line_adj);
+ /* Break corners after a certain angle to avoid really thick corners. */
+ const float miter_limit = 0.5; /* cos(60°) */
+ bool miter_break = (miter_dot < miter_limit);
+ miter_tan = (miter_break || is_stroke_start || is_stroke_end) ? line :
+ (miter_tan / miter_dot);
+ /* Rotate 90° Counter-Clockwise. */
+ vec2 miter = vec2(-miter_tan.y, miter_tan.x);
+
+ out_sspos.xy = ss1;
+ out_sspos.zw = ss2;
+ out_thickness.x = clamped_thickness / out_ndc.w;
+ out_thickness.y = thickness / out_ndc.w;
+ out_aspect = vec2(1.0);
+
+ vec2 screen_ofs = miter * y;
+
+ /* Reminder: we packed the cap flag into the sign of strength and thickness sign. */
+ if ((is_stroke_start && strength1 > 0.0) || (is_stroke_end && thickness1 > 0.0) ||
+ (miter_break && !is_stroke_start && !is_stroke_end)) {
+ screen_ofs += line * x;
+ }
+
+ out_ndc.xy += screen_ofs * viewport_size.zw * clamped_thickness;
+
+ out_uv.x = (use_curr) ? uv1.z : uv2.z;
+ }
+
+ out_color = (use_curr) ? col1 : col2;
+ }
+ else {
+ /* Fill vertex. */
+ out_P = transform_point(ModelMatrix, pos1.xyz);
+ out_ndc = point_world_to_ndc(out_P);
+ out_uv = uv1.xy;
+ out_thickness.x = 1e18;
+ out_thickness.y = 1e20;
+ out_hardness = 1.0;
+ out_aspect = vec2(1.0);
+ out_sspos = vec4(0.0);
+
+ /* Flat normal following camera and object bounds. */
+ vec3 V = cameraVec(ModelMatrix[3].xyz);
+ vec3 N = normal_world_to_object(V);
+ N *= OrcoTexCoFactors[1].xyz;
+ N = normal_object_to_world(N);
+ out_N = safe_normalize(N);
+
+ /* Decode fill opacity. */
+ out_color = vec4(fcol1.rgb, floor(fcol1.a / 10.0));
+ out_color.a /= 10000.0;
+
+ /* We still offset the fills a little to avoid overlaps */
+ out_ndc.z += 0.000002;
+ }
+
+# undef thickness1
+# undef thickness2
+# undef strength1
+# undef strength2
+# undef hardness1
+# undef hardness2
+# undef uvrot1
+# undef aspect1
+
+ return out_ndc;
+}
+
+vec4 gpencil_vertex(ivec4 ma,
+ ivec4 ma1,
+ ivec4 ma2,
+ ivec4 ma3,
+ vec4 pos,
+ vec4 pos1,
+ vec4 pos2,
+ vec4 pos3,
+ vec4 uv1,
+ vec4 uv2,
+ vec4 col1,
+ vec4 col2,
+ vec4 fcol1,
+ vec4 viewport_size,
+ out vec3 out_P,
+ out vec3 out_N,
+ out vec4 out_color,
+ out float out_strength,
+ out vec2 out_uv,
+ out vec4 out_sspos,
+ out vec2 out_aspect,
+ out vec2 out_thickness,
+ out float out_hardness)
+{
+ return gpencil_vertex(ma,
+ ma1,
+ ma2,
+ ma3,
+ pos,
+ pos1,
+ pos2,
+ pos3,
+ uv1,
+ uv2,
+ col1,
+ col2,
+ fcol1,
+ viewport_size,
+ GP_STROKE_ALIGNMENT_OBJECT,
+ vec2(1.0, 0.0),
+ out_P,
+ out_N,
+ out_color,
+ out_strength,
+ out_uv,
+ out_sspos,
+ out_aspect,
+ out_thickness,
+ out_hardness);
+}
+
+#endif
diff --git a/source/blender/draw/intern/shaders/common_hair_lib.glsl b/source/blender/draw/intern/shaders/common_hair_lib.glsl
index ed8b8aeb849..7f94b7ea1c1 100644
--- a/source/blender/draw/intern/shaders/common_hair_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_hair_lib.glsl
@@ -158,7 +158,7 @@ float hair_shaperadius(float shape, float root, float tip, float time)
return (radius * (root - tip)) + tip;
}
-# ifdef OS_MAC
+# if defined(OS_MAC) && defined(GPU_OPENGL)
in float dummy;
# endif
@@ -178,7 +178,7 @@ void hair_get_pos_tan_binor_time(bool is_persp,
wpos = data.point_position;
time = data.point_time;
-# ifdef OS_MAC
+# if defined(OS_MAC) && defined(GPU_OPENGL)
/* Generate a dummy read to avoid the driver bug with shaders having no
* vertex reads on macOS (T60171) */
wpos.y += dummy * 0.0;
diff --git a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl
index 7b701d1d81b..6d4452c18c8 100644
--- a/source/blender/draw/intern/shaders/common_math_geom_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_math_geom_lib.glsl
@@ -86,7 +86,7 @@ float line_unit_box_intersect_dist(vec3 lineorigin, vec3 linedirection)
float line_unit_box_intersect_dist_safe(vec3 lineorigin, vec3 linedirection)
{
vec3 safe_linedirection = max(vec3(1e-8), abs(linedirection)) *
- mix(vec3(1.0), -vec3(1.0), lessThan(linedirection, vec3(0.0)));
+ select(vec3(1.0), -vec3(1.0), lessThan(linedirection, vec3(0.0)));
return line_unit_box_intersect_dist(lineorigin, safe_linedirection);
}
diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl
index bc31649fd0f..4d0ffaeb40f 100644
--- a/source/blender/draw/intern/shaders/common_math_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_math_lib.glsl
@@ -68,12 +68,12 @@ mat2 rot2_from_angle(float a)
#define avg9(a, b, c, d, e, f, g, h, i) (a + b + c + d + e + f + g + h + i) * (1.0 / 9.0)
/* clang-format off */
-float min_v2(vec2 v) { return min(v.x, v.y); }
-float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); }
-float min_v4(vec4 v) { return min(min(v.x, v.y), min(v.z, v.w)); }
-float max_v2(vec2 v) { return max(v.x, v.y); }
-float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); }
-float max_v4(vec4 v) { return max(max(v.x, v.y), max(v.z, v.w)); }
+#define min_v2(v) min((v).x, (v).y)
+#define min_v3(v) min((v).x, min((v).y, (v).z))
+#define min_v4(v) min(min((v).x, (v).y), min((v).z, (v).w))
+#define max_v2(v) max((v).x, (v).y)
+#define max_v3(v) max((v).x, max((v).y, (v).z))
+#define max_v4(v) max(max((v).x, (v).y), max((v).z, (v).w))
float sum(vec2 v) { return dot(vec2(1.0), v); }
float sum(vec3 v) { return dot(vec3(1.0), v); }
@@ -84,11 +84,14 @@ float avg(vec3 v) { return dot(vec3(1.0 / 3.0), v); }
float avg(vec4 v) { return dot(vec4(1.0 / 4.0), v); }
float safe_rcp(float a) { return (a != 0.0) ? (1.0 / a) : 0.0; }
-vec2 safe_rcp(vec2 a) { return mix(vec2(0.0), (1.0 / a), notEqual(a, vec2(0.0))); }
-vec4 safe_rcp(vec4 a) { return mix(vec4(0.0), (1.0 / a), notEqual(a, vec4(0.0))); }
+vec2 safe_rcp(vec2 a) { return select(vec2(0.0), (1.0 / a), notEqual(a, vec2(0.0))); }
+vec3 safe_rcp(vec3 a) { return select(vec3(0.0), (1.0 / a), notEqual(a, vec3(0.0))); }
+vec4 safe_rcp(vec4 a) { return select(vec4(0.0), (1.0 / a), notEqual(a, vec4(0.0))); }
float safe_sqrt(float a) { return sqrt(max(a, 0.0)); }
+float safe_acos(float a) { return acos(clamp(a, -1.0, 1.0)); }
+
float sqr(float a) { return a * a; }
vec2 sqr(vec2 a) { return a * a; }
vec3 sqr(vec3 a) { return a * a; }
@@ -102,6 +105,12 @@ float pow8(float x) { return sqr(sqr(sqr(x))); }
float len_squared(vec3 a) { return dot(a, a); }
float len_squared(vec2 a) { return dot(a, a); }
+bool flag_test(uint flag, uint val) { return (flag & val) != 0u; }
+bool flag_test(int flag, int val) { return (flag & val) != 0; }
+
+void set_flag_from_test(inout uint value, bool test, uint flag) { if (test) { value |= flag; } else { value &= ~flag; } }
+void set_flag_from_test(inout int value, bool test, int flag) { if (test) { value |= flag; } else { value &= ~flag; } }
+
#define weighted_sum(val0, val1, val2, val3, weights) ((val0 * weights[0] + val1 * weights[1] + val2 * weights[2] + val3 * weights[3]) * safe_rcp(sum(weights)));
#define weighted_sum_array(val, weights) ((val[0] * weights[0] + val[1] * weights[1] + val[2] * weights[2] + val[3] * weights[3]) * safe_rcp(sum(weights)));
@@ -109,6 +118,52 @@ float len_squared(vec2 a) { return dot(a, a); }
#define saturate(a) clamp(a, 0.0, 1.0)
+#define in_range_inclusive(val, min_v, max_v) \
+ (all(greaterThanEqual(val, min_v)) && all(lessThanEqual(val, max_v)))
+#define in_range_exclusive(val, min_v, max_v) \
+ (all(greaterThan(val, min_v)) && all(lessThan(val, max_v)))
+#define in_texture_range(texel, tex) \
+ (all(greaterThanEqual(texel, ivec2(0))) && all(lessThan(texel, textureSize(tex, 0).xy)))
+
+uint divide_ceil_u(uint visible_count, uint divisor)
+{
+ return (visible_count + (divisor - 1u)) / divisor;
+}
+
+int divide_ceil_i(int visible_count, int divisor)
+{
+ return (visible_count + (divisor - 1)) / divisor;
+}
+
+uint bit_field_mask(uint bit_width, uint bit_min)
+{
+ /* Cannot bit shift more than 31 positions. */
+ uint mask = (bit_width > 31u) ? 0x0u : (0xFFFFFFFFu << bit_width);
+ return ~mask << bit_min;
+}
+
+uvec2 unpackUvec2x16(uint data)
+{
+ return (uvec2(data) >> uvec2(0u, 16u)) & uvec2(0xFFFFu);
+}
+
+uint packUvec2x16(uvec2 data)
+{
+ data = (data & 0xFFFFu) << uvec2(0u, 16u);
+ return data.x | data.y;
+}
+
+uvec4 unpackUvec4x8(uint data)
+{
+ return (uvec4(data) >> uvec4(0u, 8u, 16u, 24u)) & uvec4(0xFFu);
+}
+
+uint packUvec4x8(uvec4 data)
+{
+ data = (data & 0xFFu) << uvec4(0u, 8u, 16u, 24u);
+ return data.x | data.y | data.z | data.w;
+}
+
float distance_squared(vec2 a, vec2 b)
{
a -= b;
@@ -130,6 +185,21 @@ vec3 safe_normalize(vec3 v)
return v / len;
}
+vec2 safe_normalize_len(vec2 v, out float len)
+{
+ len = length(v);
+ if (isnan(len) || len == 0.0) {
+ return vec2(1.0, 0.0);
+ }
+ return v / len;
+}
+
+vec2 safe_normalize(vec2 v)
+{
+ float len;
+ return safe_normalize_len(v, len);
+}
+
vec3 normalize_len(vec3 v, out float len)
{
len = length(v);
@@ -141,6 +211,11 @@ vec4 safe_color(vec4 c)
/* Clamp to avoid black square artifacts if a pixel goes NaN. */
return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */
}
+vec3 safe_color(vec3 c)
+{
+ /* Clamp to avoid black square artifacts if a pixel goes NaN. */
+ return clamp(c, vec3(0.0), vec3(1e20)); /* 1e20 arbitrary. */
+}
/** \} */
@@ -188,3 +263,16 @@ vec3 neon_gradient(float t)
{
return clamp(vec3(t * 1.3 + 0.1, sqr(abs(0.43 - t) * 1.7), (1.0 - t) * 1.7), 0.0, 1.0);
}
+vec3 heatmap_gradient(float t)
+{
+ float a = pow(t, 1.5) * 0.8 + 0.2;
+ float b = smoothstep(0.0, 0.35, t) + t * 0.5;
+ float c = smoothstep(0.5, 1.0, t);
+ float d = max(1.0 - t * 1.7, t * 7.0 - 6.0);
+ return saturate(a * vec3(b, c, d));
+}
+vec3 hue_gradient(float t)
+{
+ vec3 p = abs(fract(t + vec3(1.0, 2.0 / 3.0, 1.0 / 3.0)) * 6.0 - 3.0);
+ return (clamp(p - 1.0, 0.0, 1.0));
+}
diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl
index 2ac157ad208..6c58752c8bb 100644
--- a/source/blender/draw/intern/shaders/common_view_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_view_lib.glsl
@@ -174,7 +174,7 @@ flat in int resourceIDFrag;
/* Breaking this across multiple lines causes issues for some older GLSL compilers. */
/* clang-format off */
-#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && !defined(OS_MAC) && !defined(INSTANCED_ATTR) && !defined(DRW_LEGACY_MODEL_MATRIX)
+#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && (!defined(OS_MAC) || defined(GPU_METAL)) && !defined(INSTANCED_ATTR) && !defined(DRW_LEGACY_MODEL_MATRIX)
/* clang-format on */
/* Temporary until we fully make the switch. */
@@ -251,7 +251,7 @@ uniform mat4 ModelMatrixInverse;
/* Due to some shader compiler bug, we somewhat need to access gl_VertexID
* to make vertex shaders work. even if it's actually dead code. */
-#ifdef GPU_INTEL
+#if defined(GPU_INTEL) && defined(GPU_OPENGL)
# define GPU_INTEL_VERTEX_SHADER_WORKAROUND gl_Position.x = float(gl_VertexID);
#else
# define GPU_INTEL_VERTEX_SHADER_WORKAROUND
diff --git a/source/blender/draw/intern/shaders/draw_object_infos_info.hh b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
index 11b33dec0d4..392b016fc3b 100644
--- a/source/blender/draw/intern/shaders/draw_object_infos_info.hh
+++ b/source/blender/draw/intern/shaders/draw_object_infos_info.hh
@@ -4,4 +4,5 @@
GPU_SHADER_CREATE_INFO(draw_object_infos)
.typedef_source("draw_shader_shared.h")
+ .define("OBINFO_LIB")
.uniform_buf(1, "ObjectInfos", "drw_infos[DRW_RESOURCE_CHUNK_LEN]", Frequency::BATCH);
diff --git a/source/blender/draw/intern/shaders/draw_view_info.hh b/source/blender/draw/intern/shaders/draw_view_info.hh
index 4a148901d66..a699b9013ef 100644
--- a/source/blender/draw/intern/shaders/draw_view_info.hh
+++ b/source/blender/draw/intern/shaders/draw_view_info.hh
@@ -103,4 +103,28 @@ GPU_SHADER_CREATE_INFO(draw_pointcloud)
GPU_SHADER_CREATE_INFO(draw_volume).additional_info("draw_modelmat", "draw_resource_id_uniform");
+GPU_SHADER_CREATE_INFO(draw_gpencil)
+ .typedef_source("gpencil_shader_shared.h")
+ .define("DRW_GPENCIL_INFO")
+ .vertex_in(0, Type::IVEC4, "ma")
+ .vertex_in(1, Type::IVEC4, "ma1")
+ .vertex_in(2, Type::IVEC4, "ma2")
+ .vertex_in(3, Type::IVEC4, "ma3")
+ .vertex_in(4, Type::VEC4, "pos")
+ .vertex_in(5, Type::VEC4, "pos1")
+ .vertex_in(6, Type::VEC4, "pos2")
+ .vertex_in(7, Type::VEC4, "pos3")
+ .vertex_in(8, Type::VEC4, "uv1")
+ .vertex_in(9, Type::VEC4, "uv2")
+ .vertex_in(10, Type::VEC4, "col1")
+ .vertex_in(11, Type::VEC4, "col2")
+ .vertex_in(12, Type::VEC4, "fcol1")
+ /* Per Object */
+ .push_constant(Type::FLOAT, "gpThicknessScale") /* TODO(fclem): Replace with object info. */
+ .push_constant(Type::FLOAT, "gpThicknessWorldScale") /* TODO(fclem): Same as above. */
+ .define("gpThicknessIsScreenSpace", "(gpThicknessWorldScale < 0.0)")
+ /* Per Layer */
+ .push_constant(Type::FLOAT, "gpThicknessOffset")
+ .additional_info("draw_modelmat", "draw_resource_id_uniform", "draw_object_infos");
+
/** \} */
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index df418b204f9..08379be36fa 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -1131,7 +1131,7 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn
{
AnimChanRearrangeFp rearrange_func;
ListBase anim_data_visible = {NULL, NULL};
- const bool is_liboverride = ID_IS_OVERRIDE_LIBRARY(ac->obact);
+ const bool is_liboverride = (ac->obact != NULL) ? ID_IS_OVERRIDE_LIBRARY(ac->obact) : false;
/* hack: invert mode so that functions will work in right order */
mode *= -1;
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index f18873cc22b..ed40845a47c 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -1292,8 +1292,8 @@ void ANIM_fcurve_equalize_keyframes_loop(FCurve *fcu,
{
uint i;
BezTriple *bezt;
- const float flat_direction_left[2] = {-handle_length, 0.f};
- const float flat_direction_right[2] = {handle_length, 0.f};
+ const float flat_direction_left[2] = {-handle_length, 0.0f};
+ const float flat_direction_right[2] = {handle_length, 0.0f};
/* Loop through an F-Curves keyframes. */
for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) {
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 24ba62fc0f7..aec2b0f769a 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -382,6 +382,68 @@ void blend_to_neighbor_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const
/* ---------------- */
+float get_default_rna_value(FCurve *fcu, PropertyRNA *prop, PointerRNA *ptr)
+{
+ const int len = RNA_property_array_length(ptr, prop);
+
+ float default_value = 0;
+ /* Find the default value of that property. */
+ switch (RNA_property_type(prop)) {
+ case PROP_BOOLEAN:
+ if (len) {
+ default_value = RNA_property_boolean_get_default_index(ptr, prop, fcu->array_index);
+ }
+ else {
+ default_value = RNA_property_boolean_get_default(ptr, prop);
+ }
+ break;
+ case PROP_INT:
+ if (len) {
+ default_value = RNA_property_int_get_default_index(ptr, prop, fcu->array_index);
+ }
+ else {
+ default_value = RNA_property_int_get_default(ptr, prop);
+ }
+ break;
+ case PROP_FLOAT:
+ if (len) {
+ default_value = RNA_property_float_get_default_index(ptr, prop, fcu->array_index);
+ }
+ else {
+ default_value = RNA_property_float_get_default(ptr, prop);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return default_value;
+}
+
+/* This function blends the selected keyframes to the default value of the property the fcurve
+ * drives. */
+void blend_to_default_fcurve(PointerRNA *id_ptr, FCurve *fcu, const float factor)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ /* Check if path is valid. */
+ if (!RNA_path_resolve_property(id_ptr, fcu->rna_path, &ptr, &prop)) {
+ return;
+ }
+
+ const float default_value = get_default_rna_value(fcu, prop, &ptr);
+
+ /* Blend selected keys to default */
+ for (int i = 0; i < fcu->totvert; i++) {
+ if (fcu->bezt[i].f2 & SELECT) {
+ fcu->bezt[i].vec[1][1] = interpf(default_value, fcu->bezt[i].vec[1][1], factor);
+ }
+ }
+}
+
+/* ---------------- */
+
void breakdown_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
{
BezTriple left_bezt = fcurve_segment_start_get(fcu, segment->start_index);
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index dcf8835c911..6fcdd21bad8 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -715,54 +715,55 @@ const EnumPropertyItem *ANIM_keying_sets_enum_itemf(bContext *C,
PropertyRNA *UNUSED(prop),
bool *r_free)
{
+ Scene *scene = CTX_data_scene(C);
KeyingSet *ks;
EnumPropertyItem *item = NULL, item_tmp = {0};
int totitem = 0;
int i = 0;
- if (C != NULL) {
- Scene *scene = CTX_data_scene(C);
- /* active Keying Set
- * - only include entry if it exists
- */
- if (scene->active_keyingset) {
- /* active Keying Set */
- item_tmp.identifier = "__ACTIVE__";
- item_tmp.name = "Active Keying Set";
- item_tmp.value = i;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
+ if (C == NULL) {
+ return DummyRNA_DEFAULT_items;
+ }
- /* separator */
- RNA_enum_item_add_separator(&item, &totitem);
- }
+ /* active Keying Set
+ * - only include entry if it exists
+ */
+ if (scene->active_keyingset) {
+ /* active Keying Set */
+ item_tmp.identifier = "__ACTIVE__";
+ item_tmp.name = "Active Keying Set";
+ item_tmp.value = i;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+
+ /* separator */
+ RNA_enum_item_add_separator(&item, &totitem);
+ }
- i++;
+ i++;
- /* user-defined Keying Sets
- * - these are listed in the order in which they were defined for the active scene
- */
- if (scene->keyingsets.first) {
- for (ks = scene->keyingsets.first; ks; ks = ks->next, i++) {
- if (ANIM_keyingset_context_ok_poll(C, ks)) {
- item_tmp.identifier = ks->idname;
- item_tmp.name = ks->name;
- item_tmp.description = ks->description;
- item_tmp.value = i;
- RNA_enum_item_add(&item, &totitem, &item_tmp);
- }
+ /* user-defined Keying Sets
+ * - these are listed in the order in which they were defined for the active scene
+ */
+ if (scene->keyingsets.first) {
+ for (ks = scene->keyingsets.first; ks; ks = ks->next, i++) {
+ if (ANIM_keyingset_context_ok_poll(C, ks)) {
+ item_tmp.identifier = ks->idname;
+ item_tmp.name = ks->name;
+ item_tmp.description = ks->description;
+ item_tmp.value = i;
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
}
-
- /* separator */
- RNA_enum_item_add_separator(&item, &totitem);
}
+
+ /* separator */
+ RNA_enum_item_add_separator(&item, &totitem);
}
/* builtin Keying Sets */
i = -1;
for (ks = builtin_keyingsets.first; ks; ks = ks->next, i--) {
- /* Only show #KeyingSet if context is suitable or if there is no context which is needed
- * to support key-bindings to be assigned since key bindings are not context aware. */
- if ((C == NULL) || ANIM_keyingset_context_ok_poll(C, ks)) {
+ /* only show KeyingSet if context is suitable */
+ if (ANIM_keyingset_context_ok_poll(C, ks)) {
item_tmp.identifier = ks->idname;
item_tmp.name = ks->name;
item_tmp.description = ks->description;
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 45d64807e65..be4829c02be 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -377,6 +377,15 @@ int ED_armature_join_objects_exec(bContext *C, wmOperator *op)
BKE_pose_channels_hash_free(pose);
}
+ /* Armature ID itself is not freed below, however it has been modified (and is now completely
+ * empty). This needs to be told to the depsgraph, it will also ensure that the global
+ * memfile undo system properly detects the change.
+ *
+ * FIXME: Modifying an existing obdata because we are joining an object using it into another
+ * object is a very questionable behavior, which also does not match with other object types
+ * joining. */
+ DEG_id_tag_update_ex(bmain, &curarm->id, ID_RECALC_GEOMETRY);
+
/* Fix all the drivers (and animation data) */
BKE_fcurves_main_cb(bmain, joined_armature_fix_animdata_cb, &afd);
BLI_ghash_free(afd.names_map, MEM_freeN, NULL);
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index d7240782840..08d5d6558e0 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -951,127 +951,180 @@ bool ED_armature_edit_select_pick_bone(bContext *C,
Base *basact,
EditBone *ebone,
const int selmask,
- const bool extend,
- const bool deselect,
- const bool toggle)
+ const struct SelectPick_Params *params)
{
- if (!ebone) {
- return false;
- }
-
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
+ bool changed = false;
+ bool found = false;
- BLI_assert(BKE_object_is_in_editmode(basact->object));
- bArmature *arm = basact->object->data;
-
- if (!EBONE_SELECTABLE(arm, ebone)) {
- return false;
+ if (ebone) {
+ bArmature *arm = basact->object->data;
+ if (EBONE_SELECTABLE(arm, ebone)) {
+ found = true;
+ }
}
- if (!extend && !deselect && !toggle) {
- uint bases_len = 0;
- Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
- view_layer, v3d, &bases_len);
- ED_armature_edit_deselect_all_multi_ex(bases, bases_len);
- MEM_freeN(bases);
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) &&
+ (ED_armature_ebone_selectflag_get(ebone) & selmask)) {
+ found = false;
+ }
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
+ view_layer, v3d, &bases_len);
+ ED_armature_edit_deselect_all_multi_ex(bases, bases_len);
+ MEM_freeN(bases);
+ changed = true;
+ }
}
- /* By definition the non-root connected bones have no root point drawn,
- * so a root selection needs to be delivered to the parent tip. */
+ if (found) {
+ BLI_assert(BKE_object_is_in_editmode(basact->object));
+ bArmature *arm = basact->object->data;
- if (selmask & BONE_SELECTED) {
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- /* Bone is in a chain. */
- if (extend) {
- /* Select this bone. */
- ebone->flag |= BONE_TIPSEL;
- ebone->parent->flag |= BONE_TIPSEL;
- }
- else if (deselect) {
- /* Deselect this bone. */
- ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
- /* Only deselect parent tip if it is not selected. */
- if (!(ebone->parent->flag & BONE_SELECTED)) {
- ebone->parent->flag &= ~BONE_TIPSEL;
- }
- }
- else if (toggle) {
- /* Toggle inverts this bone's selection. */
- if (ebone->flag & BONE_SELECTED) {
- /* Deselect this bone. */
- ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
- /* Only deselect parent tip if it is not selected. */
- if (!(ebone->parent->flag & BONE_SELECTED)) {
- ebone->parent->flag &= ~BONE_TIPSEL;
+ /* By definition the non-root connected bones have no root point drawn,
+ * so a root selection needs to be delivered to the parent tip. */
+
+ if (selmask & BONE_SELECTED) {
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+
+ /* Bone is in a chain. */
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ /* Select this bone. */
+ ebone->flag |= BONE_TIPSEL;
+ ebone->parent->flag |= BONE_TIPSEL;
+ break;
+ }
+ case SEL_OP_SUB: {
+ /* Deselect this bone. */
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
+ /* Only deselect parent tip if it is not selected. */
+ if (!(ebone->parent->flag & BONE_SELECTED)) {
+ ebone->parent->flag &= ~BONE_TIPSEL;
+ }
+ break;
+ }
+ case SEL_OP_XOR: {
+ /* Toggle inverts this bone's selection. */
+ if (ebone->flag & BONE_SELECTED) {
+ /* Deselect this bone. */
+ ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
+ /* Only deselect parent tip if it is not selected. */
+ if (!(ebone->parent->flag & BONE_SELECTED)) {
+ ebone->parent->flag &= ~BONE_TIPSEL;
+ }
+ }
+ else {
+ /* Select this bone. */
+ ebone->flag |= BONE_TIPSEL;
+ ebone->parent->flag |= BONE_TIPSEL;
+ }
+ break;
+ }
+ case SEL_OP_SET: {
+ /* Select this bone. */
+ ebone->flag |= BONE_TIPSEL;
+ ebone->parent->flag |= BONE_TIPSEL;
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
}
- }
- else {
- /* Select this bone. */
- ebone->flag |= BONE_TIPSEL;
- ebone->parent->flag |= BONE_TIPSEL;
}
}
else {
- /* Select this bone. */
- ebone->flag |= BONE_TIPSEL;
- ebone->parent->flag |= BONE_TIPSEL;
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
+ break;
+ }
+ case SEL_OP_SUB: {
+ ebone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
+ break;
+ }
+ case SEL_OP_XOR: {
+ /* Toggle inverts this bone's selection. */
+ if (ebone->flag & BONE_SELECTED) {
+ ebone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else {
+ ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ break;
+ }
+ case SEL_OP_SET: {
+ ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
+ }
+ }
}
}
else {
- if (extend) {
- ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (deselect) {
- ebone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if (toggle) {
- /* Toggle inverts this bone's selection. */
- if (ebone->flag & BONE_SELECTED) {
- ebone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ ebone->flag |= selmask;
+ break;
}
- else {
- ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
+ case SEL_OP_SUB: {
+ ebone->flag &= ~selmask;
+ break;
+ }
+ case SEL_OP_XOR: {
+ if (ebone->flag & selmask) {
+ ebone->flag &= ~selmask;
+ }
+ else {
+ ebone->flag |= selmask;
+ }
+ break;
+ }
+ case SEL_OP_SET: {
+ ebone->flag |= selmask;
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
}
- }
- else {
- ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
}
}
- }
- else {
- if (extend) {
- ebone->flag |= selmask;
- }
- else if (deselect) {
- ebone->flag &= ~selmask;
- }
- else if (toggle && (ebone->flag & selmask)) {
- ebone->flag &= ~selmask;
- }
- else {
- ebone->flag |= selmask;
+
+ ED_armature_edit_sync_selection(arm->edbo);
+
+ /* Then now check for active status. */
+ if (ED_armature_ebone_selectflag_get(ebone)) {
+ arm->act_edbone = ebone;
}
- }
- ED_armature_edit_sync_selection(arm->edbo);
+ if (view_layer->basact != basact) {
+ ED_object_base_activate(C, basact);
+ }
- /* Then now check for active status. */
- if (ED_armature_ebone_selectflag_get(ebone)) {
- arm->act_edbone = ebone;
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ changed = true;
}
- if (view_layer->basact != basact) {
- ED_object_base_activate(C, basact);
+ if (changed) {
+ ED_outliner_select_sync_from_edit_bone_tag(C);
}
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
- return true;
+ return changed || found;
}
-bool ED_armature_edit_select_pick(
- bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+bool ED_armature_edit_select_pick(bContext *C,
+ const int mval[2],
+ const struct SelectPick_Params *params)
+
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
@@ -1084,7 +1137,7 @@ bool ED_armature_edit_select_pick(
vc.mval[1] = mval[1];
nearBone = get_nearest_editbonepoint(&vc, true, true, &basact, &selmask);
- return ED_armature_edit_select_pick_bone(C, basact, nearBone, selmask, extend, deselect, toggle);
+ return ED_armature_edit_select_pick_bone(C, basact, nearBone, selmask, params);
}
/** \} */
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 12238280b06..8790a10f3e5 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -121,43 +121,27 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
}
}
-void ED_armature_pose_select_pick_bone(ViewLayer *view_layer,
+bool ED_armature_pose_select_pick_bone(ViewLayer *view_layer,
View3D *v3d,
Object *ob,
Bone *bone,
- const bool extend,
- const bool deselect,
- const bool toggle)
+ const struct SelectPick_Params *params)
{
- if (!ob || !ob->pose) {
- return;
- }
-
- Object *ob_act = OBACT(view_layer);
- BLI_assert(OBEDIT_FROM_VIEW_LAYER(view_layer) == NULL);
-
- /* If the bone cannot be affected, don't do anything. */
- if (bone == NULL || (bone->flag & BONE_UNSELECTABLE)) {
- return;
- }
- bArmature *arm = ob->data;
+ bool found = false;
+ bool changed = false;
- /* Since we do unified select, we don't shift+select a bone if the
- * armature object was not active yet.
- * NOTE(campbell): special exception for armature mode so we can do multi-select
- * we could check for multi-select explicitly but think its fine to
- * always give predictable behavior in weight paint mode. */
- if ((ob_act == NULL) || ((ob_act != ob) && (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) == 0)) {
- /* When we are entering into posemode via toggle-select,
- * from another active object - always select the bone. */
- if (!extend && !deselect && toggle) {
- /* Re-select the bone again later in this function. */
- bone->flag &= ~BONE_SELECTED;
+ if (ob || ob->pose) {
+ if (bone && ((bone->flag & BONE_UNSELECTABLE) == 0)) {
+ found = true;
}
}
- if (!extend && !deselect && !toggle) {
- {
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) && (bone->flag & BONE_SELECTED)) {
+ found = false;
+ }
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
/* Don't use 'BKE_object_pose_base_array_get_unique'
* because we may be selecting from object mode. */
FOREACH_VISIBLE_BASE_BEGIN (view_layer, v3d, base_iter) {
@@ -169,56 +153,94 @@ void ED_armature_pose_select_pick_bone(ViewLayer *view_layer,
}
}
FOREACH_VISIBLE_BASE_END;
+ changed = true;
}
- bone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_bone = bone;
}
- else {
- if (extend) {
- bone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- arm->act_bone = bone;
- }
- else if (deselect) {
- bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+
+ if (found) {
+ Object *ob_act = OBACT(view_layer);
+ BLI_assert(OBEDIT_FROM_VIEW_LAYER(view_layer) == NULL);
+
+ /* If the bone cannot be affected, don't do anything. */
+ bArmature *arm = ob->data;
+
+ /* Since we do unified select, we don't shift+select a bone if the
+ * armature object was not active yet.
+ * NOTE(campbell): special exception for armature mode so we can do multi-select
+ * we could check for multi-select explicitly but think its fine to
+ * always give predictable behavior in weight paint mode. */
+ if ((ob_act == NULL) || ((ob_act != ob) && (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) == 0)) {
+ /* When we are entering into posemode via toggle-select,
+ * from another active object - always select the bone. */
+ if (params->sel_op == SEL_OP_SET) {
+ /* Re-select the bone again later in this function. */
+ bone->flag &= ~BONE_SELECTED;
+ }
}
- else if (toggle) {
- if (bone->flag & BONE_SELECTED) {
- /* If not active, we make it active. */
- if (bone != arm->act_bone) {
- arm->act_bone = bone;
+
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ bone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_bone = bone;
+ break;
+ }
+ case SEL_OP_SUB: {
+ bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ break;
+ }
+ case SEL_OP_XOR: {
+ if (bone->flag & BONE_SELECTED) {
+ /* If not active, we make it active. */
+ if (bone != arm->act_bone) {
+ arm->act_bone = bone;
+ }
+ else {
+ bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
}
else {
- bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ bone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ arm->act_bone = bone;
}
+ break;
}
- else {
+ case SEL_OP_SET: {
bone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
arm->act_bone = bone;
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
}
}
- }
- if (ob_act) {
- /* In weightpaint we select the associated vertex group too. */
- if (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) {
- if (bone == arm->act_bone) {
- ED_vgroup_select_by_name(ob_act, bone->name);
- DEG_id_tag_update(&ob_act->id, ID_RECALC_GEOMETRY);
+ if (ob_act) {
+ /* In weightpaint we select the associated vertex group too. */
+ if (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) {
+ if (bone == arm->act_bone) {
+ ED_vgroup_select_by_name(ob_act, bone->name);
+ DEG_id_tag_update(&ob_act->id, ID_RECALC_GEOMETRY);
+ }
}
- }
- /* If there are some dependencies for visualizing armature state
- * (e.g. Mask Modifier in 'Armature' mode), force update.
- */
- else if (arm->flag & ARM_HAS_VIZ_DEPS) {
- /* NOTE: ob not ob_act here is intentional - it's the source of the
- * bones being selected [T37247]
+ /* If there are some dependencies for visualizing armature state
+ * (e.g. Mask Modifier in 'Armature' mode), force update.
*/
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ else if (arm->flag & ARM_HAS_VIZ_DEPS) {
+ /* NOTE: ob not ob_act here is intentional - it's the source of the
+ * bones being selected [T37247]
+ */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+
+ /* Tag armature for copy-on-write update (since act_bone is in armature not object). */
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
}
- /* Tag armature for copy-on-write update (since act_bone is in armature not object). */
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ changed = true;
}
+
+ return changed || found;
}
bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
@@ -226,9 +248,7 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
Base *base,
const struct GPUSelectResult *buffer,
const short hits,
- bool extend,
- bool deselect,
- bool toggle,
+ const struct SelectPick_Params *params,
bool do_nearest)
{
Object *ob = base->object;
@@ -243,9 +263,7 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
nearBone = ED_armature_pick_bone_from_selectbuffer(
&base, 1, buffer, hits, 1, do_nearest, &base_dummy);
- ED_armature_pose_select_pick_bone(view_layer, v3d, ob, nearBone, extend, deselect, toggle);
-
- return nearBone != NULL;
+ return ED_armature_pose_select_pick_bone(view_layer, v3d, ob, nearBone, params);
}
void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_select)
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index fb349b78d71..cf04cdba859 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -896,7 +896,7 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
strcpy(mode_str, TIP_("Breakdown"));
break;
case POSESLIDE_BLEND:
- strcpy(mode_str, TIP_("Blend To Neighbor"));
+ strcpy(mode_str, TIP_("Blend to Neighbor"));
break;
default:
@@ -1722,7 +1722,7 @@ static int pose_slide_blend_to_neighbors_exec(bContext *C, wmOperator *op)
void POSE_OT_blend_to_neighbors(wmOperatorType *ot)
{
/* Identifiers. */
- ot->name = "Blend To Neighbor";
+ ot->name = "Blend to Neighbor";
ot->idname = "POSE_OT_blend_to_neighbor";
ot->description = "Blend from current position to previous or next keyframe";
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 90d4ef60598..f0b0218d7e0 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -1100,7 +1100,7 @@ static void pchan_clear_rot(bPoseChannel *pchan)
copy_v3_v3(pchan->eul, eul);
}
}
- } /* Duplicated in source/blender/editors/object/object_transform.c */
+ } /* Duplicated in source/blender/editors/object/object_transform.cc */
else {
if (pchan->rotmode == ROT_MODE_QUAT) {
unit_qt(pchan->quat);
diff --git a/source/blender/editors/asset/intern/asset_indexer.cc b/source/blender/editors/asset/intern/asset_indexer.cc
index 49c4002eee8..3cc3638c299 100644
--- a/source/blender/editors/asset/intern/asset_indexer.cc
+++ b/source/blender/editors/asset/intern/asset_indexer.cc
@@ -39,7 +39,6 @@ using namespace blender::bke;
using namespace blender::bke::idprop;
/**
- * \file asset_indexer.cc
* \brief Indexer for asset libraries.
*
* Indexes are stored per input file. Each index can contain zero to multiple asset entries.
@@ -494,15 +493,15 @@ struct AssetLibraryIndex {
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++) {
+ const int dir_entries_num = BLI_filelist_dir_contents(index_path, &dir_entries);
+ for (int i = 0; i < dir_entries_num; 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);
+ BLI_filelist_free(dir_entries, dir_entries_num);
}
void mark_as_used(const std::string &filename)
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index c3ea36fcda5..8bfabe23ea1 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -181,6 +181,7 @@ void SURFACE_OT_primitive_nurbs_surface_sphere_add(struct wmOperatorType *ot);
void SURFACE_OT_primitive_nurbs_surface_torus_add(struct wmOperatorType *ot);
/* editcurve_query.c */
+
bool ED_curve_pick_vert(struct ViewContext *vc,
short sel,
struct Nurb **r_nurb,
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 2dcddd01670..5ff63e767f6 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -44,6 +44,7 @@
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
#include "ED_types.h"
@@ -4722,8 +4723,9 @@ void CURVE_OT_make_segment(wmOperatorType *ot)
/** \name Pick Select from 3D View
* \{ */
-bool ED_curve_editnurb_select_pick(
- bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+bool ED_curve_editnurb_select_pick(bContext *C,
+ const int mval[2],
+ const struct SelectPick_Params *params)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
@@ -4732,18 +4734,21 @@ bool ED_curve_editnurb_select_pick(
BPoint *bp = NULL;
Base *basact = NULL;
short hand;
+ bool changed = false;
view3d_operator_needs_opengl(C);
ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, mval);
- if (ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, &hand, &basact)) {
- Object *obedit = basact->object;
- Curve *cu = obedit->data;
- ListBase *editnurb = object_editcurve_get(obedit);
- const void *vert = BKE_curve_vert_active_get(cu);
+ bool found = ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, &hand, &basact);
- if (!extend && !deselect && !toggle) {
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) &&
+ (((bezt ? (&bezt->f1)[hand] : bp->f1) & SELECT) != 0)) {
+ found = false;
+ }
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &objects_len);
@@ -4756,105 +4761,123 @@ bool ED_curve_editnurb_select_pick(
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
}
MEM_freeN(objects);
+ changed = true;
}
+ }
- if (extend) {
- if (bezt) {
- if (hand == 1) {
- select_beztriple(bezt, SELECT, SELECT, HIDDEN);
- }
- else {
- if (hand == 0) {
- bezt->f1 |= SELECT;
+ if (found) {
+ Object *obedit = basact->object;
+ Curve *cu = obedit->data;
+ ListBase *editnurb = object_editcurve_get(obedit);
+ const void *vert = BKE_curve_vert_active_get(cu);
+
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ if (bezt) {
+ if (hand == 1) {
+ select_beztriple(bezt, SELECT, SELECT, HIDDEN);
}
else {
- bezt->f3 |= SELECT;
- }
- }
- BKE_curve_nurb_vert_active_set(cu, nu, bezt);
- }
- else {
- select_bpoint(bp, SELECT, SELECT, HIDDEN);
- BKE_curve_nurb_vert_active_set(cu, nu, bp);
- }
- }
- else if (deselect) {
- if (bezt) {
- if (hand == 1) {
- select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
- if (bezt == vert) {
- cu->actvert = CU_ACT_NONE;
+ if (hand == 0) {
+ bezt->f1 |= SELECT;
+ }
+ else {
+ bezt->f3 |= SELECT;
+ }
}
- }
- else if (hand == 0) {
- bezt->f1 &= ~SELECT;
+ BKE_curve_nurb_vert_active_set(cu, nu, bezt);
}
else {
- bezt->f3 &= ~SELECT;
- }
- }
- else {
- select_bpoint(bp, DESELECT, SELECT, HIDDEN);
- if (bp == vert) {
- cu->actvert = CU_ACT_NONE;
+ select_bpoint(bp, SELECT, SELECT, HIDDEN);
+ BKE_curve_nurb_vert_active_set(cu, nu, bp);
}
+ break;
}
- }
- else if (toggle) {
- if (bezt) {
- if (hand == 1) {
- if (bezt->f2 & SELECT) {
+ case SEL_OP_SUB: {
+ if (bezt) {
+ if (hand == 1) {
select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
if (bezt == vert) {
cu->actvert = CU_ACT_NONE;
}
}
+ else if (hand == 0) {
+ bezt->f1 &= ~SELECT;
+ }
else {
- select_beztriple(bezt, SELECT, SELECT, HIDDEN);
- BKE_curve_nurb_vert_active_set(cu, nu, bezt);
+ bezt->f3 &= ~SELECT;
}
}
- else if (hand == 0) {
- bezt->f1 ^= SELECT;
- }
else {
- bezt->f3 ^= SELECT;
- }
- }
- else {
- if (bp->f1 & SELECT) {
select_bpoint(bp, DESELECT, SELECT, HIDDEN);
if (bp == vert) {
cu->actvert = CU_ACT_NONE;
}
}
+ break;
+ }
+ case SEL_OP_XOR: {
+ if (bezt) {
+ if (hand == 1) {
+ if (bezt->f2 & SELECT) {
+ select_beztriple(bezt, DESELECT, SELECT, HIDDEN);
+ if (bezt == vert) {
+ cu->actvert = CU_ACT_NONE;
+ }
+ }
+ else {
+ select_beztriple(bezt, SELECT, SELECT, HIDDEN);
+ BKE_curve_nurb_vert_active_set(cu, nu, bezt);
+ }
+ }
+ else if (hand == 0) {
+ bezt->f1 ^= SELECT;
+ }
+ else {
+ bezt->f3 ^= SELECT;
+ }
+ }
else {
- select_bpoint(bp, SELECT, SELECT, HIDDEN);
- BKE_curve_nurb_vert_active_set(cu, nu, bp);
+ if (bp->f1 & SELECT) {
+ select_bpoint(bp, DESELECT, SELECT, HIDDEN);
+ if (bp == vert) {
+ cu->actvert = CU_ACT_NONE;
+ }
+ }
+ else {
+ select_bpoint(bp, SELECT, SELECT, HIDDEN);
+ BKE_curve_nurb_vert_active_set(cu, nu, bp);
+ }
}
+ break;
}
- }
- else {
- BKE_nurbList_flag_set(editnurb, SELECT, false);
+ case SEL_OP_SET: {
+ BKE_nurbList_flag_set(editnurb, SELECT, false);
- if (bezt) {
+ if (bezt) {
- if (hand == 1) {
- select_beztriple(bezt, SELECT, SELECT, HIDDEN);
- }
- else {
- if (hand == 0) {
- bezt->f1 |= SELECT;
+ if (hand == 1) {
+ select_beztriple(bezt, SELECT, SELECT, HIDDEN);
}
else {
- bezt->f3 |= SELECT;
+ if (hand == 0) {
+ bezt->f1 |= SELECT;
+ }
+ else {
+ bezt->f3 |= SELECT;
+ }
}
+ BKE_curve_nurb_vert_active_set(cu, nu, bezt);
+ }
+ else {
+ select_bpoint(bp, SELECT, SELECT, HIDDEN);
+ BKE_curve_nurb_vert_active_set(cu, nu, bp);
}
- BKE_curve_nurb_vert_active_set(cu, nu, bezt);
+ break;
}
- else {
- select_bpoint(bp, SELECT, SELECT, HIDDEN);
- BKE_curve_nurb_vert_active_set(cu, nu, bp);
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
}
}
@@ -4876,10 +4899,10 @@ bool ED_curve_editnurb_select_pick(
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT | ID_RECALC_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- return true;
+ changed = true;
}
- return false;
+ return changed || found;
}
/** \} */
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 02c7f3856e8..611dbb2e80c 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -526,16 +526,16 @@ static bool font_paste_utf8(bContext *C, const char *str, const size_t str_len)
/** \name Paste From File Operator
* \{ */
-static int paste_from_file(bContext *C, ReportList *reports, const char *filename)
+static int paste_from_file(bContext *C, ReportList *reports, const char *filepath)
{
Object *obedit = CTX_data_edit_object(C);
char *strp;
size_t filelen;
int retval;
- strp = BLI_file_read_text_as_mem(filename, 1, &filelen);
+ strp = BLI_file_read_text_as_mem(filepath, 1, &filelen);
if (strp == NULL) {
- BKE_reportf(reports, RPT_ERROR, "Failed to open file '%s'", filename);
+ BKE_reportf(reports, RPT_ERROR, "Failed to open file '%s'", filepath);
return OPERATOR_CANCELLED;
}
strp[filelen] = 0;
@@ -545,7 +545,7 @@ static int paste_from_file(bContext *C, ReportList *reports, const char *filenam
retval = OPERATOR_FINISHED;
}
else {
- BKE_reportf(reports, RPT_ERROR, "File too long %s", filename);
+ BKE_reportf(reports, RPT_ERROR, "File too long %s", filepath);
retval = OPERATOR_CANCELLED;
}
@@ -556,12 +556,12 @@ static int paste_from_file(bContext *C, ReportList *reports, const char *filenam
static int paste_from_file_exec(bContext *C, wmOperator *op)
{
- char *path;
+ char *filepath;
int retval;
- path = RNA_string_get_alloc(op->ptr, "filepath", NULL, 0, NULL);
- retval = paste_from_file(C, op->reports, path);
- MEM_freeN(path);
+ filepath = RNA_string_get_alloc(op->ptr, "filepath", NULL, 0, NULL);
+ retval = paste_from_file(C, op->reports, filepath);
+ MEM_freeN(filepath);
return retval;
}
@@ -2091,7 +2091,7 @@ static int font_open_exec(bContext *C, wmOperator *op)
static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
VFont *vfont = NULL;
- const char *path;
+ const char *filepath;
PointerRNA idptr;
PropertyPointerRNA *pprop;
@@ -2106,13 +2106,13 @@ static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
vfont = (VFont *)idptr.owner_id;
}
- path = (vfont && !BKE_vfont_is_builtin(vfont)) ? vfont->filepath : U.fontdir;
+ filepath = (vfont && !BKE_vfont_is_builtin(vfont)) ? vfont->filepath : U.fontdir;
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
return font_open_exec(C, op);
}
- RNA_string_set(op->ptr, "filepath", path);
+ RNA_string_set(op->ptr, "filepath", filepath);
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -2184,7 +2184,10 @@ void FONT_OT_unlink(wmOperatorType *ot)
}
bool ED_curve_editfont_select_pick(
- bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+ bContext *C,
+ const int mval[2],
+ /* NOTE: `params->deselect_all` is ignored as only one text-box is active at once. */
+ const struct SelectPick_Params *params)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obedit = CTX_data_edit_object(C);
@@ -2203,9 +2206,7 @@ bool ED_curve_editfont_select_pick(
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
/* currently only select active */
- (void)extend;
- (void)deselect;
- (void)toggle;
+ (void)params;
for (i_iter = 0; i_iter < cu->totbox; i_iter++) {
int i = (i_iter + i_actbox) % cu->totbox;
@@ -2257,6 +2258,8 @@ bool ED_curve_editfont_select_pick(
if (cu->actbox != actbox_select) {
cu->actbox = actbox_select;
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ /* TODO: support #ID_RECALC_SELECT. */
+ DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE);
}
return true;
}
diff --git a/source/blender/editors/curves/intern/curves_add.cc b/source/blender/editors/curves/intern/curves_add.cc
index 9cde23451dc..17108619a4d 100644
--- a/source/blender/editors/curves/intern/curves_add.cc
+++ b/source/blender/editors/curves/intern/curves_add.cc
@@ -21,7 +21,7 @@ bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int poi
float *radius_data = (float *)CustomData_add_layer_named(
&curves.point_data, CD_PROP_FLOAT, CD_DEFAULT, nullptr, curves.point_size, "radius");
- MutableSpan<float> radii{radius_data, curves.points_size()};
+ MutableSpan<float> radii{radius_data, curves.points_num()};
for (const int i : offsets.index_range()) {
offsets[i] = points_per_curve * i;
@@ -30,7 +30,7 @@ bke::CurvesGeometry primitive_random_sphere(const int curves_size, const int poi
RandomNumberGenerator rng;
for (const int i : curves.curves_range()) {
- const IndexRange curve_range = curves.range_for_curve(i);
+ const IndexRange curve_range = curves.points_for_curve(i);
MutableSpan<float3> curve_positions = positions.slice(curve_range);
MutableSpan<float> curve_radii = radii.slice(curve_range);
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index edbdc1ee96f..d58bbec01cd 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -595,9 +595,9 @@ set(ICON_NAMES
axis_top
layer_used
layer_active
- outliner_ob_hair
- outliner_data_hair
- hair_data
+ outliner_ob_curves
+ outliner_data_curves
+ curves_data
outliner_ob_pointcloud
outliner_data_pointcloud
pointcloud_data
@@ -652,7 +652,7 @@ set(ICON_NAMES
matsphere
matcube
monkey
- hair
+ curves
aliased
antialiased
mat_sphere_sky
@@ -770,6 +770,11 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.curve.extrude_move
ops.curve.radius
ops.curve.vertex_random
+ ops.curves.sculpt_add
+ ops.curves.sculpt_comb
+ ops.curves.sculpt_cut
+ ops.curves.sculpt_delete
+ ops.curves.sculpt_grow
ops.generic.cursor
ops.generic.select
ops.generic.select_box
diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc
index 77cd5d9221f..6225a68f53c 100644
--- a/source/blender/editors/geometry/geometry_attributes.cc
+++ b/source/blender/editors/geometry/geometry_attributes.cc
@@ -36,10 +36,6 @@
namespace blender::ed::geometry {
-using fn::CPPType;
-using fn::GArray;
-using fn::GVArray;
-
/*********************** Attribute Operators ************************/
static bool geometry_attributes_poll(bContext *C)
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index d4518f21586..4f9468cc9c4 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -207,7 +207,7 @@ typedef struct tGpTimingData {
int seed;
/* Data set from points, used to compute final timing FCurve */
- int num_points, cur_point;
+ int points_num, cur_point;
/* Distances */
float *dists;
@@ -229,29 +229,29 @@ typedef struct tGpTimingData {
/* Init point buffers for timing data.
* Note this assumes we only grow those arrays!
*/
-static void gpencil_timing_data_set_nbr(tGpTimingData *gtd, const int nbr)
+static void gpencil_timing_data_set_num(tGpTimingData *gtd, const int num)
{
float *tmp;
- BLI_assert(nbr > gtd->num_points);
+ BLI_assert(num > gtd->points_num);
/* distances */
tmp = gtd->dists;
- gtd->dists = MEM_callocN(sizeof(float) * nbr, __func__);
+ gtd->dists = MEM_callocN(sizeof(float) * num, __func__);
if (tmp) {
- memcpy(gtd->dists, tmp, sizeof(float) * gtd->num_points);
+ memcpy(gtd->dists, tmp, sizeof(float) * gtd->points_num);
MEM_freeN(tmp);
}
/* times */
tmp = gtd->times;
- gtd->times = MEM_callocN(sizeof(float) * nbr, __func__);
+ gtd->times = MEM_callocN(sizeof(float) * num, __func__);
if (tmp) {
- memcpy(gtd->times, tmp, sizeof(float) * gtd->num_points);
+ memcpy(gtd->times, tmp, sizeof(float) * gtd->points_num);
MEM_freeN(tmp);
}
- gtd->num_points = nbr;
+ gtd->points_num = num;
}
/* add stroke point to timing buffers */
@@ -297,15 +297,15 @@ static void gpencil_timing_data_add_point(tGpTimingData *gtd,
static int gpencil_find_end_of_stroke_idx(tGpTimingData *gtd,
RNG *rng,
const int idx,
- const int nbr_gaps,
- int *nbr_done_gaps,
+ const int gaps_count,
+ int *gaps_done_count,
const float tot_gaps_time,
const float delta_time,
float *next_delta_time)
{
int j;
- for (j = idx + 1; j < gtd->num_points; j++) {
+ for (j = idx + 1; j < gtd->points_num; j++) {
if (gtd->times[j] < 0) {
gtd->times[j] = -gtd->times[j];
if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
@@ -316,7 +316,7 @@ static int gpencil_find_end_of_stroke_idx(tGpTimingData *gtd,
/* We want gaps that are in gtd->gap_duration +/- gtd->gap_randomness range,
* and which sum to exactly tot_gaps_time...
*/
- int rem_gaps = nbr_gaps - (*nbr_done_gaps);
+ int rem_gaps = gaps_count - (*gaps_done_count);
if (rem_gaps < 2) {
/* Last gap, just give remaining time! */
*next_delta_time = tot_gaps_time;
@@ -327,7 +327,7 @@ static int gpencil_find_end_of_stroke_idx(tGpTimingData *gtd,
/* This code ensures that if the first gaps
* have been shorter than average gap_duration, next gaps
* will tend to be longer (i.e. try to recover the lateness), and vice-versa! */
- delta = delta_time - (gtd->gap_duration * (*nbr_done_gaps));
+ delta = delta_time - (gtd->gap_duration * (*gaps_done_count));
/* Clamp min between [-gap_randomness, 0.0], with lower delta giving higher min */
min = -gtd->gap_randomness - delta;
@@ -343,7 +343,7 @@ static int gpencil_find_end_of_stroke_idx(tGpTimingData *gtd,
*next_delta_time += gtd->gap_duration;
}
}
- (*nbr_done_gaps)++;
+ (*gaps_done_count)++;
break;
}
}
@@ -353,14 +353,14 @@ static int gpencil_find_end_of_stroke_idx(tGpTimingData *gtd,
static void gpencil_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd,
RNG *rng,
- int *nbr_gaps,
+ int *gaps_count,
float *r_tot_gaps_time)
{
float delta_time = 0.0f;
- for (int i = 0; i < gtd->num_points; i++) {
+ for (int i = 0; i < gtd->points_num; i++) {
if (gtd->times[i] < 0 && i) {
- (*nbr_gaps)++;
+ (*gaps_count)++;
gtd->times[i] = -gtd->times[i] - delta_time;
delta_time += gtd->times[i] - gtd->times[i - 1];
gtd->times[i] = -gtd->times[i - 1]; /* Temp marker, values *have* to be different! */
@@ -371,7 +371,7 @@ static void gpencil_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd,
}
gtd->tot_time -= delta_time;
- *r_tot_gaps_time = (float)(*nbr_gaps) * gtd->gap_duration;
+ *r_tot_gaps_time = (float)(*gaps_count) * gtd->gap_duration;
gtd->tot_time += *r_tot_gaps_time;
if (gtd->gap_randomness > 0.0f) {
BLI_rng_srandom(rng, gtd->seed);
@@ -387,7 +387,7 @@ static void gpencil_stroke_path_animation_add_keyframes(ReportList *reports,
tGpTimingData *gtd,
RNG *rng,
const float time_range,
- const int nbr_gaps,
+ const int gaps_count,
const float tot_gaps_time)
{
/* Use actual recorded timing! */
@@ -399,20 +399,20 @@ static void gpencil_stroke_path_animation_add_keyframes(ReportList *reports,
/* CustomGaps specific */
float delta_time = 0.0f, next_delta_time = 0.0f;
- int nbr_done_gaps = 0;
+ int gaps_done_count = 0;
/* This is a bit tricky, as:
* - We can't add arbitrarily close points on FCurve (in time).
* - We *must* have all "caps" points of all strokes in FCurve, as much as possible!
*/
- for (int i = 0; i < gtd->num_points; i++) {
+ for (int i = 0; i < gtd->points_num; i++) {
/* If new stroke... */
if (i > end_stroke_idx) {
start_stroke_idx = i;
delta_time = next_delta_time;
/* find end of that new stroke */
end_stroke_idx = gpencil_find_end_of_stroke_idx(
- gtd, rng, i, nbr_gaps, &nbr_done_gaps, tot_gaps_time, delta_time, &next_delta_time);
+ gtd, rng, i, gaps_count, &gaps_done_count, tot_gaps_time, delta_time, &next_delta_time);
/* This one should *never* be negative! */
end_stroke_time = time_start +
((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range);
@@ -502,7 +502,7 @@ static void gpencil_stroke_path_animation(bContext *C,
FCurve *fcu;
PointerRNA ptr;
PropertyRNA *prop = NULL;
- int nbr_gaps = 0;
+ int gaps_count = 0;
if (gtd->mode == GP_STROKECONVERT_TIMING_NONE) {
return;
@@ -571,7 +571,7 @@ static void gpencil_stroke_path_animation(bContext *C,
/* Pre-process gaps, in case we don't want to keep their original timing */
if (gtd->mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
- gpencil_stroke_path_animation_preprocess_gaps(gtd, rng, &nbr_gaps, &tot_gaps_time);
+ gpencil_stroke_path_animation_preprocess_gaps(gtd, rng, &gaps_count, &tot_gaps_time);
}
if (gtd->realtime) {
@@ -582,7 +582,7 @@ static void gpencil_stroke_path_animation(bContext *C,
}
gpencil_stroke_path_animation_add_keyframes(
- reports, ptr, prop, depsgraph, fcu, cu, gtd, rng, time_range, nbr_gaps, tot_gaps_time);
+ reports, ptr, prop, depsgraph, fcu, cu, gtd, rng, time_range, gaps_count, tot_gaps_time);
BLI_rng_free(rng);
}
@@ -684,7 +684,7 @@ static void gpencil_stroke_to_path(bContext *C,
}
if (do_gtd) {
- gpencil_timing_data_set_nbr(gtd, nu->pntsu);
+ gpencil_timing_data_set_num(gtd, nu->pntsu);
}
/* If needed, make the link between both strokes with two zero-radius additional points */
@@ -929,7 +929,7 @@ static void gpencil_stroke_to_bezier(bContext *C,
}
if (do_gtd) {
- gpencil_timing_data_set_nbr(gtd, nu->pntsu);
+ gpencil_timing_data_set_num(gtd, nu->pntsu);
}
tot = gps->totpoints;
@@ -1536,7 +1536,7 @@ static int gpencil_convert_layer_exec(bContext *C, wmOperator *op)
gtd.gap_randomness = RNA_float_get(op->ptr, "gap_randomness");
gtd.gap_randomness = min_ff(gtd.gap_randomness, gtd.gap_duration);
gtd.seed = RNA_int_get(op->ptr, "seed");
- gtd.num_points = gtd.cur_point = 0;
+ gtd.points_num = gtd.cur_point = 0;
gtd.dists = gtd.times = NULL;
gtd.tot_dist = gtd.tot_time = gtd.gap_tot_time = 0.0f;
gtd.inittime = 0.0;
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 069493025dc..45a2247c65e 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1387,6 +1387,15 @@ static void gpencil_get_outline_points(tGPDfill *tgpf, const bool dilate)
current_check_co[1] = boundary_co[1] + offset[offset_idx][1];
int image_idx = ibuf->x * current_check_co[1] + current_check_co[0];
+ /* Check if the index is inside the image. If the index is outside is
+ * because the algorithm is unable to find the outline of the figure. This is
+ * possible for negative filling when click inside a figure instead of
+ * clicking outside.
+ * If the index is out of range, finish the filling. */
+ if (image_idx > imagesize - 1) {
+ start_found = false;
+ break;
+ }
get_pixel(ibuf, image_idx, rgba);
/* find next boundary pixel */
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 2f5f82e332c..84efc875be7 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -27,6 +27,7 @@ struct MeshDeformModifierData;
struct Object;
struct ReportList;
struct Scene;
+struct SelectPick_Params;
struct UndoType;
struct View3D;
struct ViewLayer;
@@ -164,18 +165,20 @@ bool ED_armature_edit_deselect_all_visible(struct Object *obedit);
bool ED_armature_edit_deselect_all_multi_ex(struct Base **bases, uint bases_len);
bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint bases_len);
bool ED_armature_edit_deselect_all_visible_multi(struct bContext *C);
+/**
+ * \return True when pick finds an element or the selection changed.
+ */
bool ED_armature_edit_select_pick_bone(struct bContext *C,
struct Base *basact,
struct EditBone *ebone,
int selmask,
- bool extend,
- bool deselect,
- bool toggle);
+ const struct SelectPick_Params *params);
/**
* 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);
+bool ED_armature_edit_select_pick(struct bContext *C,
+ const int mval[2],
+ const struct SelectPick_Params *params);
/**
* Perform a selection operation on elements which have been 'touched',
* use for lasso & border select but can be used elsewhere too.
@@ -305,25 +308,26 @@ void ED_pose_recalculate_paths(struct bContext *C,
/* pose_select.c */
-void ED_armature_pose_select_pick_bone(struct ViewLayer *view_layer,
+/**
+ * \return True when pick finds an element or the selection changed.
+ */
+bool ED_armature_pose_select_pick_bone(struct ViewLayer *view_layer,
struct View3D *v3d,
struct Object *ob,
struct Bone *bone,
- bool extend,
- bool deselect,
- bool toggle);
+ const struct SelectPick_Params *params);
/**
* Called for mode-less pose selection.
* assumes the active object is still on old situation.
+ *
+ * \return True when pick finds an element or the selection changed.
*/
bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer,
struct View3D *v3d,
struct Base *base,
const struct GPUSelectResult *buffer,
short hits,
- bool extend,
- bool deselect,
- bool toggle,
+ const struct SelectPick_Params *params,
bool do_nearest);
/**
* While in weight-paint mode, a single pose may be active as well.
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index c97f97a2ddc..6097e7c69d9 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -19,6 +19,7 @@ struct EditNurb;
struct Main;
struct Nurb;
struct Object;
+struct SelectPick_Params;
struct Text;
struct UndoType;
struct View3D;
@@ -46,8 +47,12 @@ void ED_curve_editnurb_load(struct Main *bmain, struct Object *obedit);
void ED_curve_editnurb_make(struct Object *obedit);
void ED_curve_editnurb_free(struct Object *obedit);
-bool ED_curve_editnurb_select_pick(
- struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+/**
+ * \return True when pick finds an element or the selection changed.
+ */
+bool ED_curve_editnurb_select_pick(struct bContext *C,
+ const int mval[2],
+ const struct SelectPick_Params *params);
struct Nurb *ED_curve_add_nurbs_primitive(
struct bContext *C, struct Object *obedit, float mat[4][4], int type, int newob);
@@ -100,10 +105,13 @@ int ED_curve_updateAnimPaths(struct Main *bmain, struct Curve *cu);
bool ED_curve_active_center(struct Curve *cu, float center[3]);
/**
- * TextBox selection
+ * Text box selection.
+ *
+ * \return True when pick finds an element or the selection changed.
*/
-bool ED_curve_editfont_select_pick(
- struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+bool ED_curve_editfont_select_pick(struct bContext *C,
+ const int mval[2],
+ const struct SelectPick_Params *params);
/* editfont_undo.c */
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index 90e8dbad272..3a0bb9738ae 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -382,6 +382,7 @@ void delete_fcurve_key(struct FCurve *fcu, int index, bool do_recalc);
bool delete_fcurve_keys(struct FCurve *fcu);
void clear_fcurve_keys(struct FCurve *fcu);
void duplicate_fcurve_keys(struct FCurve *fcu);
+float get_default_rna_value(struct FCurve *fcu, struct PropertyRNA *prop, struct PointerRNA *ptr);
typedef struct FCurveSegment {
struct FCurveSegment *next, *prev;
@@ -404,6 +405,7 @@ void blend_to_neighbor_fcurve_segment(struct FCurve *fcu,
float factor);
void breakdown_fcurve_segment(struct FCurve *fcu, struct FCurveSegment *segment, float factor);
bool decimate_fcurve(struct bAnimListElem *ale, float remove_ratio, float error_sq_max);
+void blend_to_default_fcurve(struct PointerRNA *id_ptr, struct FCurve *fcu, float factor);
/**
* Use a weighted moving-means method to reduce intensity of fluctuations.
*/
diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h
index eddf69e1cb6..1b9311cbacf 100644
--- a/source/blender/editors/include/ED_lattice.h
+++ b/source/blender/editors/include/ED_lattice.h
@@ -13,6 +13,7 @@ extern "C" {
struct Base;
struct Object;
+struct SelectPick_Params;
struct UndoType;
struct wmKeyConfig;
@@ -24,8 +25,12 @@ 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);
+/**
+ * \return True when pick finds an element or the selection changed.
+ */
+bool ED_lattice_select_pick(struct bContext *C,
+ const int mval[2],
+ const struct SelectPick_Params *params);
bool ED_lattice_deselect_all_multi_ex(struct Base **bases, uint bases_len);
bool ED_lattice_deselect_all_multi(struct bContext *C);
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index bc01f76f20d..7039d6d9fc7 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -63,7 +63,6 @@ bool ED_mask_selected_minmax(const struct bContext *C,
/* mask_draw.c */
-void ED_mask_draw(const struct bContext *C, char draw_flag, char draw_type);
/**
* Sets up the opengl context.
* width, height are to match the values from #ED_mask_get_size().
diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h
index e0c921ea0db..7f2c4dff311 100644
--- a/source/blender/editors/include/ED_mball.h
+++ b/source/blender/editors/include/ED_mball.h
@@ -12,7 +12,9 @@ extern "C" {
#endif
struct Base;
+struct MetaElem;
struct Object;
+struct SelectPick_Params;
struct UndoType;
struct bContext;
struct wmKeyConfig;
@@ -31,11 +33,19 @@ struct MetaElem *ED_mball_add_primitive(struct bContext *C,
float dia,
int type);
+struct Base *ED_mball_base_and_elem_from_select_buffer(struct Base **bases,
+ uint bases_len,
+ const uint select_id,
+ struct MetaElem **r_ml);
+
/**
- * Select MetaElement with mouse click (user can select radius circle or stiffness circle).
+ * Select meta-element with mouse click (user can select radius circle or stiffness circle).
+ *
+ * \return True when pick finds an element or the selection changed.
*/
-bool ED_mball_select_pick(
- struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+bool ED_mball_select_pick(struct bContext *C,
+ const int mval[2],
+ const struct SelectPick_Params *params);
bool ED_mball_deselect_all_multi_ex(struct Base **bases, uint bases_len);
bool ED_mball_deselect_all_multi(struct bContext *C);
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 68e46dfa0e5..03ca4cd062b 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -31,6 +31,7 @@ struct Mesh;
struct Object;
struct ReportList;
struct Scene;
+struct SelectPick_Params;
struct UndoType;
struct UvMapVert;
struct UvVertMap;
@@ -268,8 +269,9 @@ bool EDBM_unified_findnearest_from_raycast(struct ViewContext *vc,
struct BMEdge **r_eed,
struct BMFace **r_efa);
-bool EDBM_select_pick(
- struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+bool EDBM_select_pick(struct bContext *C,
+ const int mval[2],
+ const struct SelectPick_Params *params);
/**
* When switching select mode, makes sure selection is consistent for editing
@@ -387,12 +389,13 @@ void ED_keymap_mesh(struct wmKeyConfig *keyconf);
* use in object mode when selecting faces (while painting).
*/
void paintface_flush_flags(struct bContext *C, struct Object *ob, short flag);
+/**
+ * \return True when pick finds an element or the selection changed.
+ */
bool paintface_mouse_select(struct bContext *C,
- struct Object *ob,
const int mval[2],
- bool extend,
- bool deselect,
- bool toggle);
+ const struct SelectPick_Params *params,
+ struct Object *ob);
bool paintface_deselect_all_visible(struct bContext *C,
struct Object *ob,
int action,
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index a4797ff167c..553aa444891 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -16,6 +16,7 @@ struct PTCacheEdit;
struct ParticleEditSettings;
struct ParticleSystem;
struct Scene;
+struct SelectPick_Params;
struct UndoType;
struct ViewLayer;
struct bContext;
@@ -54,8 +55,9 @@ void PE_update_object(struct Depsgraph *depsgraph,
/* selection tools */
-bool PE_mouse_particles(
- struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle);
+bool PE_mouse_particles(struct bContext *C,
+ const int mval[2],
+ const struct SelectPick_Params *params);
bool PE_box_select(struct bContext *C, const struct rcti *rect, int sel_op);
bool PE_circle_select(struct bContext *C,
struct wmGenericUserData *wm_userdata,
diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h
index 26d8d0a3d8c..b9ef5c283aa 100644
--- a/source/blender/editors/include/ED_select_utils.h
+++ b/source/blender/editors/include/ED_select_utils.h
@@ -70,6 +70,31 @@ bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree,
*/
eSelectOp ED_select_op_modal(eSelectOp sel_op, bool is_first);
+/** Argument passed to picking functions. */
+struct SelectPick_Params {
+ /**
+ * - #SEL_OP_ADD named "extend" from operators.
+ * - #SEL_OP_SUB named "deselect" from operators.
+ * - #SEL_OP_XOR named "toggle" from operators.
+ * - #SEL_OP_AND (never used for picking).
+ * - #SEL_OP_SET use when "extend", "deselect" and "toggle" are all disabled.
+ */
+ eSelectOp sel_op;
+ /** Deselect all, even when there is nothing found at the cursor location. */
+ bool deselect_all;
+ /**
+ * When selecting an element that is already selected, do nothing (passthrough).
+ * don't even make it active.
+ * Use to implement tweaking to move the selection without first de-selecting.
+ */
+ bool select_passthrough;
+};
+
+/**
+ * Utility to get #eSelectPickMode from booleans for convenience.
+ */
+eSelectOp ED_select_op_from_booleans(bool extend, bool deselect, bool toggle);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index d28700c64ee..d8415064d2f 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -157,6 +157,8 @@ enum {
UI_BLOCK_POPOVER_ONCE = 1 << 22,
/** Always show key-maps, even for non-menus. */
UI_BLOCK_SHOW_SHORTCUT_ALWAYS = 1 << 23,
+ /** Don't show library override state for buttons in this block. */
+ UI_BLOCK_NO_DRAW_OVERRIDDEN_STATE = 1 << 24,
/** The block is only used during the search process and will not be drawn.
* Currently just for the case of a closed panel's sub-panel (and its sub-panels). */
UI_BLOCK_SEARCH_ONLY = 1 << 25,
@@ -1610,6 +1612,14 @@ uiBut *uiDefAutoButR(uiBlock *block,
int y,
int width,
int height);
+void uiDefAutoButsArrayR(uiBlock *block,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ const int icon,
+ const int x,
+ const int y,
+ const int tot_width,
+ const 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.
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 3619a7ce317..e83a8761e12 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -4238,28 +4238,28 @@ static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *bu
int totitems = 0;
int categories = 0;
- int nbr_entries_nosepr = 0;
+ int entries_nosepr_count = 0;
for (const EnumPropertyItem *item = item_array; item->identifier; item++, totitems++) {
if (!item->identifier[0]) {
/* inconsistent, but menus with categories do not look good flipped */
if (item->name) {
block->flag |= UI_BLOCK_NO_FLIP;
categories++;
- nbr_entries_nosepr++;
+ entries_nosepr_count++;
}
- /* We do not want simple separators in nbr_entries_nosepr count */
+ /* We do not want simple separators in `entries_nosepr_count`. */
continue;
}
- nbr_entries_nosepr++;
+ entries_nosepr_count++;
}
/* Columns and row estimation. Ignore simple separators here. */
- int columns = (nbr_entries_nosepr + 20) / 20;
+ int columns = (entries_nosepr_count + 20) / 20;
if (columns < 1) {
columns = 1;
}
if (columns > 8) {
- columns = (nbr_entries_nosepr + 25) / 25;
+ columns = (entries_nosepr_count + 25) / 25;
}
int rows = totitems / columns;
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index decd8c03d70..c02024bc82d 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -546,13 +546,13 @@ void ui_draw_but_HISTOGRAM(ARegion *UNUSED(region),
#undef HISTOGRAM_TOT_GRID_LINES
-static void waveform_draw_one(float *waveform, int nbr, const float col[3])
+static void waveform_draw_one(float *waveform, int waveform_num, const float col[3])
{
GPUVertFormat format = {0};
const uint pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, nbr);
+ GPU_vertbuf_data_alloc(vbo, waveform_num);
GPU_vertbuf_attr_fill(vbo, pos_id, waveform);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 8677b1ed78a..8935df7b581 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -7969,7 +7969,16 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
if (but->flag & UI_BUT_DISABLED) {
- return WM_UI_HANDLER_BREAK;
+ /* It's important to continue here instead of breaking since breaking causes the event to be
+ * considered "handled", preventing further click/drag events from being generated.
+ *
+ * An example of where this is needed is dragging node-sockets, where dragging a node-socket
+ * could exit the button before the drag threshold was reached, disable the button then break
+ * handling of the #MOUSEMOVE event preventing the socket being dragged entirely, see: T96255.
+ *
+ * Region level event handling is responsible for preventing events being passed
+ * through to parts of the UI that are logically behind this button, see: T92364. */
+ return WM_UI_HANDLER_CONTINUE;
}
switch (but->type) {
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 694ae78ca9e..a7a2409ef17 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -1275,7 +1275,8 @@ void ui_layout_remove_but(uiLayout *layout, const uiBut *but);
*/
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.
+ * \note May reallocate \a but, so the possibly new address is returned. May also override the
+ * #UI_BUT_DISABLED flag depending on if a search pointer-property pair was provided/found.
*/
uiBut *ui_but_add_search(uiBut *but,
PointerRNA *ptr,
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 17f0ae1f2d4..cbc21bd481f 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -2751,6 +2751,10 @@ uiBut *ui_but_add_search(
ui_rna_collection_search_arg_free_fn,
NULL,
NULL);
+ /* If this is called multiple times for the same button, an earlier call may have taken the
+ * else branch below so the button was disabled. Now we have a searchprop, so it can be enabled
+ * again. */
+ but->flag &= ~UI_BUT_DISABLED;
}
else if (but->type == UI_BTYPE_SEARCH_MENU) {
/* In case we fail to find proper searchprop,
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 54bd1a2cebb..0f4f0ef48ff 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1976,6 +1976,9 @@ static void UI_OT_drop_name(wmOperatorType *ot)
static bool ui_list_focused_poll(bContext *C)
{
const ARegion *region = CTX_wm_region(C);
+ if (!region) {
+ return false;
+ }
const wmWindow *win = CTX_wm_window(C);
const uiList *list = UI_list_find_mouse_over(region, win->eventstate);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index ad7c71e3be9..0e417fda911 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -6261,16 +6261,13 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout,
ColorManagedViewSettings *view_settings = view_transform_ptr.data;
uiLayout *col = uiLayoutColumn(layout, false);
-
- uiLayout *row = uiLayoutRow(col, false);
- uiItemR(row, &view_transform_ptr, "view_transform", 0, IFACE_("View"), ICON_NONE);
+ uiItemR(col, &view_transform_ptr, "view_transform", 0, IFACE_("View"), ICON_NONE);
+ uiItemR(col, &view_transform_ptr, "look", 0, IFACE_("Look"), ICON_NONE);
col = uiLayoutColumn(layout, false);
uiItemR(col, &view_transform_ptr, "exposure", 0, NULL, ICON_NONE);
uiItemR(col, &view_transform_ptr, "gamma", 0, NULL, ICON_NONE);
- uiItemR(col, &view_transform_ptr, "look", 0, IFACE_("Look"), ICON_NONE);
-
col = uiLayoutColumn(layout, false);
uiItemR(col, &view_transform_ptr, "use_curve_mapping", 0, NULL, ICON_NONE);
if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES) {
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 814bd956096..728d42a9353 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -320,6 +320,7 @@ uiBut *uiDefAutoButR(uiBlock *block,
-1,
-1,
NULL);
+ ui_but_add_search(but, ptr, prop, NULL, NULL);
break;
}
case PROP_COLLECTION: {
@@ -338,6 +339,29 @@ uiBut *uiDefAutoButR(uiBlock *block,
return but;
}
+void uiDefAutoButsArrayR(uiBlock *block,
+ PointerRNA *ptr,
+ PropertyRNA *prop,
+ const int icon,
+ const int x,
+ const int y,
+ const int tot_width,
+ const int height)
+{
+ const int len = RNA_property_array_length(ptr, prop);
+ if (len == 0) {
+ return;
+ }
+
+ const int item_width = tot_width / len;
+
+ UI_block_align_begin(block);
+ for (int i = 0; i < len; i++) {
+ uiDefAutoButR(block, ptr, prop, i, "", icon, x + i * item_width, y, item_width, height);
+ }
+ UI_block_align_end(block);
+}
+
eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
PointerRNA *ptr,
bool (*check_prop)(PointerRNA *ptr,
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 35cf952b5ce..b33cab3cbc6 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -4963,6 +4963,9 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu
}
}
#endif
+ if (but->block->flag & UI_BLOCK_NO_DRAW_OVERRIDDEN_STATE) {
+ state &= ~UI_BUT_OVERRIDDEN;
+ }
const float zoom = 1.0f / but->block->aspect;
wt->state(wt, state, drawflag, but->emboss);
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index 1d5c9d717d0..dc62212bf53 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -221,14 +221,6 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
export_settings.limit_precision = limit_precision != 0;
export_settings.keep_bind_info = keep_bind_info != 0;
- int includeFilter = OB_REL_NONE;
- if (export_settings.include_armatures) {
- includeFilter |= OB_REL_MOD_ARMATURE;
- }
- if (export_settings.include_children) {
- includeFilter |= OB_REL_CHILDREN_RECURSIVE;
- }
-
export_count = collada_export(C, &export_settings);
if (export_count == 0) {
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
index f253f63946b..df15191916a 100644
--- a/source/blender/editors/io/io_obj.c
+++ b/source/blender/editors/io/io_obj.c
@@ -293,11 +293,8 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
0.01,
1000.0f);
/* File Writer options. */
- RNA_def_boolean(ot->srna,
- "apply_modifiers",
- true,
- "Apply Modifiers",
- "Apply modifiers to exported meshes");
+ RNA_def_boolean(
+ ot->srna, "apply_modifiers", true, "Apply Modifiers", "Apply modifiers to exported meshes");
RNA_def_enum(ot->srna,
"export_eval_mode",
io_obj_export_evaluation_mode,
@@ -345,7 +342,7 @@ void WM_OT_obj_export(struct wmOperatorType *ot)
"export_material_groups",
false,
"Export Material Groups",
- "Append mesh name and material name to object name, separated by a '_'");
+ "Generate an OBJ group for each part of a geometry using a different material");
RNA_def_boolean(
ot->srna,
"export_vertex_groups",
diff --git a/source/blender/editors/lattice/editlattice_select.c b/source/blender/editors/lattice/editlattice_select.c
index d1635078126..ea99c6e23ff 100644
--- a/source/blender/editors/lattice/editlattice_select.c
+++ b/source/blender/editors/lattice/editlattice_select.c
@@ -556,15 +556,18 @@ void LATTICE_OT_select_ungrouped(wmOperatorType *ot)
* Gets called via generic mouse select operator.
* \{ */
-static void findnearestLattvert__doClosest(void *userData, BPoint *bp, const float screen_co[2])
+struct NearestLatticeVert_UserData {
+ BPoint *bp;
+ float dist;
+ /** When true, the existing selection gets a disadvantage. */
+ bool select;
+ float mval_fl[2];
+ bool is_changed;
+};
+
+static void findnearestLattvert__doClosest(void *user_data, BPoint *bp, const float screen_co[2])
{
- struct {
- BPoint *bp;
- float dist;
- int select;
- float mval_fl[2];
- bool is_changed;
- } *data = userData;
+ struct NearestLatticeVert_UserData *data = user_data;
float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
if ((bp->f1 & SELECT) && data->select) {
@@ -578,21 +581,12 @@ static void findnearestLattvert__doClosest(void *userData, BPoint *bp, const flo
}
}
-static BPoint *findnearestLattvert(ViewContext *vc, int sel, Base **r_base)
+static BPoint *findnearestLattvert(ViewContext *vc, bool select, Base **r_base)
{
- /* (sel == 1): selected gets a disadvantage */
- /* in nurb and bezt or bp the nearest is written */
- /* return 0 1 2: handlepunt */
- struct {
- BPoint *bp;
- float dist;
- int select;
- float mval_fl[2];
- bool is_changed;
- } data = {NULL};
+ struct NearestLatticeVert_UserData data = {NULL};
data.dist = ED_view3d_select_dist_px();
- data.select = sel;
+ data.select = select;
data.mval_fl[0] = vc->mval[0];
data.mval_fl[1] = vc->mval[1];
@@ -616,24 +610,27 @@ static BPoint *findnearestLattvert(ViewContext *vc, int sel, Base **r_base)
return data.bp;
}
-bool ED_lattice_select_pick(
- bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+bool ED_lattice_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
BPoint *bp = NULL;
Base *basact = NULL;
+ bool changed = false;
ED_view3d_viewcontext_init(C, &vc, depsgraph);
vc.mval[0] = mval[0];
vc.mval[1] = mval[1];
bp = findnearestLattvert(&vc, true, &basact);
- if (bp) {
- ED_view3d_viewcontext_init_object(&vc, basact->object);
- Lattice *lt = ((Lattice *)vc.obedit->data)->editlatt->latt;
+ bool found = (bp != NULL);
- if (!extend && !deselect && !toggle) {
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) && (bp->f1 & SELECT)) {
+ found = false;
+ }
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &objects_len);
@@ -645,20 +642,36 @@ bool ED_lattice_select_pick(
}
}
MEM_freeN(objects);
+ changed = true;
}
+ }
- if (extend) {
- bp->f1 |= SELECT;
- }
- else if (deselect) {
- bp->f1 &= ~SELECT;
- }
- else if (toggle) {
- bp->f1 ^= SELECT; /* swap */
- }
- else {
- ED_lattice_flags_set(vc.obedit, 0);
- bp->f1 |= SELECT;
+ if (found) {
+ ED_view3d_viewcontext_init_object(&vc, basact->object);
+ Lattice *lt = ((Lattice *)vc.obedit->data)->editlatt->latt;
+
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ bp->f1 |= SELECT;
+ break;
+ }
+ case SEL_OP_SUB: {
+ bp->f1 &= ~SELECT;
+ break;
+ }
+ case SEL_OP_XOR: {
+ bp->f1 ^= SELECT; /* swap */
+ break;
+ }
+ case SEL_OP_SET: {
+ ED_lattice_flags_set(vc.obedit, 0);
+ bp->f1 |= SELECT;
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
+ }
}
if (bp->f1 & SELECT) {
@@ -675,10 +688,10 @@ bool ED_lattice_select_pick(
DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
- return true;
+ changed = true;
}
- return false;
+ return changed || found;
}
/** \} */
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 8fe3b74f9c9..60232dee109 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -638,21 +638,6 @@ static void draw_mask_layers(const bContext *C,
GPU_blend(GPU_BLEND_NONE);
}
-void ED_mask_draw(const bContext *C, const char draw_flag, const char draw_type)
-{
- ScrArea *area = CTX_wm_area(C);
- Mask *mask = CTX_data_edit_mask(C);
- int width, height;
-
- if (!mask) {
- return;
- }
-
- ED_mask_get_size(area, &width, &height);
-
- draw_mask_layers(C, mask, draw_flag, draw_type, width, height);
-}
-
static float *mask_rasterize(Mask *mask, const int width, const int height)
{
MaskRasterHandle *handle;
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 8a1e12c76c5..a5c6adaa43e 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -366,59 +366,77 @@ bool paintface_minmax(Object *ob, float r_min[3], float r_max[3])
return ok;
}
-bool paintface_mouse_select(
- struct bContext *C, Object *ob, const int mval[2], bool extend, bool deselect, bool toggle)
+bool paintface_mouse_select(struct bContext *C,
+ const int mval[2],
+ const struct SelectPick_Params *params,
+ Object *ob)
{
Mesh *me;
- MPoly *mpoly_sel;
+ MPoly *mpoly_sel = NULL;
uint index;
+ bool changed = false;
+ bool found = false;
/* Get the face under the cursor */
me = BKE_mesh_from_object(ob);
- if (!ED_mesh_pick_face(C, ob, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
- return false;
- }
-
- if (index >= me->totpoly) {
- return false;
- }
-
- mpoly_sel = me->mpoly + index;
- if (mpoly_sel->flag & ME_HIDE) {
- return false;
+ if (ED_mesh_pick_face(C, ob, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) {
+ if (index < me->totpoly) {
+ mpoly_sel = me->mpoly + index;
+ if ((mpoly_sel->flag & ME_HIDE) == 0) {
+ found = true;
+ }
+ }
}
- /* clear flags */
- if (!extend && !deselect && !toggle) {
- paintface_deselect_all_visible(C, ob, SEL_DESELECT, false);
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) && (mpoly_sel->flag & ME_FACE_SEL)) {
+ found = false;
+ }
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
+ changed |= paintface_deselect_all_visible(C, ob, SEL_DESELECT, false);
+ }
}
- me->act_face = (int)index;
+ if (found) {
+ me->act_face = (int)index;
- if (extend) {
- mpoly_sel->flag |= ME_FACE_SEL;
- }
- else if (deselect) {
- mpoly_sel->flag &= ~ME_FACE_SEL;
- }
- else if (toggle) {
- if (mpoly_sel->flag & ME_FACE_SEL) {
- mpoly_sel->flag &= ~ME_FACE_SEL;
- }
- else {
- mpoly_sel->flag |= ME_FACE_SEL;
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ mpoly_sel->flag |= ME_FACE_SEL;
+ break;
+ }
+ case SEL_OP_SUB: {
+ mpoly_sel->flag &= ~ME_FACE_SEL;
+ break;
+ }
+ case SEL_OP_XOR: {
+ if (mpoly_sel->flag & ME_FACE_SEL) {
+ mpoly_sel->flag &= ~ME_FACE_SEL;
+ }
+ else {
+ mpoly_sel->flag |= ME_FACE_SEL;
+ }
+ break;
+ }
+ case SEL_OP_SET: {
+ mpoly_sel->flag |= ME_FACE_SEL;
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
+ }
}
- }
- else {
- mpoly_sel->flag |= ME_FACE_SEL;
- }
- /* image window redraw */
+ /* image window redraw */
- paintface_flush_flags(C, ob, SELECT);
- ED_region_tag_redraw(CTX_wm_region(C)); /* XXX: should redraw all 3D views. */
- return true;
+ paintface_flush_flags(C, ob, SELECT);
+ ED_region_tag_redraw(CTX_wm_region(C)); /* XXX: should redraw all 3D views. */
+ changed = true;
+ }
+ return changed || found;
}
void paintvert_flush_flags(Object *ob)
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index faf449a77aa..d3fc83eedd7 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -108,6 +108,7 @@ static int geometry_extract_apply(bContext *C,
new_mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
BMEditMesh *em = BKE_editmesh_create(bm);
diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c
index dbda9fa7746..f2e7150e791 100644
--- a/source/blender/editors/mesh/editmesh_path.c
+++ b/source/blender/editors/mesh/editmesh_path.c
@@ -28,6 +28,7 @@
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
@@ -700,7 +701,10 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE
/* TODO(dfelinto): right now we try to find the closest element twice.
* The ideal is to refactor EDBM_select_pick so it doesn't
* have to pick the nearest vert/edge/face again. */
- EDBM_select_pick(C, event->mval, true, false, false);
+ const struct SelectPick_Params params = {
+ .sel_op = SEL_OP_ADD,
+ };
+ EDBM_select_pick(C, event->mval, &params);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_rip_edge.c b/source/blender/editors/mesh/editmesh_rip_edge.c
index 6b3a796ab0d..85426acb905 100644
--- a/source/blender/editors/mesh/editmesh_rip_edge.c
+++ b/source/blender/editors/mesh/editmesh_rip_edge.c
@@ -125,7 +125,7 @@ static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve
#ifdef USE_TRICKY_EXTEND
/* first check if we can select the edge to split based on selection-only */
- int tot_sel = 0, tot = 0;
+ int tot_sel = 0;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
@@ -133,7 +133,6 @@ static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve
e_best = e;
tot_sel += 1;
}
- tot += 1;
}
}
if (tot_sel != 1) {
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 8784b1a90d9..9c8c5c45cb7 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -2016,7 +2016,7 @@ void MESH_OT_select_interior_faces(wmOperatorType *ot)
* Gets called via generic mouse select operator.
* \{ */
-bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+bool EDBM_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params)
{
ViewContext vc;
@@ -2033,100 +2033,153 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
- bool ok = false;
-
- if (unified_findnearest(&vc, bases, bases_len, &base_index_active, &eve, &eed, &efa)) {
- Base *basact = bases[base_index_active];
- ED_view3d_viewcontext_init_object(&vc, basact->object);
+ bool changed = false;
+ bool found = unified_findnearest(&vc, bases, bases_len, &base_index_active, &eve, &eed, &efa);
- /* Deselect everything */
- if (extend == false && deselect == false && toggle == false) {
+ if (params->sel_op == SEL_OP_SET) {
+ BMElem *ele = efa ? (BMElem *)efa : (eed ? (BMElem *)eed : (BMElem *)eve);
+ if ((found && params->select_passthrough) && BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
+ found = false;
+ }
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
for (uint base_index = 0; base_index < bases_len; base_index++) {
Base *base_iter = bases[base_index];
Object *ob_iter = base_iter->object;
EDBM_flag_disable_all(BKE_editmesh_from_object(ob_iter), BM_ELEM_SELECT);
- if (basact->object != ob_iter) {
- DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
- }
+ DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
}
+ changed = true;
}
+ }
+
+ if (found) {
+ Base *basact = bases[base_index_active];
+ ED_view3d_viewcontext_init_object(&vc, basact->object);
if (efa) {
- if (extend) {
- /* set the last selected face */
- BM_mesh_active_face_set(vc.em->bm, efa);
-
- /* Work-around: deselect first, so we can guarantee it will */
- /* be active even if it was already selected */
- BM_select_history_remove(vc.em->bm, efa);
- BM_face_select_set(vc.em->bm, efa, false);
- BM_select_history_store(vc.em->bm, efa);
- BM_face_select_set(vc.em->bm, efa, true);
- }
- else if (deselect) {
- BM_select_history_remove(vc.em->bm, efa);
- BM_face_select_set(vc.em->bm, efa, false);
- }
- else {
- /* set the last selected face */
- BM_mesh_active_face_set(vc.em->bm, efa);
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ BM_mesh_active_face_set(vc.em->bm, efa);
- if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ /* Work-around: deselect first, so we can guarantee it will
+ * be active even if it was already selected. */
+ BM_select_history_remove(vc.em->bm, efa);
+ BM_face_select_set(vc.em->bm, efa, false);
BM_select_history_store(vc.em->bm, efa);
BM_face_select_set(vc.em->bm, efa, true);
+ break;
}
- else if (toggle) {
+ case SEL_OP_SUB: {
BM_select_history_remove(vc.em->bm, efa);
BM_face_select_set(vc.em->bm, efa, false);
+ break;
+ }
+ case SEL_OP_XOR: {
+ BM_mesh_active_face_set(vc.em->bm, efa);
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_select_history_store(vc.em->bm, efa);
+ BM_face_select_set(vc.em->bm, efa, true);
+ }
+ else {
+ BM_select_history_remove(vc.em->bm, efa);
+ BM_face_select_set(vc.em->bm, efa, false);
+ }
+ break;
+ }
+ case SEL_OP_SET: {
+ BM_mesh_active_face_set(vc.em->bm, efa);
+ if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_select_history_store(vc.em->bm, efa);
+ BM_face_select_set(vc.em->bm, efa, true);
+ }
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
}
}
}
else if (eed) {
- if (extend) {
- /* Work-around: deselect first, so we can guarantee it will */
- /* be active even if it was already selected */
- BM_select_history_remove(vc.em->bm, eed);
- BM_edge_select_set(vc.em->bm, eed, false);
- BM_select_history_store(vc.em->bm, eed);
- BM_edge_select_set(vc.em->bm, eed, true);
- }
- else if (deselect) {
- BM_select_history_remove(vc.em->bm, eed);
- BM_edge_select_set(vc.em->bm, eed, false);
- }
- else {
- if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ /* Work-around: deselect first, so we can guarantee it will
+ * be active even if it was already selected. */
+ BM_select_history_remove(vc.em->bm, eed);
+ BM_edge_select_set(vc.em->bm, eed, false);
BM_select_history_store(vc.em->bm, eed);
BM_edge_select_set(vc.em->bm, eed, true);
+ break;
}
- else if (toggle) {
+ case SEL_OP_SUB: {
BM_select_history_remove(vc.em->bm, eed);
BM_edge_select_set(vc.em->bm, eed, false);
+ break;
+ }
+ case SEL_OP_XOR: {
+ if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ BM_select_history_store(vc.em->bm, eed);
+ BM_edge_select_set(vc.em->bm, eed, true);
+ }
+ else {
+ BM_select_history_remove(vc.em->bm, eed);
+ BM_edge_select_set(vc.em->bm, eed, false);
+ }
+ break;
+ }
+ case SEL_OP_SET: {
+ if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ BM_select_history_store(vc.em->bm, eed);
+ BM_edge_select_set(vc.em->bm, eed, true);
+ }
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
}
}
}
else if (eve) {
- if (extend) {
- /* Work-around: deselect first, so we can guarantee it will */
- /* be active even if it was already selected */
- BM_select_history_remove(vc.em->bm, eve);
- BM_vert_select_set(vc.em->bm, eve, false);
- BM_select_history_store(vc.em->bm, eve);
- BM_vert_select_set(vc.em->bm, eve, true);
- }
- else if (deselect) {
- BM_select_history_remove(vc.em->bm, eve);
- BM_vert_select_set(vc.em->bm, eve, false);
- }
- else {
- if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ /* Work-around: deselect first, so we can guarantee it will
+ * be active even if it was already selected. */
+ BM_select_history_remove(vc.em->bm, eve);
+ BM_vert_select_set(vc.em->bm, eve, false);
BM_select_history_store(vc.em->bm, eve);
BM_vert_select_set(vc.em->bm, eve, true);
+ break;
}
- else if (toggle) {
+ case SEL_OP_SUB: {
BM_select_history_remove(vc.em->bm, eve);
BM_vert_select_set(vc.em->bm, eve, false);
+ break;
+ }
+ case SEL_OP_XOR: {
+ if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ BM_select_history_store(vc.em->bm, eve);
+ BM_vert_select_set(vc.em->bm, eve, true);
+ }
+ else {
+ BM_select_history_remove(vc.em->bm, eve);
+ BM_vert_select_set(vc.em->bm, eve, false);
+ }
+ break;
+ }
+ case SEL_OP_SET: {
+ if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ BM_select_history_store(vc.em->bm, eve);
+ BM_vert_select_set(vc.em->bm, eve, true);
+ }
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
}
}
}
@@ -2168,12 +2221,12 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect
DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
- ok = true;
+ changed = true;
}
MEM_freeN(bases);
- return ok;
+ return changed;
}
/** \} */
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 54cc3efe986..2181b652d16 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -57,6 +57,7 @@
#include "ED_object.h"
#include "ED_outliner.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_transform.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
@@ -2301,7 +2302,7 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
BMIter iter;
const bool use_ccw = RNA_boolean_get(op->ptr, "use_ccw");
- int tot_rotate_all = 0, tot_failed_all = 0;
+ int tot_failed_all = 0;
bool no_selected_edges = true, invalid_selected_edges = true;
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -2359,7 +2360,6 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
const int tot_rotate = BMO_slot_buffer_len(bmop.slots_out, "edges.out");
const int tot_failed = tot - tot_rotate;
- tot_rotate_all += tot_rotate;
tot_failed_all += tot_failed;
if (tot_failed != 0) {
@@ -8540,7 +8540,10 @@ static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *
case EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED:
new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES;
view3d_operator_needs_opengl(C);
- if (EDBM_select_pick(C, event->mval, false, false, false)) {
+ const struct SelectPick_Params params = {
+ .sel_op = SEL_OP_SET,
+ };
+ if (EDBM_select_pick(C, event->mval, &params)) {
/* Point to newly selected active. */
ED_object_calc_active_center_for_editmode(obedit, false, target);
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index 9c7d712a739..ecc5f8f8ef5 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -673,6 +673,7 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em)
(&(struct BMeshFromMeshParams){
/* Handled with tessellation. */
.calc_face_normal = false,
+ .calc_vert_normal = false,
.active_shapekey = um->shapenr,
}));
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 136d0d46c68..06a649e5b6c 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -736,14 +736,43 @@ void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
/** \name Select Pick Utility
* \{ */
-bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+Base *ED_mball_base_and_elem_from_select_buffer(Base **bases,
+ uint bases_len,
+ const uint select_id,
+ MetaElem **r_ml)
+{
+ const uint hit_object = select_id & 0xFFFF;
+ Base *base = NULL;
+ MetaElem *ml = NULL;
+ /* TODO(campbell): optimize, eg: sort & binary search. */
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ if (bases[base_index]->object->runtime.select_id == hit_object) {
+ base = bases[base_index];
+ break;
+ }
+ }
+ if (base != NULL) {
+ const uint hit_elem = (select_id & ~MBALLSEL_ANY) >> 16;
+ MetaBall *mb = base->object->data;
+ ml = BLI_findlink(mb->editelems, hit_elem);
+ }
+ *r_ml = ml;
+ return base;
+}
+
+static bool ed_mball_findnearest_metaelem(bContext *C,
+ const int mval[2],
+ bool use_cycle,
+ Base **r_base,
+ MetaElem **r_ml,
+ uint *r_selmask)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- static MetaElem *startelem = NULL;
ViewContext vc;
int a, hits;
GPUSelectResult buffer[MAXPICKELEMS];
rcti rect;
+ bool found = false;
ED_view3d_viewcontext_init(C, &vc, depsgraph);
@@ -753,131 +782,140 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
buffer,
ARRAY_SIZE(buffer),
&rect,
- VIEW3D_SELECT_PICK_NEAREST,
+ use_cycle ? VIEW3D_SELECT_PICK_ALL : VIEW3D_SELECT_PICK_NEAREST,
VIEW3D_SELECT_FILTER_NOP);
- FOREACH_BASE_IN_EDIT_MODE_BEGIN (vc.view_layer, vc.v3d, base) {
- ED_view3d_viewcontext_init_object(&vc, base->object);
- MetaBall *mb = (MetaBall *)base->object->data;
- MetaElem *ml, *ml_act = NULL;
+ if (hits == 0) {
+ return false;
+ }
- /* does startelem exist? */
- ml = mb->editelems->first;
- while (ml) {
- if (ml == startelem) {
- break;
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len);
+
+ int hit_cycle_offset = 0;
+ if (use_cycle) {
+ /* When cycling, use the hit directly after the current active meta-element (when set). */
+ const int base_index = vc.obact->runtime.select_id;
+ MetaBall *mb = (MetaBall *)vc.obact->data;
+ MetaElem *ml = mb->lastelem;
+ if (ml && (ml->flag & SELECT)) {
+ const int ml_index = BLI_findindex(mb->editelems, ml);
+ BLI_assert(ml_index != -1);
+
+ /* Count backwards in case the active meta-element has multiple entries,
+ * ensure this steps onto the next meta-element. */
+ a = hits;
+ while (a--) {
+ const int select_id = buffer[a].id;
+ if (select_id == -1) {
+ continue;
+ }
+
+ if (((select_id & 0xFFFF) == base_index) &&
+ ((select_id & ~MBALLSEL_ANY) >> 16 == ml_index)) {
+ hit_cycle_offset = a + 1;
+ break;
+ }
}
- ml = ml->next;
}
+ }
- if (ml == NULL) {
- startelem = mb->editelems->first;
+ for (a = 0; a < hits; a++) {
+ const int index = (hit_cycle_offset == 0) ? a : ((a + hit_cycle_offset) % hits);
+ const uint select_id = buffer[index].id;
+ if (select_id == -1) {
+ continue;
}
- if (hits > 0) {
- int metaelem_id = 0;
- ml = startelem;
- while (ml) {
- for (a = 0; a < hits; a++) {
- const int hitresult = buffer[a].id;
- if (hitresult == -1) {
- continue;
- }
+ MetaElem *ml;
+ Base *base = ED_mball_base_and_elem_from_select_buffer(bases, bases_len, select_id, &ml);
+ if (ml == NULL) {
+ continue;
+ }
+ *r_base = base;
+ *r_ml = ml;
+ *r_selmask = select_id & MBALLSEL_ANY;
+ found = true;
+ break;
+ }
- const uint hit_object = hitresult & 0xFFFF;
- if (vc.obedit->runtime.select_id != hit_object) {
- continue;
- }
+ MEM_freeN(bases);
- if (metaelem_id != (hitresult & 0xFFFF0000 & ~MBALLSEL_ANY)) {
- continue;
- }
+ return found;
+}
- if (hitresult & MBALLSEL_RADIUS) {
- ml->flag |= MB_SCALE_RAD;
- ml_act = ml;
- break;
- }
+bool ED_mball_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params)
+{
+ Base *base = NULL;
+ MetaElem *ml = NULL;
+ uint selmask = 0;
- if (hitresult & MBALLSEL_STIFF) {
- ml->flag &= ~MB_SCALE_RAD;
- ml_act = ml;
- break;
- }
- }
+ bool changed = false;
- if (ml_act) {
- break;
- }
- ml = ml->next;
- if (ml == NULL) {
- ml = mb->editelems->first;
- }
- if (ml == startelem) {
- break;
- }
+ bool found = ed_mball_findnearest_metaelem(C, mval, true, &base, &ml, &selmask);
- metaelem_id += 0x10000;
- }
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) && (ml->flag & SELECT)) {
+ found = false;
+ }
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
+ changed |= ED_mball_deselect_all_multi(C);
+ }
+ }
- /* When some metaelem was found, then it is necessary to select or deselect it. */
- if (ml_act) {
- if (!extend && !deselect && !toggle) {
- uint objects_len;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
- vc.view_layer, vc.v3d, &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob_iter = objects[ob_index];
-
- if (ob_iter == base->object) {
- continue;
- }
-
- BKE_mball_deselect_all((MetaBall *)ob_iter->data);
- DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data);
- }
- MEM_freeN(objects);
- }
+ if (found) {
+ if (selmask & MBALLSEL_RADIUS) {
+ ml->flag |= MB_SCALE_RAD;
+ }
+ else if (selmask & MBALLSEL_STIFF) {
+ ml->flag &= ~MB_SCALE_RAD;
+ }
- if (extend) {
- ml_act->flag |= SELECT;
- }
- else if (deselect) {
- ml_act->flag &= ~SELECT;
- }
- else if (toggle) {
- if (ml_act->flag & SELECT) {
- ml_act->flag &= ~SELECT;
- }
- else {
- ml_act->flag |= SELECT;
- }
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ ml->flag |= SELECT;
+ break;
+ }
+ case SEL_OP_SUB: {
+ ml->flag &= ~SELECT;
+ break;
+ }
+ case SEL_OP_XOR: {
+ if (ml->flag & SELECT) {
+ ml->flag &= ~SELECT;
}
else {
- /* Deselect all existing metaelems */
- BKE_mball_deselect_all(mb);
-
- /* Select only metaelem clicked on */
- ml_act->flag |= SELECT;
+ ml->flag |= SELECT;
}
+ break;
+ }
+ case SEL_OP_SET: {
+ /* Deselect has already been performed. */
+ ml->flag |= SELECT;
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
+ }
+ }
- mb->lastelem = ml_act;
-
- DEG_id_tag_update(&mb->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ MetaBall *mb = (MetaBall *)base->object->data;
+ mb->lastelem = ml;
- if (vc.view_layer->basact != base) {
- ED_object_base_activate(C, base);
- }
+ DEG_id_tag_update(&mb->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, mb);
- return true;
- }
+ if (view_layer->basact != base) {
+ ED_object_base_activate(C, base);
}
+
+ changed = true;
}
- FOREACH_BASE_IN_EDIT_MODE_END;
- return false;
+ return changed || found;
}
/** \} */
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index 6f8763fa2bb..02feccc211a 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -51,7 +51,7 @@ set(SRC
object_select.c
object_shader_fx.c
object_shapekey.c
- object_transform.c
+ object_transform.cc
object_utils.c
object_vgroup.c
object_volume.c
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 3529574a3a4..efcb47f76ab 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -23,6 +23,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c
index 9b62823ea8a..d0a6a5d44c0 100644
--- a/source/blender/editors/object/object_gpencil_modifier.c
+++ b/source/blender/editors/object/object_gpencil_modifier.c
@@ -403,7 +403,7 @@ void OBJECT_OT_gpencil_modifier_add(wmOperatorType *ot)
/* properties */
prop = RNA_def_enum(ot->srna,
"type",
- rna_enum_object_modifier_type_items,
+ rna_enum_object_greasepencil_modifier_type_items,
eGpencilModifierType_Thick,
"Type",
"");
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 60a49fa6945..490c495dad5 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -28,7 +28,7 @@ enum eObject_Hook_Add_Mode {
/* internal exports only */
-/* object_transform.c */
+/* object_transform.cc */
void OBJECT_OT_location_clear(struct wmOperatorType *ot);
void OBJECT_OT_rotation_clear(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index b0c8646dd04..7fedc2c6265 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -2219,7 +2219,7 @@ static int multires_unsubdivide_exec(bContext *C, wmOperator *op)
int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, 1, true);
if (new_levels == 0) {
- BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild a lower level");
+ BKE_report(op->reports, RPT_ERROR, "No valid subdivisions found to rebuild a lower level");
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.cc
index 9e82abf4d07..24425b5a991 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.cc
@@ -5,8 +5,8 @@
* \ingroup edobj
*/
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
@@ -19,10 +19,12 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "BLI_array.h"
+#include "BLI_array.hh"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_math_vector.hh"
#include "BLI_utildefines.h"
+#include "BLI_vector.hh"
#include "BKE_armature.h"
#include "BKE_context.h"
@@ -64,6 +66,10 @@
#include "object_intern.h"
+using blender::Array;
+using blender::float2;
+using blender::Vector;
+
/* -------------------------------------------------------------------- */
/** \name Clear Transformation Utilities
* \{ */
@@ -283,25 +289,20 @@ static int object_clear_transform_generic_exec(bContext *C,
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- /* May be NULL. */
+ /* May be null. */
View3D *v3d = CTX_wm_view3d(C);
KeyingSet *ks;
const bool clear_delta = RNA_boolean_get(op->ptr, "clear_delta");
- BLI_assert(!ELEM(NULL, clear_func, default_ksName));
+ BLI_assert(!ELEM(nullptr, clear_func, default_ksName));
- Object **objects = NULL;
- uint objects_len = 0;
- {
- BLI_array_declare(objects);
- FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN (view_layer, v3d, ob) {
- BLI_array_append(objects, ob);
- }
- FOREACH_SELECTED_EDITABLE_OBJECT_END;
- objects_len = BLI_array_len(objects);
+ Vector<Object *> objects;
+ FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN (view_layer, v3d, ob) {
+ objects.append(ob);
}
+ FOREACH_SELECTED_EDITABLE_OBJECT_END;
- if (objects == NULL) {
+ if (objects.is_empty()) {
return OPERATOR_CANCELLED;
}
@@ -310,14 +311,14 @@ static int object_clear_transform_generic_exec(bContext *C,
SCE_XFORM_SKIP_CHILDREN);
const bool use_transform_data_origin = (scene->toolsettings->transform_flag &
SCE_XFORM_DATA_ORIGIN);
- struct XFormObjectSkipChild_Container *xcs = NULL;
- struct XFormObjectData_Container *xds = NULL;
+ struct XFormObjectSkipChild_Container *xcs = nullptr;
+ struct XFormObjectData_Container *xds = nullptr;
if (use_transform_skip_children) {
BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
xcs = ED_object_xform_skip_child_container_create();
ED_object_xform_skip_child_container_item_ensure_from_array(
- xcs, view_layer, objects, objects_len);
+ xcs, view_layer, objects.data(), objects.size());
}
if (use_transform_data_origin) {
BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
@@ -327,9 +328,7 @@ static int object_clear_transform_generic_exec(bContext *C,
/* get KeyingSet to use */
ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *ob = objects[ob_index];
-
+ for (Object *ob : objects) {
if (use_transform_data_origin) {
ED_object_data_xform_container_item_ensure(xds, ob);
}
@@ -342,7 +341,6 @@ static int object_clear_transform_generic_exec(bContext *C,
/* tag for updates */
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
}
- MEM_freeN(objects);
if (use_transform_skip_children) {
ED_object_xform_skip_child_container_update_all(xcs, bmain, depsgraph);
@@ -355,7 +353,7 @@ static int object_clear_transform_generic_exec(bContext *C,
}
/* this is needed so children are also updated */
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
return OPERATOR_FINISHED;
}
@@ -488,7 +486,7 @@ static int object_origin_clear_exec(bContext *C, wmOperator *UNUSED(op))
}
CTX_DATA_END;
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
return OPERATOR_FINISHED;
}
@@ -519,12 +517,11 @@ void OBJECT_OT_origin_clear(wmOperatorType *ot)
static void ignore_parent_tx(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
{
Object workob;
- Object *ob_child;
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
/* a change was made, adjust the children to compensate */
- for (ob_child = bmain->objects.first; ob_child; ob_child = ob_child->id.next) {
+ LISTBASE_FOREACH (Object *, ob_child, &bmain->objects) {
if (ob_child->parent == ob) {
Object *ob_child_eval = DEG_get_evaluated_object(depsgraph, ob_child);
BKE_object_apply_mat4(ob_child_eval, ob_child_eval->obmat, true, false);
@@ -549,7 +546,7 @@ static void append_sorted_object_parent_hierarchy(Object *root_object,
Object **sorted_objects,
int *object_index)
{
- if (!ELEM(object->parent, NULL, root_object)) {
+ if (!ELEM(object->parent, nullptr, root_object)) {
append_sorted_object_parent_hierarchy(
root_object, object->parent, sorted_objects, object_index);
}
@@ -560,7 +557,7 @@ static void append_sorted_object_parent_hierarchy(Object *root_object,
}
}
-static Object **sorted_selected_editable_objects(bContext *C, int *r_num_objects)
+static Array<Object *> sorted_selected_editable_objects(bContext *C)
{
Main *bmain = CTX_data_main(C);
@@ -573,23 +570,20 @@ static Object **sorted_selected_editable_objects(bContext *C, int *r_num_objects
}
CTX_DATA_END;
if (num_objects == 0) {
- *r_num_objects = 0;
- return NULL;
+ return {};
}
/* Append all the objects. */
- Object **sorted_objects = MEM_malloc_arrayN(num_objects, sizeof(Object *), "sorted objects");
+ Array<Object *> sorted_objects(num_objects);
int object_index = 0;
CTX_DATA_BEGIN (C, Object *, object, selected_editable_objects) {
if ((object->id.tag & LIB_TAG_DOIT) == 0) {
continue;
}
- append_sorted_object_parent_hierarchy(object, object, sorted_objects, &object_index);
+ append_sorted_object_parent_hierarchy(object, object, sorted_objects.data(), &object_index);
}
CTX_DATA_END;
- *r_num_objects = num_objects;
-
return sorted_objects;
}
@@ -617,11 +611,11 @@ static int apply_objects_internal(bContext *C,
OB_SURF,
OB_FONT,
OB_GPENCIL)) {
- ID *obdata = ob->data;
+ ID *obdata = static_cast<ID *>(ob->data);
if (ID_REAL_USERS(obdata) > 1) {
BKE_reportf(reports,
RPT_ERROR,
- "Cannot apply to a multi user: Object \"%s\", %s \"%s\", aborting",
+ R"(Cannot apply to a multi user: Object "%s", %s "%s", aborting)",
ob->id.name + 2,
BKE_idtype_idcode_to_name(GS(obdata->name)),
obdata->name + 2);
@@ -631,7 +625,7 @@ static int apply_objects_internal(bContext *C,
if (ID_IS_LINKED(obdata)) {
BKE_reportf(reports,
RPT_ERROR,
- "Cannot apply to library data: Object \"%s\", %s \"%s\", aborting",
+ R"(Cannot apply to library data: Object "%s", %s "%s", aborting)",
ob->id.name + 2,
BKE_idtype_idcode_to_name(GS(obdata->name)),
obdata->name + 2);
@@ -640,16 +634,14 @@ static int apply_objects_internal(bContext *C,
}
if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF)) {
- ID *obdata = ob->data;
- Curve *cu;
-
- cu = ob->data;
+ ID *obdata = static_cast<ID *>(ob->data);
+ Curve *cu = static_cast<Curve *>(ob->data);
if (((ob->type == OB_CURVES_LEGACY) && !(cu->flag & CU_3D)) && (apply_rot || apply_loc)) {
BKE_reportf(
reports,
RPT_ERROR,
- "Rotation/Location can't apply to a 2D curve: Object \"%s\", %s \"%s\", aborting",
+ R"(Rotation/Location can't apply to a 2D curve: Object "%s", %s "%s", aborting)",
ob->id.name + 2,
BKE_idtype_idcode_to_name(GS(obdata->name)),
obdata->name + 2);
@@ -658,7 +650,7 @@ static int apply_objects_internal(bContext *C,
if (cu->key) {
BKE_reportf(reports,
RPT_ERROR,
- "Can't apply to a curve with shape-keys: Object \"%s\", %s \"%s\", aborting",
+ R"(Can't apply to a curve with shape-keys: Object "%s", %s "%s", aborting)",
ob->id.name + 2,
BKE_idtype_idcode_to_name(GS(obdata->name)),
obdata->name + 2);
@@ -675,7 +667,7 @@ static int apply_objects_internal(bContext *C,
}
if (ob->type == OB_GPENCIL) {
- bGPdata *gpd = ob->data;
+ bGPdata *gpd = static_cast<bGPdata *>(ob->data);
if (gpd) {
if (gpd->layers.first) {
/* Unsupported configuration */
@@ -684,7 +676,7 @@ static int apply_objects_internal(bContext *C,
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* Parented layers aren't supported as we can't easily re-evaluate
* the scene to sample parent movement */
- if (gpl->parent == NULL) {
+ if (gpl->parent == nullptr) {
has_unparented_layers = true;
break;
}
@@ -706,7 +698,7 @@ static int apply_objects_internal(bContext *C,
BKE_reportf(
reports,
RPT_ERROR,
- "Can't apply to GP data-block with no layers: Object \"%s\", %s \"%s\", aborting",
+ R"(Can't apply to GP data-block with no layers: Object "%s", %s "%s", aborting)",
ob->id.name + 2,
BKE_idtype_idcode_to_name(ID_GD),
gpd->id.name + 2);
@@ -715,7 +707,7 @@ static int apply_objects_internal(bContext *C,
}
if (ob->type == OB_LAMP) {
- Light *la = ob->data;
+ Light *la = static_cast<Light *>(ob->data);
if (la->type == LA_AREA) {
if (apply_rot || apply_loc) {
BKE_reportf(reports,
@@ -736,15 +728,12 @@ static int apply_objects_internal(bContext *C,
changed = false;
/* now execute */
- int num_objects;
- Object **objects = sorted_selected_editable_objects(C, &num_objects);
- if (objects == NULL) {
+ Array<Object *> objects = sorted_selected_editable_objects(C);
+ if (objects.is_empty()) {
return OPERATOR_CANCELLED;
}
- for (int object_index = 0; object_index < num_objects; object_index++) {
- Object *ob = objects[object_index];
-
+ for (Object *ob : objects) {
/* calculate rotation/scale matrix */
if (apply_scale && apply_rot) {
BKE_object_to_mat3(ob, rsmat);
@@ -786,7 +775,7 @@ static int apply_objects_internal(bContext *C,
/* apply to object data */
if (ob->type == OB_MESH) {
- Mesh *me = ob->data;
+ Mesh *me = static_cast<Mesh *>(ob->data);
if (apply_scale) {
multiresModifier_scale_disp(depsgraph, scene, ob);
@@ -799,25 +788,25 @@ static int apply_objects_internal(bContext *C,
BKE_mesh_normals_tag_dirty(me);
}
else if (ob->type == OB_ARMATURE) {
- bArmature *arm = ob->data;
+ bArmature *arm = static_cast<bArmature *>(ob->data);
BKE_armature_transform(arm, mat, do_props);
}
else if (ob->type == OB_LATTICE) {
- Lattice *lt = ob->data;
+ Lattice *lt = static_cast<Lattice *>(ob->data);
BKE_lattice_transform(lt, mat, true);
}
else if (ob->type == OB_MBALL) {
- MetaBall *mb = ob->data;
+ MetaBall *mb = static_cast<MetaBall *>(ob->data);
BKE_mball_transform(mb, mat, do_props);
}
else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF)) {
- Curve *cu = ob->data;
+ Curve *cu = static_cast<Curve *>(ob->data);
scale = mat3_to_scale(rsmat);
BKE_curve_transform_ex(cu, mat, true, do_props, scale);
}
else if (ob->type == OB_FONT) {
- Curve *cu = ob->data;
+ Curve *cu = static_cast<Curve *>(ob->data);
scale = mat3_to_scale(rsmat);
@@ -834,7 +823,7 @@ static int apply_objects_internal(bContext *C,
}
}
else if (ob->type == OB_GPENCIL) {
- bGPdata *gpd = ob->data;
+ bGPdata *gpd = static_cast<bGPdata *>(ob->data);
BKE_gpencil_transform(gpd, mat);
}
else if (ob->type == OB_CAMERA) {
@@ -870,7 +859,7 @@ static int apply_objects_internal(bContext *C,
}
}
else if (ob->type == OB_LAMP) {
- Light *la = ob->data;
+ Light *la = static_cast<Light *>(ob->data);
if (la->type != LA_AREA) {
continue;
}
@@ -911,7 +900,8 @@ static int apply_objects_internal(bContext *C,
BKE_object_where_is_calc(depsgraph, scene, ob_eval);
if (ob->type == OB_ARMATURE) {
/* needed for bone parents */
- BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
+ BKE_armature_copy_bone_transforms(static_cast<bArmature *>(ob_eval->data),
+ static_cast<bArmature *>(ob->data));
BKE_pose_where_is(depsgraph, scene, ob_eval);
}
@@ -922,14 +912,12 @@ static int apply_objects_internal(bContext *C,
changed = true;
}
- MEM_freeN(objects);
-
if (!changed) {
BKE_report(reports, RPT_WARNING, "Objects have no data to transform");
return OPERATOR_CANCELLED;
}
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
return OPERATOR_FINISHED;
}
@@ -956,7 +944,7 @@ static int visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
return OPERATOR_FINISHED;
}
@@ -1034,7 +1022,6 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
Object *obact = CTX_data_active_object(C);
Object *obedit = CTX_data_edit_object(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Object *tob;
float cent[3], cent_neg[3], centn[3];
const float *cursor = scene->cursor.location;
int centermode = RNA_enum_get(op->ptr, "type");
@@ -1068,7 +1055,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
if (obedit) {
if (obedit->type == OB_MESH) {
- Mesh *me = obedit->data;
+ Mesh *me = static_cast<Mesh *>(obedit->data);
BMEditMesh *em = me->edit_mesh;
BMVert *eve;
BMIter iter;
@@ -1107,25 +1094,24 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
}
- int num_objects;
- Object **objects = sorted_selected_editable_objects(C, &num_objects);
- if (objects == NULL) {
+ Array<Object *> objects = sorted_selected_editable_objects(C);
+ if (objects.is_empty()) {
return OPERATOR_CANCELLED;
}
/* reset flags */
- for (int object_index = 0; object_index < num_objects; object_index++) {
+ for (int object_index = 0; object_index < objects.size(); object_index++) {
Object *ob = objects[object_index];
ob->flag &= ~OB_DONE;
/* move active first */
if (ob == obact) {
- memmove(&objects[1], objects, object_index * sizeof(Object *));
+ memmove(&objects[1], objects.data(), object_index * sizeof(Object *));
objects[0] = ob;
}
}
- for (tob = bmain->objects.first; tob; tob = tob->id.next) {
+ LISTBASE_FOREACH (Object *, tob, &bmain->objects) {
if (tob->data) {
((ID *)tob->data)->tag &= ~LIB_TAG_DOIT;
}
@@ -1134,8 +1120,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
}
- for (int object_index = 0; object_index < num_objects; object_index++) {
- Object *ob = objects[object_index];
+ for (Object *ob : objects) {
if (ob->flag & OB_DONE) {
continue;
}
@@ -1149,8 +1134,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
mul_m4_v3(ob->imat, cent);
}
- if (ob->data == NULL) {
- /* special support for dupligroups */
+ if (ob->data == nullptr) {
+ /* Special support for instanced collections. */
if ((ob->transflag & OB_DUPLICOLLECTION) && ob->instance_collection &&
(ob->instance_collection->id.tag & LIB_TAG_DOIT) == 0) {
if (ID_IS_LINKED(ob->instance_collection)) {
@@ -1182,8 +1167,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
tot_lib_error++;
}
else if (ob->type == OB_MESH) {
- if (obedit == NULL) {
- Mesh *me = ob->data;
+ if (obedit == nullptr) {
+ Mesh *me = static_cast<Mesh *>(ob->data);
if (centermode == ORIGIN_TO_CURSOR) {
/* done */
@@ -1202,7 +1187,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
negate_v3_v3(cent_neg, cent);
- BKE_mesh_translate(me, cent_neg, 1);
+ BKE_mesh_translate(me, cent_neg, true);
tot_change++;
me->id.tag |= LIB_TAG_DOIT;
@@ -1210,7 +1195,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
}
else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF)) {
- Curve *cu = ob->data;
+ Curve *cu = static_cast<Curve *>(ob->data);
if (centermode == ORIGIN_TO_CURSOR) {
/* done */
@@ -1228,7 +1213,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
negate_v3_v3(cent_neg, cent);
- BKE_curve_translate(cu, cent_neg, 1);
+ BKE_curve_translate(cu, cent_neg, true);
tot_change++;
cu->id.tag |= LIB_TAG_DOIT;
@@ -1244,9 +1229,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
else if (ob->type == OB_FONT) {
/* Get from bounding-box. */
- Curve *cu = ob->data;
+ Curve *cu = static_cast<Curve *>(ob->data);
- if (ob->runtime.bb == NULL && (centermode != ORIGIN_TO_CURSOR)) {
+ if (ob->runtime.bb == nullptr && (centermode != ORIGIN_TO_CURSOR)) {
/* Do nothing. */
}
else {
@@ -1270,7 +1255,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
}
else if (ob->type == OB_ARMATURE) {
- bArmature *arm = ob->data;
+ bArmature *arm = static_cast<bArmature *>(ob->data);
if (ID_REAL_USERS(arm) > 1) {
#if 0
@@ -1291,7 +1276,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
BKE_object_transform_copy(ob_eval, ob);
- BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
+ BKE_armature_copy_bone_transforms(static_cast<bArmature *>(ob_eval->data),
+ static_cast<bArmature *>(ob->data));
BKE_object_where_is_calc(depsgraph, scene, ob_eval);
BKE_pose_where_is(depsgraph, scene, ob_eval); /* needed for bone parents */
@@ -1303,7 +1289,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
}
else if (ob->type == OB_MBALL) {
- MetaBall *mb = ob->data;
+ MetaBall *mb = static_cast<MetaBall *>(ob->data);
if (centermode == ORIGIN_TO_CURSOR) {
/* done */
@@ -1330,7 +1316,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
}
else if (ob->type == OB_LATTICE) {
- Lattice *lt = ob->data;
+ Lattice *lt = static_cast<Lattice *>(ob->data);
if (centermode == ORIGIN_TO_CURSOR) {
/* done */
@@ -1343,14 +1329,14 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
negate_v3_v3(cent_neg, cent);
- BKE_lattice_translate(lt, cent_neg, 1);
+ BKE_lattice_translate(lt, cent_neg, true);
tot_change++;
lt->id.tag |= LIB_TAG_DOIT;
do_inverse_offset = true;
}
else if (ob->type == OB_GPENCIL) {
- bGPdata *gpd = ob->data;
+ bGPdata *gpd = static_cast<bGPdata *>(ob->data);
float gpcenter[3];
if (gpd) {
if (centermode == ORIGIN_TO_GEOMETRY) {
@@ -1394,7 +1380,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
/* Apply transform to edit-curve. */
- if (gps->editcurve != NULL) {
+ if (gps->editcurve != nullptr) {
for (i = 0; i < gps->editcurve->tot_curve_points; i++) {
BezTriple *bezt = &gps->editcurve->curve_points[i].bezt;
for (int j = 0; j < 3; j++) {
@@ -1444,7 +1430,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
BKE_object_where_is_calc(depsgraph, scene, ob_eval);
if (ob->type == OB_ARMATURE) {
/* needed for bone parents */
- BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
+ BKE_armature_copy_bone_transforms(static_cast<bArmature *>(ob_eval->data),
+ static_cast<bArmature *>(ob->data));
BKE_pose_where_is(depsgraph, scene, ob_eval);
}
@@ -1455,9 +1442,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
//{
/* use existing context looper */
- for (int other_object_index = 0; other_object_index < num_objects; other_object_index++) {
- Object *ob_other = objects[other_object_index];
-
+ for (Object *ob_other : objects) {
if ((ob_other->flag & OB_DONE) == 0 &&
((ob->data && (ob->data == ob_other->data)) ||
(ob->instance_collection == ob_other->instance_collection &&
@@ -1473,7 +1458,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
BKE_object_where_is_calc(depsgraph, scene, ob_other_eval);
if (ob_other->type == OB_ARMATURE) {
/* needed for bone parents */
- BKE_armature_copy_bone_transforms(ob_eval->data, ob->data);
+ BKE_armature_copy_bone_transforms(static_cast<bArmature *>(ob_eval->data),
+ static_cast<bArmature *>(ob->data));
BKE_pose_where_is(depsgraph, scene, ob_other_eval);
}
ignore_parent_tx(bmain, depsgraph, scene, ob_other);
@@ -1482,9 +1468,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
// CTX_DATA_END;
}
}
- MEM_freeN(objects);
- for (tob = bmain->objects.first; tob; tob = tob->id.next) {
+ LISTBASE_FOREACH (Object *, tob, &bmain->objects) {
if (tob->data && (((ID *)tob->data)->tag & LIB_TAG_DOIT)) {
BKE_object_batch_cache_dirty_tag(tob);
DEG_id_tag_update(&tob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
@@ -1497,7 +1482,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
if (tot_change) {
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr);
}
/* Warn if any errors occurred */
@@ -1550,13 +1535,13 @@ void OBJECT_OT_origin_set(wmOperatorType *ot)
"Origin to Center of Mass (Volume)",
"Calculate the center of mass from the volume (must be manifold geometry with consistent "
"normals)"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
static const EnumPropertyItem prop_set_bounds_types[] = {
{V3D_AROUND_CENTER_MEDIAN, "MEDIAN", 0, "Median Center", ""},
{V3D_AROUND_CENTER_BOUNDS, "BOUNDS", 0, "Bounds Center", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -1622,26 +1607,23 @@ struct XFormAxisData {
bool is_normal_valid;
} prev;
- struct XFormAxisItem *object_data;
- uint object_data_len;
+ Vector<XFormAxisItem> object_data;
bool is_translate;
int init_event;
};
#ifdef USE_FAKE_DEPTH_INIT
-static void object_transform_axis_target_calc_depth_init(struct XFormAxisData *xfd,
- const int mval[2])
+static void object_transform_axis_target_calc_depth_init(XFormAxisData *xfd, const int mval[2])
{
- struct XFormAxisItem *item = xfd->object_data;
float view_co_a[3], view_co_b[3];
- const float mval_fl[2] = {UNPACK2(mval)};
+ const float2 mval_fl = {static_cast<float>(mval[0]), static_cast<float>(mval[1])};
ED_view3d_win_to_ray(xfd->vc.region, mval_fl, view_co_a, view_co_b);
add_v3_v3(view_co_b, view_co_a);
float center[3] = {0.0f};
int center_tot = 0;
- for (int i = 0; i < xfd->object_data_len; i++, item++) {
- const Object *ob = item->ob;
+ for (XFormAxisItem &item : xfd->object_data) {
+ const Object *ob = item.ob;
const float *ob_co_a = ob->obmat[3];
float ob_co_b[3];
add_v3_v3v3(ob_co_b, ob->obmat[3], ob->obmat[2]);
@@ -1664,7 +1646,7 @@ static void object_transform_axis_target_calc_depth_init(struct XFormAxisData *x
static bool object_is_target_compat(const Object *ob)
{
if (ob->type == OB_LAMP) {
- const Light *la = ob->data;
+ const Light *la = static_cast<Light *>(ob->data);
if (ELEM(la->type, LA_SUN, LA_SPOT, LA_AREA)) {
return true;
}
@@ -1680,8 +1662,7 @@ static bool object_is_target_compat(const Object *ob)
static void object_transform_axis_target_free_data(wmOperator *op)
{
- struct XFormAxisData *xfd = op->customdata;
- struct XFormAxisItem *item = xfd->object_data;
+ XFormAxisData *xfd = static_cast<XFormAxisData *>(op->customdata);
#ifdef USE_RENDER_OVERRIDE
if (xfd->depths) {
@@ -1689,12 +1670,11 @@ static void object_transform_axis_target_free_data(wmOperator *op)
}
#endif
- for (int i = 0; i < xfd->object_data_len; i++, item++) {
- MEM_freeN(item->obtfm);
+ for (XFormAxisItem &item : xfd->object_data) {
+ MEM_freeN(item.obtfm);
}
- MEM_freeN(xfd->object_data);
- MEM_freeN(xfd);
- op->customdata = NULL;
+ MEM_delete(xfd);
+ op->customdata = nullptr;
}
/* We may want to expose as alternative to: BKE_object_apply_rotation */
@@ -1755,12 +1735,11 @@ static bool object_orient_to_location(Object *ob,
static void object_transform_axis_target_cancel(bContext *C, wmOperator *op)
{
- struct XFormAxisData *xfd = op->customdata;
- struct XFormAxisItem *item = xfd->object_data;
- for (int i = 0; i < xfd->object_data_len; i++, item++) {
- BKE_object_tfm_restore(item->ob, item->obtfm);
- DEG_id_tag_update(&item->ob->id, ID_RECALC_TRANSFORM);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
+ XFormAxisData *xfd = static_cast<XFormAxisData *>(op->customdata);
+ for (XFormAxisItem &item : xfd->object_data) {
+ BKE_object_tfm_restore(item.ob, item.obtfm);
+ DEG_id_tag_update(&item.ob->id, ID_RECALC_TRANSFORM);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item.ob);
}
object_transform_axis_target_free_data(op);
@@ -1772,7 +1751,7 @@ static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, cons
ViewContext vc;
ED_view3d_viewcontext_init(C, &vc, depsgraph);
- if (vc.obact == NULL || !object_is_target_compat(vc.obact)) {
+ if (vc.obact == nullptr || !object_is_target_compat(vc.obact)) {
/* Falls back to texture space transform. */
return OPERATOR_PASS_THROUGH;
}
@@ -1782,22 +1761,23 @@ static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, cons
vc.v3d->flag2 |= V3D_HIDE_OVERLAYS;
#endif
- ViewDepths *depths = NULL;
- ED_view3d_depth_override(vc.depsgraph, vc.region, vc.v3d, NULL, V3D_DEPTH_NO_GPENCIL, &depths);
+ ViewDepths *depths = nullptr;
+ ED_view3d_depth_override(
+ vc.depsgraph, vc.region, vc.v3d, nullptr, V3D_DEPTH_NO_GPENCIL, &depths);
#ifdef USE_RENDER_OVERRIDE
vc.v3d->flag2 = flag2_prev;
#endif
- if (depths == NULL) {
+ if (depths == nullptr) {
BKE_report(op->reports, RPT_WARNING, "Unable to access depth buffer, using view plane");
return OPERATOR_CANCELLED;
}
ED_region_tag_redraw(vc.region);
- struct XFormAxisData *xfd;
- xfd = op->customdata = MEM_callocN(sizeof(struct XFormAxisData), __func__);
+ XFormAxisData *xfd = MEM_new<XFormAxisData>(__func__);
+ op->customdata = xfd;
/* Don't change this at runtime. */
xfd->vc = vc;
@@ -1812,41 +1792,25 @@ static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, cons
xfd->init_event = WM_userdef_event_type_from_keymap_type(event->type);
- {
- struct XFormAxisItem *object_data = NULL;
- BLI_array_declare(object_data);
-
- struct XFormAxisItem *item = BLI_array_append_ret(object_data);
- item->ob = xfd->vc.obact;
-
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
- if ((ob != xfd->vc.obact) && object_is_target_compat(ob)) {
- item = BLI_array_append_ret(object_data);
- item->ob = ob;
- }
- }
- CTX_DATA_END;
+ xfd->object_data.append({});
+ xfd->object_data.last().ob = xfd->vc.obact;
- xfd->object_data = object_data;
- xfd->object_data_len = BLI_array_len(object_data);
-
- if (xfd->object_data_len != BLI_array_len(object_data)) {
- xfd->object_data = MEM_reallocN(xfd->object_data,
- xfd->object_data_len * sizeof(*xfd->object_data));
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
+ if ((ob != xfd->vc.obact) && object_is_target_compat(ob)) {
+ xfd->object_data.append({});
+ xfd->object_data.last().ob = ob;
}
}
+ CTX_DATA_END;
- {
- struct XFormAxisItem *item = xfd->object_data;
- for (int i = 0; i < xfd->object_data_len; i++, item++) {
- item->obtfm = BKE_object_tfm_backup(item->ob);
- BKE_object_rot_to_mat3(item->ob, item->rot_mat, true);
+ for (XFormAxisItem &item : xfd->object_data) {
+ item.obtfm = BKE_object_tfm_backup(item.ob);
+ BKE_object_rot_to_mat3(item.ob, item.rot_mat, true);
- /* Detect negative scale matrix. */
- float full_mat3[3][3];
- BKE_object_to_mat3(item->ob, full_mat3);
- item->is_z_flip = dot_v3v3(item->rot_mat[2], full_mat3[2]) < 0.0f;
- }
+ /* Detect negative scale matrix. */
+ float full_mat3[3][3];
+ BKE_object_to_mat3(item.ob, full_mat3);
+ item.is_z_flip = dot_v3v3(item.rot_mat[2], full_mat3[2]) < 0.0f;
}
WM_event_add_modal_handler(C, op);
@@ -1856,7 +1820,7 @@ static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, cons
static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- struct XFormAxisData *xfd = op->customdata;
+ XFormAxisData *xfd = static_cast<XFormAxisData *>(op->customdata);
ARegion *region = xfd->vc.region;
view3d_operator_needs_opengl(C);
@@ -1922,36 +1886,35 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
{
#ifdef USE_RELATIVE_ROTATION
- if (is_translate_init && xfd->object_data_len > 1) {
+ if (is_translate_init && xfd->object_data.size() > 1) {
float xform_rot_offset_inv_first[3][3];
- struct XFormAxisItem *item = xfd->object_data;
- for (int i = 0; i < xfd->object_data_len; i++, item++) {
- copy_m3_m4(item->xform_rot_offset, item->ob->obmat);
- normalize_m3(item->xform_rot_offset);
+ for (const int i : xfd->object_data.index_range()) {
+ XFormAxisItem &item = xfd->object_data[i];
+ copy_m3_m4(item.xform_rot_offset, item.ob->obmat);
+ normalize_m3(item.xform_rot_offset);
if (i == 0) {
invert_m3_m3(xform_rot_offset_inv_first, xfd->object_data[0].xform_rot_offset);
}
else {
- mul_m3_m3m3(item->xform_rot_offset,
- item->xform_rot_offset,
- xform_rot_offset_inv_first);
+ mul_m3_m3m3(
+ item.xform_rot_offset, item.xform_rot_offset, xform_rot_offset_inv_first);
}
}
}
#endif
- struct XFormAxisItem *item = xfd->object_data;
- for (int i = 0; i < xfd->object_data_len; i++, item++) {
+ for (const int i : xfd->object_data.index_range()) {
+ XFormAxisItem &item = xfd->object_data[i];
if (is_translate_init) {
float ob_axis[3];
- item->xform_dist = len_v3v3(item->ob->obmat[3], location_world);
- normalize_v3_v3(ob_axis, item->ob->obmat[2]);
+ item.xform_dist = len_v3v3(item.ob->obmat[3], location_world);
+ normalize_v3_v3(ob_axis, item.ob->obmat[2]);
/* Scale to avoid adding distance when moving between surfaces. */
if (normal_found) {
float scale = fabsf(dot_v3v3(ob_axis, normal));
- item->xform_dist *= scale;
+ item.xform_dist *= scale;
}
}
@@ -1961,13 +1924,13 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
copy_v3_v3(target_normal, normal);
}
else {
- normalize_v3_v3(target_normal, item->ob->obmat[2]);
+ normalize_v3_v3(target_normal, item.ob->obmat[2]);
}
#ifdef USE_RELATIVE_ROTATION
if (normal_found) {
if (i != 0) {
- mul_m3_v3(item->xform_rot_offset, target_normal);
+ mul_m3_v3(item.xform_rot_offset, target_normal);
}
}
#endif
@@ -1975,17 +1938,17 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
float loc[3];
copy_v3_v3(loc, location_world);
- madd_v3_v3fl(loc, target_normal, item->xform_dist);
- object_apply_location(item->ob, loc);
+ madd_v3_v3fl(loc, target_normal, item.xform_dist);
+ object_apply_location(item.ob, loc);
/* so orient behaves as expected */
- copy_v3_v3(item->ob->obmat[3], loc);
+ copy_v3_v3(item.ob->obmat[3], loc);
}
object_orient_to_location(
- item->ob, item->rot_mat, item->rot_mat[2], location_world, item->is_z_flip);
+ item.ob, item.rot_mat, item.rot_mat[2], location_world, item.is_z_flip);
- DEG_id_tag_update(&item->ob->id, ID_RECALC_TRANSFORM);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
+ DEG_id_tag_update(&item.ob->id, ID_RECALC_TRANSFORM);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item.ob);
}
if (normal_found) {
copy_v3_v3(xfd->prev.normal, normal);
@@ -1994,15 +1957,11 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
}
}
else {
- struct XFormAxisItem *item = xfd->object_data;
- for (int i = 0; i < xfd->object_data_len; i++, item++) {
- if (object_orient_to_location(item->ob,
- item->rot_mat,
- item->rot_mat[2],
- location_world,
- item->is_z_flip)) {
- DEG_id_tag_update(&item->ob->id, ID_RECALC_TRANSFORM);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
+ for (XFormAxisItem &item : xfd->object_data) {
+ if (object_orient_to_location(
+ item.ob, item.rot_mat, item.rot_mat[2], location_world, item.is_z_flip)) {
+ DEG_id_tag_update(&item.ob->id, ID_RECALC_TRANSFORM);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item.ob);
}
}
xfd->prev.is_normal_valid = false;
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 5bc062eb177..e8ceb97ed7a 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -399,27 +399,27 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job)
* Save output images
*/
{
- char filename[FILE_MAX];
+ char filepath[FILE_MAX];
/* primary output layer */
if (surface->flags & MOD_DPAINT_OUT1) {
/* set filepath */
BLI_join_dirfile(
- filename, sizeof(filename), surface->image_output_path, surface->output_name);
- BLI_path_frame(filename, frame, 4);
+ filepath, sizeof(filepath), surface->image_output_path, surface->output_name);
+ BLI_path_frame(filepath, frame, 4);
/* save image */
- dynamicPaint_outputSurfaceImage(surface, filename, 0);
+ dynamicPaint_outputSurfaceImage(surface, filepath, 0);
}
/* secondary output */
if (surface->flags & MOD_DPAINT_OUT2 && surface->type == MOD_DPAINT_SURFACE_T_PAINT) {
/* set filepath */
BLI_join_dirfile(
- filename, sizeof(filename), surface->image_output_path, surface->output_name2);
- BLI_path_frame(filename, frame, 4);
+ filepath, sizeof(filepath), surface->image_output_path, surface->output_name2);
+ BLI_path_frame(filepath, frame, 4);
/* save image */
- dynamicPaint_outputSurfaceImage(surface, filename, 1);
+ dynamicPaint_outputSurfaceImage(surface, filepath, 1);
}
}
}
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index fc815ebe682..4a639e227f7 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -487,6 +487,8 @@ typedef struct PEData {
int select_action;
int select_toggle_action;
bool is_changed;
+
+ void *user_data;
} PEData;
static void PE_set_data(bContext *C, PEData *data)
@@ -1721,46 +1723,6 @@ static void select_keys(PEData *data,
point->flag |= PEP_EDIT_RECALC;
}
-static void extend_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
-{
- PTCacheEdit *edit = data->edit;
- PTCacheEditPoint *point = edit->points + point_index;
- PTCacheEditKey *key = point->keys + key_index;
-
- if ((key->flag & PEK_SELECT) == 0) {
- key->flag |= PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- data->is_changed = true;
- }
-}
-
-static void deselect_key_select(PEData *data,
- int point_index,
- int key_index,
- bool UNUSED(is_inside))
-{
- PTCacheEdit *edit = data->edit;
- PTCacheEditPoint *point = edit->points + point_index;
- PTCacheEditKey *key = point->keys + key_index;
-
- if ((key->flag & PEK_SELECT) != 0) {
- key->flag &= ~PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- data->is_changed = true;
- }
-}
-
-static void toggle_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
-{
- PTCacheEdit *edit = data->edit;
- PTCacheEditPoint *point = edit->points + point_index;
- PTCacheEditKey *key = point->keys + key_index;
-
- key->flag ^= PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- data->is_changed = true;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1862,13 +1824,50 @@ void PARTICLE_OT_select_all(wmOperatorType *ot)
/** \name Pick Select Operator
* \{ */
-bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+struct NearestParticleData {
+ PTCacheEditPoint *point;
+ PTCacheEditKey *key;
+};
+
+static void nearest_key_fn(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
+{
+ PTCacheEdit *edit = data->edit;
+ PTCacheEditPoint *point = edit->points + point_index;
+ PTCacheEditKey *key = point->keys + key_index;
+
+ struct NearestParticleData *user_data = data->user_data;
+ user_data->point = point;
+ user_data->key = key;
+ data->is_changed = true;
+}
+
+static bool pe_nearest_point_and_key(bContext *C,
+ const int mval[2],
+ PTCacheEditPoint **r_point,
+ PTCacheEditKey **r_key)
+{
+ struct NearestParticleData user_data = {NULL};
+
+ PEData data;
+ PE_set_view3d_data(C, &data);
+ data.mval = mval;
+ data.rad = ED_view3d_select_dist_px();
+
+ data.user_data = &user_data;
+ for_mouse_hit_keys(&data, nearest_key_fn, PSEL_NEAREST);
+ bool found = data.is_changed;
+ PE_data_free(&data);
+
+ *r_point = user_data.point;
+ *r_key = user_data.key;
+ return found;
+}
+
+bool PE_mouse_particles(bContext *C, const int mval[2], const struct SelectPick_Params *params)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- POINT_P;
- KEY_K;
PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
@@ -1876,39 +1875,67 @@ bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool desele
return false;
}
- if (!extend && !deselect && !toggle) {
- LOOP_VISIBLE_POINTS {
- LOOP_SELECTED_KEYS {
- key->flag &= ~PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- }
- }
- }
+ PTCacheEditPoint *point;
+ PTCacheEditKey *key;
- PEData data;
- PE_set_view3d_data(C, &data);
- data.mval = mval;
- data.rad = ED_view3d_select_dist_px();
+ bool changed = false;
+ bool found = pe_nearest_point_and_key(C, mval, &point, &key);
- /* 1 = nearest only */
- if (extend) {
- for_mouse_hit_keys(&data, extend_key_select, PSEL_NEAREST);
- }
- else if (deselect) {
- for_mouse_hit_keys(&data, deselect_key_select, PSEL_NEAREST);
- }
- else {
- for_mouse_hit_keys(&data, toggle_key_select, PSEL_NEAREST);
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) && (key->flag & PEK_SELECT)) {
+ found = false;
+ }
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
+ changed |= PE_deselect_all_visible_ex(edit);
+ }
}
- if (data.is_changed) {
- PE_update_selection(data.depsgraph, scene, ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
+ if (found) {
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ if ((key->flag & PEK_SELECT) == 0) {
+ key->flag |= PEK_SELECT;
+ point->flag |= PEP_EDIT_RECALC;
+ changed = true;
+ }
+ break;
+ }
+ case SEL_OP_SUB: {
+ if ((key->flag & PEK_SELECT) != 0) {
+ key->flag &= ~PEK_SELECT;
+ point->flag |= PEP_EDIT_RECALC;
+ changed = true;
+ }
+ break;
+ }
+ case SEL_OP_XOR: {
+ key->flag ^= PEK_SELECT;
+ point->flag |= PEP_EDIT_RECALC;
+ changed = true;
+ break;
+ }
+ case SEL_OP_SET: {
+ if ((key->flag & PEK_SELECT) == 0) {
+ key->flag |= PEK_SELECT;
+ point->flag |= PEP_EDIT_RECALC;
+ changed = true;
+ }
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
+ }
+ }
}
- PE_data_free(&data);
+ if (changed) {
+ PE_update_selection(depsgraph, scene, ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
+ }
- return true;
+ return changed || found;
}
/** \} */
diff --git a/source/blender/editors/render/render_internal.cc b/source/blender/editors/render/render_internal.cc
index 33b68dfb47b..e5d2a765ca1 100644
--- a/source/blender/editors/render/render_internal.cc
+++ b/source/blender/editors/render/render_internal.cc
@@ -31,6 +31,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -101,7 +102,7 @@ struct RenderJob {
/* called inside thread! */
static bool image_buffer_calc_tile_rect(const RenderResult *rr,
const ImBuf *ibuf,
- volatile rcti *renrect,
+ rcti *renrect,
rcti *r_ibuf_rect,
int *r_offset_x,
int *r_offset_y)
@@ -355,7 +356,14 @@ static int screen_render_exec(bContext *C, wmOperator *op)
scene->r.frame_step);
}
else {
- RE_RenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still);
+ RE_RenderFrame(re,
+ mainp,
+ scene,
+ single_layer,
+ camera_override,
+ scene->r.cfra,
+ scene->r.subframe,
+ is_write_still);
}
RE_SetReports(re, nullptr);
@@ -549,7 +557,7 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
}
}
-static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
+static void image_rect_update(void *rjv, RenderResult *rr, rcti *renrect)
{
RenderJob *rj = static_cast<RenderJob *>(rjv);
Image *ima = rj->image;
@@ -655,6 +663,7 @@ static void render_startjob(void *rjv, short *stop, short *do_update, float *pro
rj->single_layer,
rj->camera_override,
rj->scene->r.cfra,
+ rj->scene->r.subframe,
rj->write_still);
}
diff --git a/source/blender/editors/render/render_opengl.cc b/source/blender/editors/render/render_opengl.cc
index be66e87f2e5..fbdc1086874 100644
--- a/source/blender/editors/render/render_opengl.cc
+++ b/source/blender/editors/render/render_opengl.cc
@@ -34,6 +34,8 @@
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
+#include "BKE_image_save.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -312,13 +314,13 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
imb_freerectfloatImBuf(out);
}
BLI_assert((oglrender->sizex == ibuf->x) && (oglrender->sizey == ibuf->y));
- RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
+ RE_render_result_rect_from_ibuf(rr, out, oglrender->view_id);
IMB_freeImBuf(out);
}
else if (gpd) {
/* If there are no strips, Grease Pencil still needs a buffer to draw on */
ImBuf *out = IMB_allocImBuf(oglrender->sizex, oglrender->sizey, 32, IB_rect);
- RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id);
+ RE_render_result_rect_from_ibuf(rr, out, oglrender->view_id);
IMB_freeImBuf(out);
}
@@ -414,7 +416,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
BKE_image_stamp_buf(scene, camera, nullptr, rect, rectf, rr->rectx, rr->recty, 4);
}
- RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id);
+ RE_render_result_rect_from_ibuf(rr, ibuf_result, oglrender->view_id);
IMB_freeImBuf(ibuf_result);
}
}
@@ -439,7 +441,7 @@ static void screen_opengl_render_write(OGLRender *oglrender)
/* write images as individual images or stereo */
BKE_render_result_stamp_info(scene, scene->camera, rr, false);
- ok = RE_WriteRenderViewsImage(oglrender->reports, rr, scene, false, name);
+ ok = BKE_image_render_write(oglrender->reports, rr, scene, false, name);
RE_ReleaseResultImage(oglrender->re);
@@ -1070,7 +1072,7 @@ static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
nullptr);
BKE_render_result_stamp_info(scene, scene->camera, rr, false);
- ok = RE_WriteRenderViewsImage(nullptr, rr, scene, true, name);
+ ok = BKE_image_render_write(nullptr, rr, scene, true, name);
if (!ok) {
BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", name);
}
diff --git a/source/blender/editors/render/render_preview.cc b/source/blender/editors/render/render_preview.cc
index cfb88cd7868..ef0f0b6225c 100644
--- a/source/blender/editors/render/render_preview.cc
+++ b/source/blender/editors/render/render_preview.cc
@@ -459,11 +459,11 @@ static Scene *preview_prepare_scene(
if (sce) {
ViewLayer *view_layer = static_cast<ViewLayer *>(sce->view_layers.first);
- /* Only enable the combined renderpass */
+ /* Only enable the combined render-pass. */
view_layer->passflag = SCE_PASS_COMBINED;
view_layer->eevee.render_passes = 0;
- /* this flag tells render to not execute depsgraph or ipos etc */
+ /* This flag tells render to not execute depsgraph or F-Curves etc. */
sce->r.scemode |= R_BUTS_PREVIEW;
BLI_strncpy(sce->r.engine, scene->r.engine, sizeof(sce->r.engine));
@@ -987,9 +987,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
* \{ */
/* inside thread, called by renderer, sets job update value */
-static void shader_preview_update(void *spv,
- RenderResult *UNUSED(rr),
- volatile struct rcti *UNUSED(rect))
+static void shader_preview_update(void *spv, RenderResult *UNUSED(rr), struct rcti *UNUSED(rect))
{
ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
@@ -1681,19 +1679,19 @@ class PreviewLoadJob {
PreviewLoadJob();
~PreviewLoadJob();
- static PreviewLoadJob &ensure_job(wmWindowManager *, wmWindow *);
- static void load_jobless(PreviewImage *, eIconSizes);
+ static PreviewLoadJob &ensure_job(wmWindowManager *wm, wmWindow *win);
+ static void load_jobless(PreviewImage *preview, eIconSizes icon_size);
- void push_load_request(PreviewImage *, eIconSizes);
+ void push_load_request(PreviewImage *preview, eIconSizes icon_size);
private:
- static void run_fn(void *, short *, short *, float *);
- static void update_fn(void *);
- static void end_fn(void *);
- static void free_fn(void *);
+ static void run_fn(void *customdata, short *stop, short *do_update, float *progress);
+ static void update_fn(void *customdata);
+ static void end_fn(void *customdata);
+ static void free_fn(void *customdata);
/** Mark a single requested preview as being done, remove the request. */
- static void finish_request(RequestedPreview &);
+ static void finish_request(RequestedPreview &request);
};
PreviewLoadJob::PreviewLoadJob() : todo_queue_(BLI_thread_queue_init())
diff --git a/source/blender/editors/scene/CMakeLists.txt b/source/blender/editors/scene/CMakeLists.txt
index 7f687212066..12043ac2957 100644
--- a/source/blender/editors/scene/CMakeLists.txt
+++ b/source/blender/editors/scene/CMakeLists.txt
@@ -8,8 +8,8 @@ set(INC
../../depsgraph
../../makesdna
../../makesrna
- ../../windowmanager
../../sequencer
+ ../../windowmanager
)
set(INC_SYS
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index ff77f9910fb..5464d0a347d 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -24,6 +24,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_screen.h"
@@ -71,7 +72,7 @@ static int screenshot_data_create(bContext *C, wmOperator *op, ScrArea *area)
scd->crop = area->totrct;
}
- BKE_imformat_defaults(&scd->im_format);
+ BKE_image_format_init(&scd->im_format, false);
op->customdata = scd;
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index ccbdb3c4145..c422c8c2033 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -13,8 +13,8 @@ set(INC
../../gpu
../../imbuf
../../makesdna
- ../../nodes
../../makesrna
+ ../../nodes
../../render
../../windowmanager
../../../../intern/atomic
@@ -27,15 +27,20 @@ set(INC
)
set(SRC
+ curves_sculpt_3d_brush.cc
+ curves_sculpt_add.cc
+ curves_sculpt_comb.cc
+ curves_sculpt_delete.cc
curves_sculpt_ops.cc
+ curves_sculpt_snake_hook.cc
paint_cursor.c
paint_curve.c
paint_curve_undo.c
paint_hide.c
paint_image.cc
- paint_image_ops_paint.cc
paint_image_2d.c
paint_image_2d_curve_mask.cc
+ paint_image_ops_paint.cc
paint_image_proj.c
paint_mask.c
paint_ops.c
@@ -72,6 +77,7 @@ set(SRC
sculpt_uv.c
curves_sculpt_intern.h
+ curves_sculpt_intern.hh
paint_intern.h
sculpt_intern.h
)
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc b/source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc
new file mode 100644
index 00000000000..945bb09c0c6
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_3d_brush.cc
@@ -0,0 +1,232 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <algorithm>
+
+#include "curves_sculpt_intern.hh"
+
+#include "BKE_bvhutils.h"
+#include "BKE_context.h"
+#include "BKE_curves.hh"
+
+#include "ED_view3d.h"
+
+#include "UI_interface.h"
+
+#include "BLI_enumerable_thread_specific.hh"
+#include "BLI_task.hh"
+
+/**
+ * The code below uses a prefix naming convention to indicate the coordinate space:
+ * cu: Local space of the curves object that is being edited.
+ * su: Local space of the surface object.
+ * wo: World space.
+ * re: 2D coordinates within the region.
+ */
+
+namespace blender::ed::sculpt_paint {
+
+struct BrushPositionCandidate {
+ /** 3D position of the brush. */
+ float3 position_cu;
+ /** Squared distance from the mouse position in screen space. */
+ float distance_sq_re = FLT_MAX;
+ /** Measure for how far away the candidate is from the camera. */
+ float depth_sq_cu = FLT_MAX;
+};
+
+/**
+ * Determine the 3D position of a brush based on curve segments under a screen position.
+ */
+static std::optional<float3> find_curves_brush_position(const CurvesGeometry &curves,
+ const float3 &ray_start_cu,
+ const float3 &ray_end_cu,
+ const float brush_radius_re,
+ ARegion &region,
+ RegionView3D &rv3d,
+ Object &object)
+{
+ /* This value might have to be adjusted based on user feedback. */
+ const float brush_inner_radius_re = std::min<float>(brush_radius_re, (float)UI_UNIT_X / 3.0f);
+ const float brush_inner_radius_sq_re = pow2f(brush_inner_radius_re);
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(&rv3d, &object, projection.values);
+
+ float2 brush_pos_re;
+ ED_view3d_project_float_v2_m4(&region, ray_start_cu, brush_pos_re, projection.values);
+
+ const float max_depth_sq_cu = math::distance_squared(ray_start_cu, ray_end_cu);
+
+ /* Contains the logic that checks if `b` is a better candidate than `a`. */
+ auto is_better_candidate = [&](const BrushPositionCandidate &a,
+ const BrushPositionCandidate &b) {
+ if (b.distance_sq_re <= brush_inner_radius_sq_re) {
+ if (a.distance_sq_re > brush_inner_radius_sq_re) {
+ /* New candidate is in inner radius while old one is not. */
+ return true;
+ }
+ if (b.depth_sq_cu < a.depth_sq_cu) {
+ /* Both candidates are in inner radius, but new one is closer to the camera. */
+ return true;
+ }
+ }
+ else if (b.distance_sq_re < a.distance_sq_re) {
+ /* Both candidates are outside of inner radius, but new on is closer to the brush center. */
+ return true;
+ }
+ return false;
+ };
+
+ auto update_if_better = [&](BrushPositionCandidate &a, const BrushPositionCandidate &b) {
+ if (is_better_candidate(a, b)) {
+ a = b;
+ }
+ };
+
+ const Span<float3> positions = curves.positions();
+
+ BrushPositionCandidate best_candidate = threading::parallel_reduce(
+ curves.curves_range(),
+ 128,
+ BrushPositionCandidate(),
+ [&](IndexRange curves_range, const BrushPositionCandidate &init) {
+ BrushPositionCandidate best_candidate = init;
+
+ for (const int curve_i : curves_range) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ const int tot_segments = points.size() - 1;
+
+ for (const int segment_i : IndexRange(tot_segments)) {
+ const float3 &p1_cu = positions[points[segment_i]];
+ const float3 &p2_cu = positions[points[segment_i] + 1];
+
+ float2 p1_re, p2_re;
+ ED_view3d_project_float_v2_m4(&region, p1_cu, p1_re, projection.values);
+ ED_view3d_project_float_v2_m4(&region, p2_cu, p2_re, projection.values);
+
+ float2 closest_re;
+ const float lambda = closest_to_line_segment_v2(
+ closest_re, brush_pos_re, p1_re, p2_re);
+
+ const float3 closest_cu = math::interpolate(p1_cu, p2_cu, lambda);
+ const float depth_sq_cu = math::distance_squared(ray_start_cu, closest_cu);
+ if (depth_sq_cu > max_depth_sq_cu) {
+ continue;
+ }
+
+ const float distance_sq_re = math::distance_squared(brush_pos_re, closest_re);
+
+ BrushPositionCandidate candidate;
+ candidate.position_cu = closest_cu;
+ candidate.depth_sq_cu = depth_sq_cu;
+ candidate.distance_sq_re = distance_sq_re;
+
+ update_if_better(best_candidate, candidate);
+ }
+ }
+ return best_candidate;
+ },
+ [&](const BrushPositionCandidate &a, const BrushPositionCandidate &b) {
+ return is_better_candidate(a, b) ? b : a;
+ });
+
+ if (best_candidate.distance_sq_re == FLT_MAX) {
+ /* Nothing found. */
+ return std::nullopt;
+ }
+
+ return best_candidate.position_cu;
+}
+
+std::optional<CurvesBrush3D> sample_curves_3d_brush(bContext &C,
+ Object &curves_object,
+ const float2 &brush_pos_re,
+ const float brush_radius_re)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(&C);
+ ARegion *region = CTX_wm_region(&C);
+ View3D *v3d = CTX_wm_view3d(&C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(&C);
+
+ Curves &curves_id = *static_cast<Curves *>(curves_object.data);
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ Object *surface_object = curves_id.surface;
+
+ float3 center_ray_start_wo, center_ray_end_wo;
+ ED_view3d_win_to_segment_clipped(
+ depsgraph, region, v3d, brush_pos_re, center_ray_start_wo, center_ray_end_wo, true);
+
+ /* Shorten ray when the surface object is hit. */
+ if (surface_object != nullptr) {
+ const float4x4 surface_to_world_mat = surface_object->obmat;
+ const float4x4 world_to_surface_mat = surface_to_world_mat.inverted();
+
+ Mesh &surface = *static_cast<Mesh *>(surface_object->data);
+ BVHTreeFromMesh surface_bvh;
+ BKE_bvhtree_from_mesh_get(&surface_bvh, &surface, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
+
+ const float3 center_ray_start_su = world_to_surface_mat * center_ray_start_wo;
+ float3 center_ray_end_su = world_to_surface_mat * center_ray_end_wo;
+ const float3 center_ray_direction_su = math::normalize(center_ray_end_su -
+ center_ray_start_su);
+
+ BVHTreeRayHit center_ray_hit;
+ center_ray_hit.dist = FLT_MAX;
+ center_ray_hit.index = -1;
+ BLI_bvhtree_ray_cast(surface_bvh.tree,
+ center_ray_start_su,
+ center_ray_direction_su,
+ 0.0f,
+ &center_ray_hit,
+ surface_bvh.raycast_callback,
+ &surface_bvh);
+ if (center_ray_hit.index >= 0) {
+ const float3 hit_position_su = center_ray_hit.co;
+ if (math::distance(center_ray_start_su, center_ray_end_su) >
+ math::distance(center_ray_start_su, hit_position_su)) {
+ center_ray_end_su = hit_position_su;
+ center_ray_end_wo = surface_to_world_mat * center_ray_end_su;
+ }
+ }
+ }
+
+ const float4x4 curves_to_world_mat = curves_object.obmat;
+ const float4x4 world_to_curves_mat = curves_to_world_mat.inverted();
+
+ const float3 center_ray_start_cu = world_to_curves_mat * center_ray_start_wo;
+ const float3 center_ray_end_cu = world_to_curves_mat * center_ray_end_wo;
+
+ const std::optional<float3> brush_position_optional_cu = find_curves_brush_position(
+ curves,
+ center_ray_start_cu,
+ center_ray_end_cu,
+ brush_radius_re,
+ *region,
+ *rv3d,
+ curves_object);
+ if (!brush_position_optional_cu.has_value()) {
+ /* Nothing found. */
+ return std::nullopt;
+ }
+ const float3 brush_position_cu = *brush_position_optional_cu;
+
+ /* Determine the 3D brush radius. */
+ float3 radius_ray_start_wo, radius_ray_end_wo;
+ ED_view3d_win_to_segment_clipped(depsgraph,
+ region,
+ v3d,
+ brush_pos_re + float2(brush_radius_re, 0.0f),
+ radius_ray_start_wo,
+ radius_ray_end_wo,
+ true);
+ const float3 radius_ray_start_cu = world_to_curves_mat * radius_ray_start_wo;
+ const float3 radius_ray_end_cu = world_to_curves_mat * radius_ray_end_wo;
+
+ CurvesBrush3D brush_3d;
+ brush_3d.position_cu = brush_position_cu;
+ brush_3d.radius_cu = dist_to_line_v3(brush_position_cu, radius_ray_start_cu, radius_ray_end_cu);
+ return brush_3d;
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
new file mode 100644
index 00000000000..809511d0106
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc
@@ -0,0 +1,792 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <algorithm>
+
+#include "curves_sculpt_intern.hh"
+
+#include "BLI_float4x4.hh"
+#include "BLI_kdtree.h"
+#include "BLI_rand.hh"
+#include "BLI_vector.hh"
+
+#include "PIL_time.h"
+
+#include "DEG_depsgraph.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_brush.h"
+#include "BKE_bvhutils.h"
+#include "BKE_context.h"
+#include "BKE_curves.hh"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_paint.h"
+#include "BKE_spline.hh"
+
+#include "DNA_brush_enums.h"
+#include "DNA_brush_types.h"
+#include "DNA_curves_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+/**
+ * The code below uses a prefix naming convention to indicate the coordinate space:
+ * cu: Local space of the curves object that is being edited.
+ * su: Local space of the surface object.
+ * wo: World space.
+ * re: 2D coordinates within the region.
+ */
+
+namespace blender::ed::sculpt_paint {
+
+using bke::CurvesGeometry;
+
+class AddOperation : public CurvesSculptStrokeOperation {
+ private:
+ /** Used when some data should be interpolated from existing curves. */
+ KDTree_3d *curve_roots_kdtree_ = nullptr;
+
+ friend struct AddOperationExecutor;
+
+ public:
+ ~AddOperation() override
+ {
+ if (curve_roots_kdtree_ != nullptr) {
+ BLI_kdtree_3d_free(curve_roots_kdtree_);
+ }
+ }
+
+ void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override;
+};
+
+static void initialize_straight_curve_positions(const float3 &p1,
+ const float3 &p2,
+ MutableSpan<float3> r_positions)
+{
+ const float step = 1.0f / (float)(r_positions.size() - 1);
+ for (const int i : r_positions.index_range()) {
+ r_positions[i] = math::interpolate(p1, p2, i * step);
+ }
+}
+
+/**
+ * Utility class that actually executes the update when the stroke is updated. That's useful
+ * because it avoids passing a very large number of parameters between functions.
+ */
+struct AddOperationExecutor {
+ AddOperation *self_ = nullptr;
+ Depsgraph *depsgraph_ = nullptr;
+ Scene *scene_ = nullptr;
+ Object *object_ = nullptr;
+ ARegion *region_ = nullptr;
+ View3D *v3d_ = nullptr;
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ Object *surface_ob_ = nullptr;
+ Mesh *surface_ = nullptr;
+ Span<MLoopTri> surface_looptris_;
+ Span<float3> corner_normals_su_;
+
+ CurvesSculpt *curves_sculpt_ = nullptr;
+ Brush *brush_ = nullptr;
+
+ float brush_radius_re_;
+ float2 brush_pos_re_;
+
+ bool use_front_face_;
+ bool interpolate_length_;
+ bool interpolate_shape_;
+ bool use_interpolation_;
+ float new_curve_length_;
+ int add_amount_;
+ int points_per_curve_ = 8;
+
+ /** Various matrices to convert between coordinate spaces. */
+ float4x4 curves_to_world_mat_;
+ float4x4 world_to_curves_mat_;
+ float4x4 world_to_surface_mat_;
+ float4x4 surface_to_world_mat_;
+ float4x4 surface_to_curves_mat_;
+ float4x4 surface_to_curves_normal_mat_;
+
+ BVHTreeFromMesh surface_bvh_;
+
+ int tot_old_curves_;
+ int tot_old_points_;
+
+ struct AddedPoints {
+ Vector<float3> positions_cu;
+ Vector<float3> bary_coords;
+ Vector<int> looptri_indices;
+ };
+
+ void execute(AddOperation &self, bContext *C, const StrokeExtension &stroke_extension)
+ {
+ self_ = &self;
+ depsgraph_ = CTX_data_depsgraph_pointer(C);
+ scene_ = CTX_data_scene(C);
+ object_ = CTX_data_active_object(C);
+ region_ = CTX_wm_region(C);
+ v3d_ = CTX_wm_view3d(C);
+
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+
+ if (curves_id_->surface == nullptr || curves_id_->surface->type != OB_MESH) {
+ return;
+ }
+
+ curves_to_world_mat_ = object_->obmat;
+ world_to_curves_mat_ = curves_to_world_mat_.inverted();
+
+ surface_ob_ = curves_id_->surface;
+ surface_ = static_cast<Mesh *>(surface_ob_->data);
+ surface_to_world_mat_ = surface_ob_->obmat;
+ world_to_surface_mat_ = surface_to_world_mat_.inverted();
+ surface_to_curves_mat_ = world_to_curves_mat_ * surface_to_world_mat_;
+ surface_to_curves_normal_mat_ = surface_to_curves_mat_.inverted().transposed();
+
+ if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) {
+ BKE_mesh_calc_normals_split(surface_);
+ }
+ corner_normals_su_ = {
+ reinterpret_cast<const float3 *>(CustomData_get_layer(&surface_->ldata, CD_NORMAL)),
+ surface_->totloop};
+
+ curves_sculpt_ = scene_->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush(&curves_sculpt_->paint);
+ brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_pos_re_ = stroke_extension.mouse_position;
+
+ use_front_face_ = brush_->flag & BRUSH_FRONTFACE;
+ const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
+ brush_->falloff_shape);
+ add_amount_ = std::max(0, brush_->curves_sculpt_settings->add_amount);
+ interpolate_length_ = curves_sculpt_->flag & CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH;
+ interpolate_shape_ = curves_sculpt_->flag & CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE;
+ use_interpolation_ = interpolate_length_ || interpolate_shape_;
+ new_curve_length_ = curves_sculpt_->curve_length;
+
+ tot_old_curves_ = curves_->curves_num();
+ tot_old_points_ = curves_->points_num();
+
+ if (add_amount_ == 0) {
+ return;
+ }
+
+ RandomNumberGenerator rng{(uint32_t)(PIL_check_seconds_timer() * 1000000.0f)};
+
+ BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); });
+
+ surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_),
+ BKE_mesh_runtime_looptri_len(surface_)};
+
+ /* Sample points on the surface using one of multiple strategies. */
+ AddedPoints added_points;
+ if (add_amount_ == 1) {
+ this->sample_in_center(added_points);
+ }
+ else if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->sample_projected(rng, added_points);
+ }
+ else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->sample_spherical(rng, added_points);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+
+ if (added_points.bary_coords.is_empty()) {
+ /* No new points have been added. */
+ return;
+ }
+
+ if (use_interpolation_) {
+ this->ensure_curve_roots_kdtree();
+ }
+
+ const int tot_added_curves = added_points.bary_coords.size();
+ const int tot_added_points = tot_added_curves * points_per_curve_;
+
+ curves_->resize(curves_->points_num() + tot_added_points,
+ curves_->curves_num() + tot_added_curves);
+
+ threading::parallel_invoke([&]() { this->initialize_curve_offsets(tot_added_curves); },
+ [&]() { this->initialize_attributes(added_points); });
+
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ ED_region_tag_redraw(region_);
+ }
+
+ float3 get_bary_coords(const Mesh &mesh, const MLoopTri &looptri, const float3 position) const
+ {
+ const float3 &v0 = mesh.mvert[mesh.mloop[looptri.tri[0]].v].co;
+ const float3 &v1 = mesh.mvert[mesh.mloop[looptri.tri[1]].v].co;
+ const float3 &v2 = mesh.mvert[mesh.mloop[looptri.tri[2]].v].co;
+ float3 bary_coords;
+ interp_weights_tri_v3(bary_coords, v0, v1, v2, position);
+ return bary_coords;
+ }
+
+ /**
+ * Sample a single point exactly at the mouse position.
+ */
+ void sample_in_center(AddedPoints &r_added_points)
+ {
+ float3 ray_start_wo, ray_end_wo;
+ ED_view3d_win_to_segment_clipped(
+ depsgraph_, region_, v3d_, brush_pos_re_, ray_start_wo, ray_end_wo, true);
+ const float3 ray_start_su = world_to_surface_mat_ * ray_start_wo;
+ const float3 ray_end_su = world_to_surface_mat_ * ray_end_wo;
+ const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
+
+ BVHTreeRayHit ray_hit;
+ ray_hit.dist = FLT_MAX;
+ ray_hit.index = -1;
+ BLI_bvhtree_ray_cast(surface_bvh_.tree,
+ ray_start_su,
+ ray_direction_su,
+ 0.0f,
+ &ray_hit,
+ surface_bvh_.raycast_callback,
+ &surface_bvh_);
+
+ if (ray_hit.index == -1) {
+ return;
+ }
+
+ const int looptri_index = ray_hit.index;
+ const float3 brush_pos_su = ray_hit.co;
+ const float3 bary_coords = this->get_bary_coords(
+ *surface_, surface_looptris_[looptri_index], brush_pos_su);
+
+ const float3 brush_pos_cu = surface_to_curves_mat_ * brush_pos_su;
+
+ r_added_points.positions_cu.append(brush_pos_cu);
+ r_added_points.bary_coords.append(bary_coords);
+ r_added_points.looptri_indices.append(looptri_index);
+ }
+
+ /**
+ * Sample points by shooting rays within the brush radius in the 3D view.
+ */
+ void sample_projected(RandomNumberGenerator &rng, AddedPoints &r_added_points)
+ {
+ const int max_iterations = std::max(100'000, add_amount_ * 10);
+ int current_iteration = 0;
+ while (r_added_points.bary_coords.size() < add_amount_) {
+ if (current_iteration++ >= max_iterations) {
+ break;
+ }
+
+ const float r = brush_radius_re_ * std::sqrt(rng.get_float());
+ const float angle = rng.get_float() * 2.0f * M_PI;
+ const float2 pos_re = brush_pos_re_ + r * float2(std::cos(angle), std::sin(angle));
+
+ float3 ray_start_wo, ray_end_wo;
+ ED_view3d_win_to_segment_clipped(
+ depsgraph_, region_, v3d_, pos_re, ray_start_wo, ray_end_wo, true);
+ const float3 ray_start_su = world_to_surface_mat_ * ray_start_wo;
+ const float3 ray_end_su = world_to_surface_mat_ * ray_end_wo;
+ const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
+
+ BVHTreeRayHit ray_hit;
+ ray_hit.dist = FLT_MAX;
+ ray_hit.index = -1;
+ BLI_bvhtree_ray_cast(surface_bvh_.tree,
+ ray_start_su,
+ ray_direction_su,
+ 0.0f,
+ &ray_hit,
+ surface_bvh_.raycast_callback,
+ &surface_bvh_);
+
+ if (ray_hit.index == -1) {
+ continue;
+ }
+
+ if (use_front_face_) {
+ const float3 normal_su = ray_hit.no;
+ if (math::dot(ray_direction_su, normal_su) >= 0.0f) {
+ continue;
+ }
+ }
+
+ const int looptri_index = ray_hit.index;
+ const float3 pos_su = ray_hit.co;
+
+ const float3 bary_coords = this->get_bary_coords(
+ *surface_, surface_looptris_[looptri_index], pos_su);
+
+ const float3 pos_cu = surface_to_curves_mat_ * pos_su;
+
+ r_added_points.positions_cu.append(pos_cu);
+ r_added_points.bary_coords.append(bary_coords);
+ r_added_points.looptri_indices.append(looptri_index);
+ }
+ }
+
+ /**
+ * Sample points in a 3D sphere around the surface position that the mouse hovers over.
+ */
+ void sample_spherical(RandomNumberGenerator &rng, AddedPoints &r_added_points)
+ {
+ /* Find ray that starts in the center of the brush. */
+ float3 brush_ray_start_wo, brush_ray_end_wo;
+ ED_view3d_win_to_segment_clipped(
+ depsgraph_, region_, v3d_, brush_pos_re_, brush_ray_start_wo, brush_ray_end_wo, true);
+ const float3 brush_ray_start_su = world_to_surface_mat_ * brush_ray_start_wo;
+ const float3 brush_ray_end_su = world_to_surface_mat_ * brush_ray_end_wo;
+ const float3 brush_ray_direction_su = math::normalize(brush_ray_end_su - brush_ray_start_su);
+
+ /* Find ray that starts on the boundary of the brush. That is used to compute the brush radius
+ * in 3D. */
+ float3 brush_radius_ray_start_wo, brush_radius_ray_end_wo;
+ ED_view3d_win_to_segment_clipped(depsgraph_,
+ region_,
+ v3d_,
+ brush_pos_re_ + float2(brush_radius_re_, 0),
+ brush_radius_ray_start_wo,
+ brush_radius_ray_end_wo,
+ true);
+ const float3 brush_radius_ray_start_su = world_to_surface_mat_ * brush_radius_ray_start_wo;
+ const float3 brush_radius_ray_end_su = world_to_surface_mat_ * brush_radius_ray_end_wo;
+
+ BVHTreeRayHit ray_hit;
+ ray_hit.dist = FLT_MAX;
+ ray_hit.index = -1;
+ BLI_bvhtree_ray_cast(surface_bvh_.tree,
+ brush_ray_start_su,
+ brush_ray_direction_su,
+ 0.0f,
+ &ray_hit,
+ surface_bvh_.raycast_callback,
+ &surface_bvh_);
+
+ if (ray_hit.index == -1) {
+ return;
+ }
+
+ /* Compute brush radius. */
+ const float3 brush_pos_su = ray_hit.co;
+ const float brush_radius_su = dist_to_line_v3(
+ brush_pos_su, brush_radius_ray_start_su, brush_radius_ray_end_su);
+ const float brush_radius_sq_su = pow2f(brush_radius_su);
+
+ /* Find surface triangles within brush radius. */
+ Vector<int> looptri_indices;
+ if (use_front_face_) {
+ BLI_bvhtree_range_query_cpp(
+ *surface_bvh_.tree,
+ brush_pos_su,
+ brush_radius_su,
+ [&](const int index, const float3 &UNUSED(co), const float UNUSED(dist_sq)) {
+ const MLoopTri &looptri = surface_looptris_[index];
+ const float3 v0_su = surface_->mvert[surface_->mloop[looptri.tri[0]].v].co;
+ const float3 v1_su = surface_->mvert[surface_->mloop[looptri.tri[1]].v].co;
+ const float3 v2_su = surface_->mvert[surface_->mloop[looptri.tri[2]].v].co;
+ float3 normal_su;
+ normal_tri_v3(normal_su, v0_su, v1_su, v2_su);
+ if (math::dot(normal_su, brush_ray_direction_su) >= 0.0f) {
+ return;
+ }
+ looptri_indices.append(index);
+ });
+ }
+ else {
+ BLI_bvhtree_range_query_cpp(
+ *surface_bvh_.tree,
+ brush_pos_su,
+ brush_radius_su,
+ [&](const int index, const float3 &UNUSED(co), const float UNUSED(dist_sq)) {
+ looptri_indices.append(index);
+ });
+ }
+
+ /* Density used for sampling points. This does not have to be exact, because the loop below
+ * automatically runs until enough samples have been found. If too many samples are found, some
+ * will be discarded afterwards. */
+ const float brush_plane_area_su = M_PI * brush_radius_sq_su;
+ const float approximate_density_su = add_amount_ / brush_plane_area_su;
+
+ /* Used for switching between two triangle sampling strategies. */
+ const float area_threshold = brush_plane_area_su;
+
+ /* Usually one or two iterations should be enough. */
+ const int max_iterations = 5;
+ int current_iteration = 0;
+
+ while (r_added_points.bary_coords.size() < add_amount_) {
+ if (current_iteration++ >= max_iterations) {
+ break;
+ }
+
+ for (const int looptri_index : looptri_indices) {
+ const MLoopTri &looptri = surface_looptris_[looptri_index];
+
+ const float3 v0_su = surface_->mvert[surface_->mloop[looptri.tri[0]].v].co;
+ const float3 v1_su = surface_->mvert[surface_->mloop[looptri.tri[1]].v].co;
+ const float3 v2_su = surface_->mvert[surface_->mloop[looptri.tri[2]].v].co;
+
+ const float looptri_area_su = area_tri_v3(v0_su, v1_su, v2_su);
+
+ if (looptri_area_su < area_threshold) {
+ /* The triangle is small compared to the brush radius. Sample by generating random
+ * barycentric coordinates. */
+ const int amount = rng.round_probabilistic(approximate_density_su * looptri_area_su);
+ for ([[maybe_unused]] const int i : IndexRange(amount)) {
+ const float3 bary_coord = rng.get_barycentric_coordinates();
+ const float3 point_pos_su = attribute_math::mix3(bary_coord, v0_su, v1_su, v2_su);
+ const float distance_to_brush_sq_su = math::distance_squared(point_pos_su,
+ brush_pos_su);
+ if (distance_to_brush_sq_su > brush_radius_sq_su) {
+ continue;
+ }
+
+ r_added_points.bary_coords.append(bary_coord);
+ r_added_points.looptri_indices.append(looptri_index);
+ r_added_points.positions_cu.append(surface_to_curves_mat_ * point_pos_su);
+ }
+ }
+ else {
+ /* The triangle is large compared to the brush radius. Sample by generating random points
+ * on the triangle plane within the brush radius. */
+ float3 normal_su;
+ normal_tri_v3(normal_su, v0_su, v1_su, v2_su);
+
+ float3 brush_pos_proj_su = brush_pos_su;
+ project_v3_plane(brush_pos_proj_su, normal_su, v0_su);
+
+ const float proj_distance_sq_su = math::distance_squared(brush_pos_proj_su,
+ brush_pos_su);
+ const float brush_radius_factor_sq = 1.0f -
+ std::min(1.0f,
+ proj_distance_sq_su / brush_radius_sq_su);
+ const float radius_proj_sq_su = brush_radius_sq_su * brush_radius_factor_sq;
+ const float radius_proj_su = std::sqrt(radius_proj_sq_su);
+ const float circle_area_su = M_PI * radius_proj_su;
+
+ const int amount = rng.round_probabilistic(approximate_density_su * circle_area_su);
+
+ const float3 axis_1_su = math::normalize(v1_su - v0_su) * radius_proj_su;
+ const float3 axis_2_su = math::normalize(math::cross(
+ axis_1_su, math::cross(axis_1_su, v2_su - v0_su))) *
+ radius_proj_su;
+
+ for ([[maybe_unused]] const int i : IndexRange(amount)) {
+ const float r = std::sqrt(rng.get_float());
+ const float angle = rng.get_float() * 2.0f * M_PI;
+ const float x = r * std::cos(angle);
+ const float y = r * std::sin(angle);
+ const float3 point_pos_su = brush_pos_proj_su + axis_1_su * x + axis_2_su * y;
+ if (!isect_point_tri_prism_v3(point_pos_su, v0_su, v1_su, v2_su)) {
+ /* Sampled point is not in the triangle. */
+ continue;
+ }
+
+ float3 bary_coord;
+ interp_weights_tri_v3(bary_coord, v0_su, v1_su, v2_su, point_pos_su);
+
+ r_added_points.bary_coords.append(bary_coord);
+ r_added_points.looptri_indices.append(looptri_index);
+ r_added_points.positions_cu.append(surface_to_curves_mat_ * point_pos_su);
+ }
+ }
+ }
+ }
+
+ /* Remove samples when there are too many. */
+ while (r_added_points.bary_coords.size() > add_amount_) {
+ const int index_to_remove = rng.get_int32(r_added_points.bary_coords.size());
+ r_added_points.bary_coords.remove_and_reorder(index_to_remove);
+ r_added_points.looptri_indices.remove_and_reorder(index_to_remove);
+ r_added_points.positions_cu.remove_and_reorder(index_to_remove);
+ }
+ }
+
+ void ensure_curve_roots_kdtree()
+ {
+ if (self_->curve_roots_kdtree_ == nullptr) {
+ self_->curve_roots_kdtree_ = BLI_kdtree_3d_new(curves_->curves_num());
+ for (const int curve_i : curves_->curves_range()) {
+ const int root_point_i = curves_->offsets()[curve_i];
+ const float3 &root_pos_cu = curves_->positions()[root_point_i];
+ BLI_kdtree_3d_insert(self_->curve_roots_kdtree_, curve_i, root_pos_cu);
+ }
+ BLI_kdtree_3d_balance(self_->curve_roots_kdtree_);
+ }
+ }
+
+ void initialize_curve_offsets(const int tot_added_curves)
+ {
+ MutableSpan<int> offsets = curves_->offsets();
+ threading::parallel_for(IndexRange(tot_added_curves), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int curve_i = tot_old_curves_ + i;
+ offsets[curve_i + 1] = tot_old_points_ + (i + 1) * points_per_curve_;
+ }
+ });
+ }
+
+ struct NeighborInfo {
+ /* Curve index of the neighbor. */
+ int index;
+ /* The weights of all neighbors of a new curve add up to 1. */
+ float weight;
+ };
+ static constexpr int max_neighbors = 5;
+ using NeighborsVector = Vector<NeighborInfo, max_neighbors>;
+
+ void initialize_attributes(const AddedPoints &added_points)
+ {
+ Array<NeighborsVector> neighbors_per_curve;
+ if (use_interpolation_) {
+ neighbors_per_curve = this->find_curve_neighbors(added_points);
+ }
+
+ Array<float> new_lengths_cu(added_points.bary_coords.size());
+ if (interpolate_length_) {
+ this->interpolate_lengths(neighbors_per_curve, new_lengths_cu);
+ }
+ else {
+ new_lengths_cu.fill(new_curve_length_);
+ }
+
+ Array<float3> new_normals_su = this->compute_normals_for_added_curves_su(added_points);
+ this->initialize_surface_attachment(added_points);
+
+ if (interpolate_shape_) {
+ this->initialize_position_with_interpolation(
+ added_points, neighbors_per_curve, new_normals_su, new_lengths_cu);
+ }
+ else {
+ this->initialize_position_without_interpolation(
+ added_points, new_lengths_cu, new_normals_su);
+ }
+ }
+
+ Array<NeighborsVector> find_curve_neighbors(const AddedPoints &added_points)
+ {
+ const int tot_added_curves = added_points.bary_coords.size();
+ Array<NeighborsVector> neighbors_per_curve(tot_added_curves);
+ threading::parallel_for(IndexRange(tot_added_curves), 128, [&](const IndexRange range) {
+ for (const int i : range) {
+ const float3 root_cu = added_points.positions_cu[i];
+ std::array<KDTreeNearest_3d, max_neighbors> nearest_n;
+ const int found_neighbors = BLI_kdtree_3d_find_nearest_n(
+ self_->curve_roots_kdtree_, root_cu, nearest_n.data(), max_neighbors);
+ float tot_weight = 0.0f;
+ for (const int neighbor_i : IndexRange(found_neighbors)) {
+ KDTreeNearest_3d &nearest = nearest_n[neighbor_i];
+ const float weight = 1.0f / std::max(nearest.dist, 0.00001f);
+ tot_weight += weight;
+ neighbors_per_curve[i].append({nearest.index, weight});
+ }
+ /* Normalize weights. */
+ for (NeighborInfo &neighbor : neighbors_per_curve[i]) {
+ neighbor.weight /= tot_weight;
+ }
+ }
+ });
+ return neighbors_per_curve;
+ }
+
+ void interpolate_lengths(const Span<NeighborsVector> neighbors_per_curve,
+ MutableSpan<float> r_lengths)
+ {
+ const Span<float3> positions_cu = curves_->positions();
+
+ threading::parallel_for(r_lengths.index_range(), 128, [&](const IndexRange range) {
+ for (const int added_curve_i : range) {
+ const Span<NeighborInfo> neighbors = neighbors_per_curve[added_curve_i];
+ float length_sum = 0.0f;
+ for (const NeighborInfo &neighbor : neighbors) {
+ const IndexRange neighbor_points = curves_->points_for_curve(neighbor.index);
+ float neighbor_length = 0.0f;
+ const int tot_segments = neighbor_points.size() - 1;
+ for (const int segment_i : IndexRange(tot_segments)) {
+ const float3 &p1 = positions_cu[neighbor_points[segment_i]];
+ const float3 &p2 = positions_cu[neighbor_points[segment_i] + 1];
+ neighbor_length += math::distance(p1, p2);
+ }
+ length_sum += neighbor.weight * neighbor_length;
+ }
+ const float length = neighbors.is_empty() ? new_curve_length_ : length_sum;
+ r_lengths[added_curve_i] = length;
+ }
+ });
+ }
+
+ float3 compute_point_normal_su(const int looptri_index, const float3 &bary_coord)
+ {
+ const MLoopTri &looptri = surface_looptris_[looptri_index];
+ const int l0 = looptri.tri[0];
+ const int l1 = looptri.tri[1];
+ const int l2 = looptri.tri[2];
+
+ const float3 &l0_normal_su = corner_normals_su_[l0];
+ const float3 &l1_normal_su = corner_normals_su_[l1];
+ const float3 &l2_normal_su = corner_normals_su_[l2];
+
+ const float3 normal_su = math::normalize(
+ attribute_math::mix3(bary_coord, l0_normal_su, l1_normal_su, l2_normal_su));
+ return normal_su;
+ }
+
+ Array<float3> compute_normals_for_added_curves_su(const AddedPoints &added_points)
+ {
+ Array<float3> normals_su(added_points.bary_coords.size());
+ threading::parallel_for(normals_su.index_range(), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int looptri_index = added_points.looptri_indices[i];
+ const float3 &bary_coord = added_points.bary_coords[i];
+ normals_su[i] = this->compute_point_normal_su(looptri_index, bary_coord);
+ }
+ });
+ return normals_su;
+ }
+
+ void initialize_surface_attachment(const AddedPoints &added_points)
+ {
+ MutableSpan<int> surface_triangle_indices = curves_->surface_triangle_indices();
+ MutableSpan<float2> surface_triangle_coords = curves_->surface_triangle_coords();
+ threading::parallel_for(
+ added_points.bary_coords.index_range(), 1024, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int curve_i = tot_old_curves_ + i;
+ surface_triangle_indices[curve_i] = added_points.looptri_indices[i];
+ surface_triangle_coords[curve_i] = float2(added_points.bary_coords[i]);
+ }
+ });
+ }
+
+ /**
+ * Initialize new curves so that they are just a straight line in the normal direction.
+ */
+ void initialize_position_without_interpolation(const AddedPoints &added_points,
+ const Span<float> lengths_cu,
+ const MutableSpan<float3> normals_su)
+ {
+ MutableSpan<float3> positions_cu = curves_->positions();
+
+ threading::parallel_for(
+ added_points.bary_coords.index_range(), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const int first_point_i = tot_old_points_ + i * points_per_curve_;
+ const float3 &root_cu = added_points.positions_cu[i];
+ const float length = lengths_cu[i];
+ const float3 &normal_su = normals_su[i];
+ const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su);
+ const float3 tip_cu = root_cu + length * normal_cu;
+
+ initialize_straight_curve_positions(
+ root_cu, tip_cu, positions_cu.slice(first_point_i, points_per_curve_));
+ }
+ });
+ }
+
+ /**
+ * Use neighboring curves to determine the shape.
+ */
+ void initialize_position_with_interpolation(const AddedPoints &added_points,
+ const Span<NeighborsVector> neighbors_per_curve,
+ const Span<float3> new_normals_su,
+ const Span<float> new_lengths_cu)
+ {
+ MutableSpan<float3> positions_cu = curves_->positions();
+ const Span<int> surface_triangle_indices = curves_->surface_triangle_indices();
+ const Span<float2> surface_triangle_coords = curves_->surface_triangle_coords();
+
+ threading::parallel_for(
+ added_points.bary_coords.index_range(), 256, [&](const IndexRange range) {
+ for (const int i : range) {
+ const Span<NeighborInfo> neighbors = neighbors_per_curve[i];
+
+ const float length_cu = new_lengths_cu[i];
+ const float3 &normal_su = new_normals_su[i];
+ const float3 normal_cu = math::normalize(surface_to_curves_normal_mat_ * normal_su);
+
+ const float3 &root_cu = added_points.positions_cu[i];
+ const int first_point_i = tot_old_points_ + i * points_per_curve_;
+
+ if (neighbors.is_empty()) {
+ /* If there are no neighbors, just make a straight line. */
+ const float3 tip_cu = root_cu + length_cu * normal_cu;
+ initialize_straight_curve_positions(
+ root_cu, tip_cu, positions_cu.slice(first_point_i, points_per_curve_));
+ continue;
+ }
+
+ positions_cu.slice(first_point_i, points_per_curve_).fill(root_cu);
+
+ for (const NeighborInfo &neighbor : neighbors) {
+ const int neighbor_curve_i = neighbor.index;
+ const int neighbor_looptri_index = surface_triangle_indices[neighbor_curve_i];
+
+ float3 neighbor_bary_coord{surface_triangle_coords[neighbor_curve_i]};
+ neighbor_bary_coord.z = 1.0f - neighbor_bary_coord.x - neighbor_bary_coord.y;
+
+ const float3 neighbor_normal_su = this->compute_point_normal_su(
+ neighbor_looptri_index, neighbor_bary_coord);
+ const float3 neighbor_normal_cu = math::normalize(surface_to_curves_normal_mat_ *
+ neighbor_normal_su);
+
+ /* The rotation matrix used to transform relative coordinates of the neighbor curve
+ * to the new curve. */
+ float normal_rotation_cu[3][3];
+ rotation_between_vecs_to_mat3(normal_rotation_cu, neighbor_normal_cu, normal_cu);
+
+ const IndexRange neighbor_points = curves_->points_for_curve(neighbor_curve_i);
+ const float3 &neighbor_root_cu = positions_cu[neighbor_points[0]];
+
+ /* Use a temporary #PolySpline, because that's the easiest way to resample an
+ * existing curve right now. Resampling is necessary if the length of the new curve
+ * does not match the length of the neighbors or the number of handle points is
+ * different. */
+ PolySpline neighbor_spline;
+ neighbor_spline.resize(neighbor_points.size());
+ neighbor_spline.positions().copy_from(positions_cu.slice(neighbor_points));
+ neighbor_spline.mark_cache_invalid();
+
+ const float neighbor_length_cu = neighbor_spline.length();
+ const float length_factor = std::min(1.0f, length_cu / neighbor_length_cu);
+
+ const float resample_factor = (1.0f / (points_per_curve_ - 1.0f)) * length_factor;
+ for (const int j : IndexRange(points_per_curve_)) {
+ const Spline::LookupResult lookup = neighbor_spline.lookup_evaluated_factor(
+ j * resample_factor);
+ const float index_factor = lookup.evaluated_index + lookup.factor;
+ float3 p;
+ neighbor_spline.sample_with_index_factors<float3>(
+ neighbor_spline.positions(), {&index_factor, 1}, {&p, 1});
+ const float3 relative_coord = p - neighbor_root_cu;
+ float3 rotated_relative_coord = relative_coord;
+ mul_m3_v3(normal_rotation_cu, rotated_relative_coord);
+ positions_cu[first_point_i + j] += neighbor.weight * rotated_relative_coord;
+ }
+ }
+ }
+ });
+ }
+};
+
+void AddOperation::on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension)
+{
+ AddOperationExecutor executor;
+ executor.execute(*this, C, stroke_extension);
+}
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation()
+{
+ return std::make_unique<AddOperation>();
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
new file mode 100644
index 00000000000..d062fe32cfe
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc
@@ -0,0 +1,377 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <algorithm>
+
+#include "curves_sculpt_intern.hh"
+
+#include "BLI_float4x4.hh"
+#include "BLI_index_mask_ops.hh"
+#include "BLI_kdtree.h"
+#include "BLI_rand.hh"
+#include "BLI_vector.hh"
+
+#include "PIL_time.h"
+
+#include "DEG_depsgraph.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_brush.h"
+#include "BKE_bvhutils.h"
+#include "BKE_context.h"
+#include "BKE_curves.hh"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_paint.h"
+
+#include "DNA_brush_enums.h"
+#include "DNA_brush_types.h"
+#include "DNA_curves_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "UI_interface.h"
+
+/**
+ * The code below uses a prefix naming convention to indicate the coordinate space:
+ * cu: Local space of the curves object that is being edited.
+ * su: Local space of the surface object.
+ * wo: World space.
+ * re: 2D coordinates within the region.
+ */
+
+namespace blender::ed::sculpt_paint {
+
+using blender::bke::CurvesGeometry;
+using threading::EnumerableThreadSpecific;
+
+/**
+ * Moves individual points under the brush and does a length preservation step afterwards.
+ */
+class CombOperation : public CurvesSculptStrokeOperation {
+ private:
+ /** Last mouse position. */
+ float2 brush_pos_last_re_;
+
+ /** Only used when a 3D brush is used. */
+ CurvesBrush3D brush_3d_;
+
+ /** Length of each segment indexed by the index of the first point in the segment. */
+ Array<float> segment_lengths_cu_;
+
+ friend struct CombOperationExecutor;
+
+ public:
+ void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override;
+};
+
+/**
+ * Utility class that actually executes the update when the stroke is updated. That's useful
+ * because it avoids passing a very large number of parameters between functions.
+ */
+struct CombOperationExecutor {
+ CombOperation *self_ = nullptr;
+ bContext *C_ = nullptr;
+ Depsgraph *depsgraph_ = nullptr;
+ Scene *scene_ = nullptr;
+ Object *object_ = nullptr;
+ ARegion *region_ = nullptr;
+ View3D *v3d_ = nullptr;
+ RegionView3D *rv3d_ = nullptr;
+
+ CurvesSculpt *curves_sculpt_ = nullptr;
+ Brush *brush_ = nullptr;
+ float brush_radius_re_;
+ float brush_strength_;
+
+ eBrushFalloffShape falloff_shape_;
+
+ Curves *curves_id_ = nullptr;
+ CurvesGeometry *curves_ = nullptr;
+
+ const Object *surface_ob_ = nullptr;
+ const Mesh *surface_ = nullptr;
+ Span<MLoopTri> surface_looptris_;
+
+ float2 brush_pos_prev_re_;
+ float2 brush_pos_re_;
+ float2 brush_pos_diff_re_;
+ float brush_pos_diff_length_re_;
+
+ float4x4 curves_to_world_mat_;
+ float4x4 world_to_curves_mat_;
+ float4x4 surface_to_world_mat_;
+ float4x4 world_to_surface_mat_;
+
+ BVHTreeFromMesh surface_bvh_;
+
+ void execute(CombOperation &self, bContext *C, const StrokeExtension &stroke_extension)
+ {
+ self_ = &self;
+
+ BLI_SCOPED_DEFER([&]() { self_->brush_pos_last_re_ = stroke_extension.mouse_position; });
+
+ C_ = C;
+ depsgraph_ = CTX_data_depsgraph_pointer(C);
+ scene_ = CTX_data_scene(C);
+ object_ = CTX_data_active_object(C);
+ region_ = CTX_wm_region(C);
+ v3d_ = CTX_wm_view3d(C);
+ rv3d_ = CTX_wm_region_view3d(C);
+
+ curves_sculpt_ = scene_->toolsettings->curves_sculpt;
+ brush_ = BKE_paint_brush(&curves_sculpt_->paint);
+ brush_radius_re_ = BKE_brush_size_get(scene_, brush_);
+ brush_strength_ = BKE_brush_alpha_get(scene_, brush_);
+
+ curves_to_world_mat_ = object_->obmat;
+ world_to_curves_mat_ = curves_to_world_mat_.inverted();
+
+ falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
+
+ curves_id_ = static_cast<Curves *>(object_->data);
+ curves_ = &CurvesGeometry::wrap(curves_id_->geometry);
+
+ brush_pos_prev_re_ = self_->brush_pos_last_re_;
+ brush_pos_re_ = stroke_extension.mouse_position;
+ brush_pos_diff_re_ = brush_pos_re_ - brush_pos_prev_re_;
+ brush_pos_diff_length_re_ = math::length(brush_pos_diff_re_);
+
+ surface_ob_ = curves_id_->surface;
+ if (surface_ob_ != nullptr) {
+ surface_ = static_cast<const Mesh *>(surface_ob_->data);
+ surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_),
+ BKE_mesh_runtime_looptri_len(surface_)};
+ surface_to_world_mat_ = surface_ob_->obmat;
+ world_to_surface_mat_ = surface_to_world_mat_.inverted();
+ BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
+ }
+
+ BLI_SCOPED_DEFER([&]() {
+ if (surface_ob_ != nullptr) {
+ free_bvhtree_from_mesh(&surface_bvh_);
+ }
+ });
+
+ if (stroke_extension.is_first) {
+ if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->initialize_spherical_brush_reference_point();
+ }
+ this->initialize_segment_lengths();
+ /* Combing does nothing when there is no mouse movement, so return directly. */
+ return;
+ }
+
+ EnumerableThreadSpecific<Vector<int>> changed_curves;
+
+ if (falloff_shape_ == PAINT_FALLOFF_SHAPE_TUBE) {
+ this->comb_projected(changed_curves);
+ }
+ else if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
+ this->comb_spherical(changed_curves);
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+
+ this->restore_segment_lengths(changed_curves);
+
+ curves_->tag_positions_changed();
+ DEG_id_tag_update(&curves_id_->id, ID_RECALC_GEOMETRY);
+ ED_region_tag_redraw(region_);
+ }
+
+ /**
+ * Do combing in screen space.
+ */
+ void comb_projected(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
+ {
+ MutableSpan<float3> positions_cu = curves_->positions();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+
+ const float brush_radius_sq_re = pow2f(brush_radius_re_);
+
+ threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
+ Vector<int> &local_changed_curves = r_changed_curves.local();
+ for (const int curve_i : curves_range) {
+ bool curve_changed = false;
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points.drop_front(1)) {
+ const float3 old_pos_cu = positions_cu[point_i];
+
+ /* Find the position of the point in screen space. */
+ float2 old_pos_re;
+ ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values);
+
+ const float distance_to_brush_sq_re = dist_squared_to_line_segment_v2(
+ old_pos_re, brush_pos_prev_re_, brush_pos_re_);
+ if (distance_to_brush_sq_re > brush_radius_sq_re) {
+ /* Ignore the point because it's too far away. */
+ continue;
+ }
+
+ const float distance_to_brush_re = std::sqrt(distance_to_brush_sq_re);
+ /* A falloff that is based on how far away the point is from the stroke. */
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, distance_to_brush_re, brush_radius_re_);
+ /* Combine the falloff and brush strength. */
+ const float weight = brush_strength_ * radius_falloff;
+
+ /* Offset the old point position in screen space and transform it back into 3D space. */
+ const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight;
+ float3 new_position_wo;
+ ED_view3d_win_to_3d(
+ v3d_, region_, curves_to_world_mat_ * old_pos_cu, new_position_re, new_position_wo);
+ const float3 new_position_cu = world_to_curves_mat_ * new_position_wo;
+ positions_cu[point_i] = new_position_cu;
+
+ curve_changed = true;
+ }
+ if (curve_changed) {
+ local_changed_curves.append(curve_i);
+ }
+ }
+ });
+ }
+
+ /**
+ * Do combing in 3D space.
+ */
+ void comb_spherical(EnumerableThreadSpecific<Vector<int>> &r_changed_curves)
+ {
+ MutableSpan<float3> positions_cu = curves_->positions();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
+
+ float3 brush_start_wo, brush_end_wo;
+ ED_view3d_win_to_3d(v3d_,
+ region_,
+ curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ brush_pos_prev_re_,
+ brush_start_wo);
+ ED_view3d_win_to_3d(v3d_,
+ region_,
+ curves_to_world_mat_ * self_->brush_3d_.position_cu,
+ brush_pos_re_,
+ brush_end_wo);
+ const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
+ const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
+
+ const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
+
+ const float brush_radius_cu = self_->brush_3d_.radius_cu;
+ const float brush_radius_sq_cu = pow2f(brush_radius_cu);
+
+ threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
+ Vector<int> &local_changed_curves = r_changed_curves.local();
+ for (const int curve_i : curves_range) {
+ bool curve_changed = false;
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points.drop_front(1)) {
+ const float3 pos_old_cu = positions_cu[point_i];
+
+ /* Compute distance to the brush. */
+ const float distance_to_brush_sq_cu = dist_squared_to_line_segment_v3(
+ pos_old_cu, brush_start_cu, brush_end_cu);
+ if (distance_to_brush_sq_cu > brush_radius_sq_cu) {
+ /* Ignore the point because it's too far away. */
+ continue;
+ }
+
+ const float distance_to_brush_cu = std::sqrt(distance_to_brush_sq_cu);
+
+ /* A falloff that is based on how far away the point is from the stroke. */
+ const float radius_falloff = BKE_brush_curve_strength(
+ brush_, distance_to_brush_cu, brush_radius_cu);
+ /* Combine the falloff and brush strength. */
+ const float weight = brush_strength_ * radius_falloff;
+
+ /* Update the point position. */
+ positions_cu[point_i] = pos_old_cu + weight * brush_diff_cu;
+ curve_changed = true;
+ }
+ if (curve_changed) {
+ local_changed_curves.append(curve_i);
+ }
+ }
+ });
+ }
+
+ /**
+ * Sample depth under mouse by looking at curves and the surface.
+ */
+ void initialize_spherical_brush_reference_point()
+ {
+ std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
+ *C_, *object_, brush_pos_re_, brush_radius_re_);
+ if (brush_3d.has_value()) {
+ self_->brush_3d_ = *brush_3d;
+ }
+ }
+
+ /**
+ * Remember the initial length of all curve segments. This allows restoring the length after
+ * combing.
+ */
+ void initialize_segment_lengths()
+ {
+ const Span<float3> positions_cu = curves_->positions();
+ self_->segment_lengths_cu_.reinitialize(curves_->points_num());
+ threading::parallel_for(curves_->curves_range(), 128, [&](const IndexRange range) {
+ for (const int curve_i : range) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int point_i : points.drop_back(1)) {
+ const float3 &p1_cu = positions_cu[point_i];
+ const float3 &p2_cu = positions_cu[point_i + 1];
+ const float length_cu = math::distance(p1_cu, p2_cu);
+ self_->segment_lengths_cu_[point_i] = length_cu;
+ }
+ }
+ });
+ }
+
+ /**
+ * Restore previously stored length for each segment in the changed curves.
+ */
+ void restore_segment_lengths(EnumerableThreadSpecific<Vector<int>> &changed_curves)
+ {
+ const Span<float> expected_lengths_cu = self_->segment_lengths_cu_;
+ MutableSpan<float3> positions_cu = curves_->positions();
+
+ threading::parallel_for_each(changed_curves, [&](const Vector<int> &changed_curves) {
+ threading::parallel_for(changed_curves.index_range(), 256, [&](const IndexRange range) {
+ for (const int curve_i : changed_curves.as_span().slice(range)) {
+ const IndexRange points = curves_->points_for_curve(curve_i);
+ for (const int segment_i : IndexRange(points.size() - 1)) {
+ const float3 &p1_cu = positions_cu[points[segment_i]];
+ float3 &p2_cu = positions_cu[points[segment_i] + 1];
+ const float3 direction = math::normalize(p2_cu - p1_cu);
+ const float expected_length_cu = expected_lengths_cu[points[segment_i]];
+ p2_cu = p1_cu + direction * expected_length_cu;
+ }
+ }
+ });
+ });
+ }
+};
+
+void CombOperation::on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension)
+{
+ CombOperationExecutor executor;
+ executor.execute(*this, C, stroke_extension);
+}
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_comb_operation()
+{
+ return std::make_unique<CombOperation>();
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
new file mode 100644
index 00000000000..ae87f414dd5
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc
@@ -0,0 +1,105 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <algorithm>
+
+#include "curves_sculpt_intern.hh"
+
+#include "BLI_float4x4.hh"
+#include "BLI_index_mask_ops.hh"
+#include "BLI_kdtree.h"
+#include "BLI_rand.hh"
+#include "BLI_vector.hh"
+
+#include "PIL_time.h"
+
+#include "DEG_depsgraph.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_brush.h"
+#include "BKE_bvhutils.h"
+#include "BKE_context.h"
+#include "BKE_curves.hh"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_paint.h"
+
+#include "DNA_brush_enums.h"
+#include "DNA_brush_types.h"
+#include "DNA_curves_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+namespace blender::ed::sculpt_paint {
+
+using blender::bke::CurvesGeometry;
+
+class DeleteOperation : public CurvesSculptStrokeOperation {
+ private:
+ float2 last_mouse_position_;
+
+ public:
+ void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override
+ {
+ Scene &scene = *CTX_data_scene(C);
+ Object &object = *CTX_data_active_object(C);
+ ARegion *region = CTX_wm_region(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
+ Brush &brush = *BKE_paint_brush(&curves_sculpt.paint);
+ const float brush_radius = BKE_brush_size_get(&scene, &brush);
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(rv3d, &object, projection.values);
+
+ Curves &curves_id = *static_cast<Curves *>(object.data);
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ MutableSpan<float3> positions = curves.positions();
+
+ const float2 mouse_start = stroke_extension.is_first ? stroke_extension.mouse_position :
+ last_mouse_position_;
+ const float2 mouse_end = stroke_extension.mouse_position;
+
+ /* Find indices of curves that have to be removed. */
+ Vector<int64_t> indices;
+ const IndexMask curves_to_remove = index_mask_ops::find_indices_based_on_predicate(
+ curves.curves_range(), 512, indices, [&](const int curve_i) {
+ const IndexRange point_range = curves.points_for_curve(curve_i);
+ for (const int segment_i : IndexRange(point_range.size() - 1)) {
+ const float3 pos1 = positions[point_range[segment_i]];
+ const float3 pos2 = positions[point_range[segment_i + 1]];
+
+ float2 pos1_proj, pos2_proj;
+ ED_view3d_project_float_v2_m4(region, pos1, pos1_proj, projection.values);
+ ED_view3d_project_float_v2_m4(region, pos2, pos2_proj, projection.values);
+
+ const float dist = dist_seg_seg_v2(pos1_proj, pos2_proj, mouse_start, mouse_end);
+ if (dist <= brush_radius) {
+ return true;
+ }
+ }
+ return false;
+ });
+
+ curves.remove_curves(curves_to_remove);
+
+ curves.tag_positions_changed();
+ DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
+ ED_region_tag_redraw(region);
+
+ last_mouse_position_ = stroke_extension.mouse_position;
+ }
+};
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_delete_operation()
+{
+ return std::make_unique<DeleteOperation>();
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
new file mode 100644
index 00000000000..d021627921f
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_intern.hh
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include <optional>
+
+#include "curves_sculpt_intern.h"
+
+#include "BLI_math_vector.hh"
+
+#include "BKE_curves.hh"
+
+struct ARegion;
+struct RegionView3D;
+struct Object;
+
+namespace blender::ed::sculpt_paint {
+
+using bke::CurvesGeometry;
+
+struct StrokeExtension {
+ bool is_first;
+ float2 mouse_position;
+};
+
+/**
+ * Base class for stroke based operations in curves sculpt mode.
+ */
+class CurvesSculptStrokeOperation {
+ public:
+ virtual ~CurvesSculptStrokeOperation() = default;
+ virtual void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) = 0;
+};
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_add_operation();
+std::unique_ptr<CurvesSculptStrokeOperation> new_comb_operation();
+std::unique_ptr<CurvesSculptStrokeOperation> new_delete_operation();
+std::unique_ptr<CurvesSculptStrokeOperation> new_snake_hook_operation();
+
+struct CurvesBrush3D {
+ float3 position_cu;
+ float radius_cu;
+};
+
+/**
+ * Find 3d brush position based on cursor position for curves sculpting.
+ */
+std::optional<CurvesBrush3D> sample_curves_3d_brush(bContext &C,
+ Object &curves_object,
+ const float2 &brush_pos_re,
+ float brush_radius_re);
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
index 63202f3902a..382f0529daa 100644
--- a/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
@@ -40,6 +40,7 @@
#include "PIL_time.h"
#include "curves_sculpt_intern.h"
+#include "curves_sculpt_intern.hh"
#include "paint_intern.h"
/* -------------------------------------------------------------------- */
@@ -68,318 +69,11 @@ bool CURVES_SCULPT_mode_poll_view3d(bContext *C)
namespace blender::ed::sculpt_paint {
using blender::bke::CurvesGeometry;
-using blender::fn::CPPType;
/* -------------------------------------------------------------------- */
/** \name * SCULPT_CURVES_OT_brush_stroke
* \{ */
-struct StrokeExtension {
- bool is_first;
- float2 mouse_position;
-};
-
-/**
- * Base class for stroke based operations in curves sculpt mode.
- */
-class CurvesSculptStrokeOperation {
- public:
- virtual ~CurvesSculptStrokeOperation() = default;
- virtual void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) = 0;
-};
-
-class DeleteOperation : public CurvesSculptStrokeOperation {
- private:
- float2 last_mouse_position_;
-
- public:
- void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override
- {
- Scene &scene = *CTX_data_scene(C);
- Object &object = *CTX_data_active_object(C);
- ARegion *region = CTX_wm_region(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
-
- CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
- Brush &brush = *BKE_paint_brush(&curves_sculpt.paint);
- const float brush_radius = BKE_brush_size_get(&scene, &brush);
-
- float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d, &object, projection.values);
-
- Curves &curves_id = *static_cast<Curves *>(object.data);
- CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
- MutableSpan<float3> positions = curves.positions();
-
- const float2 mouse_start = stroke_extension.is_first ? stroke_extension.mouse_position :
- last_mouse_position_;
- const float2 mouse_end = stroke_extension.mouse_position;
-
- /* Find indices of curves that have to be removed. */
- Vector<int64_t> indices;
- const IndexMask curves_to_remove = index_mask_ops::find_indices_based_on_predicate(
- curves.curves_range(), 512, indices, [&](const int curve_i) {
- const IndexRange point_range = curves.range_for_curve(curve_i);
- for (const int segment_i : IndexRange(point_range.size() - 1)) {
- const float3 pos1 = positions[point_range[segment_i]];
- const float3 pos2 = positions[point_range[segment_i + 1]];
-
- float2 pos1_proj, pos2_proj;
- ED_view3d_project_float_v2_m4(region, pos1, pos1_proj, projection.values);
- ED_view3d_project_float_v2_m4(region, pos2, pos2_proj, projection.values);
-
- const float dist = dist_seg_seg_v2(pos1_proj, pos2_proj, mouse_start, mouse_end);
- if (dist <= brush_radius) {
- return true;
- }
- }
- return false;
- });
-
- curves.remove_curves(curves_to_remove);
-
- curves.tag_positions_changed();
- DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
- ED_region_tag_redraw(region);
-
- last_mouse_position_ = stroke_extension.mouse_position;
- }
-};
-
-/**
- * Moves individual points under the brush and does a length preservation step afterwards.
- */
-class CombOperation : public CurvesSculptStrokeOperation {
- private:
- float2 last_mouse_position_;
-
- public:
- void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override
- {
- BLI_SCOPED_DEFER([&]() { last_mouse_position_ = stroke_extension.mouse_position; });
-
- if (stroke_extension.is_first) {
- return;
- }
-
- Scene &scene = *CTX_data_scene(C);
- Object &object = *CTX_data_active_object(C);
- ARegion *region = CTX_wm_region(C);
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
-
- CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
- Brush &brush = *BKE_paint_brush(&curves_sculpt.paint);
- const float brush_radius = BKE_brush_size_get(&scene, &brush);
- const float brush_strength = BKE_brush_alpha_get(&scene, &brush);
-
- const float4x4 ob_mat = object.obmat;
- const float4x4 ob_imat = ob_mat.inverted();
-
- float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d, &object, projection.values);
-
- Curves &curves_id = *static_cast<Curves *>(object.data);
- CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
- MutableSpan<float3> positions = curves.positions();
-
- const float2 mouse_prev = last_mouse_position_;
- const float2 mouse_cur = stroke_extension.mouse_position;
- const float2 mouse_diff = mouse_cur - mouse_prev;
- const float mouse_diff_len = math::length(mouse_diff);
-
- threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
- for (const int curve_i : curves_range) {
- const IndexRange curve_points = curves.range_for_curve(curve_i);
- /* Compute lengths of the segments. Those are used to make sure that the lengths don't
- * change. */
- Vector<float, 16> segment_lengths(curve_points.size() - 1);
- for (const int segment_i : IndexRange(curve_points.size() - 1)) {
- const float3 &p1 = positions[curve_points[segment_i]];
- const float3 &p2 = positions[curve_points[segment_i] + 1];
- const float length = math::distance(p1, p2);
- segment_lengths[segment_i] = length;
- }
- bool curve_changed = false;
- for (const int point_i : curve_points.drop_front(1)) {
- const float3 old_position = positions[point_i];
-
- /* Find the position of the point in screen space. */
- float2 old_position_screen;
- ED_view3d_project_float_v2_m4(
- region, old_position, old_position_screen, projection.values);
-
- /* Project the point onto the line drawn by the mouse. Note, it's projected on the
- * infinite line, not only on the line segment. */
- float2 old_position_screen_proj;
- /* t is 0 when the point is closest to the previous mouse position and 1 when it's
- * closest to the current mouse position. */
- const float t = closest_to_line_v2(
- old_position_screen_proj, old_position_screen, mouse_prev, mouse_cur);
-
- /* Compute the distance to the mouse line segment. */
- const float2 old_position_screen_proj_segment = mouse_prev +
- std::clamp(t, 0.0f, 1.0f) * mouse_diff;
- const float distance_screen = math::distance(old_position_screen,
- old_position_screen_proj_segment);
- if (distance_screen > brush_radius) {
- /* Ignore the point because it's too far away. */
- continue;
- }
- /* Compute a falloff that is based on how far along the point along the last stroke
- * segment is. */
- const float t_overshoot = brush_radius / mouse_diff_len;
- const float t_falloff = 1.0f - std::max(t, 0.0f) / (1.0f + t_overshoot);
- /* A falloff that is based on how far away the point is from the stroke. */
- const float radius_falloff = pow2f(1.0f - distance_screen / brush_radius);
- /* Combine the different falloffs and brush strength. */
- const float weight = brush_strength * t_falloff * radius_falloff;
-
- /* Offset the old point position in screen space and transform it back into 3D space. */
- const float2 new_position_screen = old_position_screen + mouse_diff * weight;
- float3 new_position;
- ED_view3d_win_to_3d(
- v3d, region, ob_mat * old_position, new_position_screen, new_position);
- new_position = ob_imat * new_position;
- positions[point_i] = new_position;
-
- curve_changed = true;
- }
- if (!curve_changed) {
- continue;
- }
- /* Ensure that the length of each segment stays the same. */
- for (const int segment_i : IndexRange(curve_points.size() - 1)) {
- const float3 &p1 = positions[curve_points[segment_i]];
- float3 &p2 = positions[curve_points[segment_i] + 1];
- const float3 direction = math::normalize(p2 - p1);
- const float desired_length = segment_lengths[segment_i];
- p2 = p1 + direction * desired_length;
- }
- }
- });
-
- curves.tag_positions_changed();
- DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
- ED_region_tag_redraw(region);
- }
-};
-
-/**
- * Drags the tip point of each curve and resamples the rest of the curve.
- */
-class SnakeHookOperation : public CurvesSculptStrokeOperation {
- private:
- float2 last_mouse_position_;
-
- public:
- void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override
- {
- BLI_SCOPED_DEFER([&]() { last_mouse_position_ = stroke_extension.mouse_position; });
-
- if (stroke_extension.is_first) {
- return;
- }
-
- Scene &scene = *CTX_data_scene(C);
- Object &object = *CTX_data_active_object(C);
- ARegion *region = CTX_wm_region(C);
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
-
- CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
- Brush &brush = *BKE_paint_brush(&curves_sculpt.paint);
- const float brush_radius = BKE_brush_size_get(&scene, &brush);
- const float brush_strength = BKE_brush_alpha_get(&scene, &brush);
-
- const float4x4 ob_mat = object.obmat;
- const float4x4 ob_imat = ob_mat.inverted();
-
- float4x4 projection;
- ED_view3d_ob_project_mat_get(rv3d, &object, projection.values);
-
- Curves &curves_id = *static_cast<Curves *>(object.data);
- CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
- MutableSpan<float3> positions = curves.positions();
-
- const float2 mouse_prev = last_mouse_position_;
- const float2 mouse_cur = stroke_extension.mouse_position;
- const float2 mouse_diff = mouse_cur - mouse_prev;
-
- threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
- for (const int curve_i : curves_range) {
- const IndexRange curve_points = curves.range_for_curve(curve_i);
- const int last_point_i = curve_points.last();
-
- const float3 old_position = positions[last_point_i];
-
- float2 old_position_screen;
- ED_view3d_project_float_v2_m4(
- region, old_position, old_position_screen, projection.values);
-
- const float distance_screen = math::distance(old_position_screen, mouse_prev);
- if (distance_screen > brush_radius) {
- continue;
- }
-
- const float radius_falloff = pow2f(1.0f - distance_screen / brush_radius);
- const float weight = brush_strength * radius_falloff;
-
- const float2 new_position_screen = old_position_screen + mouse_diff * weight;
- float3 new_position;
- ED_view3d_win_to_3d(v3d, region, ob_mat * old_position, new_position_screen, new_position);
- new_position = ob_imat * new_position;
-
- this->move_last_point_and_resample(positions, curve_points, new_position);
- }
- });
-
- curves.tag_positions_changed();
- DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
- ED_region_tag_redraw(region);
- }
-
- void move_last_point_and_resample(MutableSpan<float3> positions,
- const IndexRange curve_points,
- const float3 &new_last_point_position) const
- {
- Vector<float> old_lengths;
- old_lengths.append(0.0f);
- /* Used to (1) normalize the segment sizes over time and (2) support making zero-length
- * segments */
- const float extra_length = 0.001f;
- for (const int segment_i : IndexRange(curve_points.size() - 1)) {
- const float3 &p1 = positions[curve_points[segment_i]];
- const float3 &p2 = positions[curve_points[segment_i] + 1];
- const float length = math::distance(p1, p2);
- old_lengths.append(old_lengths.last() + length + extra_length);
- }
- Vector<float> point_factors;
- for (float &old_length : old_lengths) {
- point_factors.append(old_length / old_lengths.last());
- }
-
- PolySpline new_spline;
- new_spline.resize(curve_points.size());
- MutableSpan<float3> new_spline_positions = new_spline.positions();
- for (const int i : IndexRange(curve_points.size() - 1)) {
- new_spline_positions[i] = positions[curve_points[i]];
- }
- new_spline_positions.last() = new_last_point_position;
- new_spline.mark_cache_invalid();
-
- for (const int i : IndexRange(curve_points.size())) {
- const float factor = point_factors[i];
- const Spline::LookupResult lookup = new_spline.lookup_evaluated_factor(factor);
- const float index_factor = lookup.evaluated_index + lookup.factor;
- float3 p;
- new_spline.sample_with_index_factors<float3>(
- new_spline_positions, {&index_factor, 1}, {&p, 1});
- positions[curve_points[i]] = p;
- }
- }
-};
-
/**
* Resamples the curves to a shorter length.
*/
@@ -423,7 +117,7 @@ class ShrinkOperation : public CurvesSculptStrokeOperation {
threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
for (const int curve_i : curves_range) {
- const IndexRange curve_points = curves.range_for_curve(curve_i);
+ const IndexRange curve_points = curves.points_for_curve(curve_i);
const int last_point_i = curve_points.last();
const float3 old_tip_position = positions[last_point_i];
@@ -492,7 +186,7 @@ class ShrinkOperation : public CurvesSculptStrokeOperation {
}
};
-class AddOperation : public CurvesSculptStrokeOperation {
+class DensityAddOperation : public CurvesSculptStrokeOperation {
private:
/** Contains the root points of the curves that existed before this operation started. */
KDTree_3d *old_kdtree_ = nullptr;
@@ -513,7 +207,7 @@ class AddOperation : public CurvesSculptStrokeOperation {
};
public:
- ~AddOperation() override
+ ~DensityAddOperation() override
{
if (old_kdtree_ != nullptr) {
BLI_kdtree_3d_free(old_kdtree_);
@@ -610,7 +304,7 @@ class AddOperation : public CurvesSculptStrokeOperation {
if (old_kdtree_ == nullptr && minimum_distance > 0.0f) {
old_kdtree_ = this->kdtree_from_curve_roots_and_positions(curves, curves.curves_range(), {});
- old_kdtree_size_ = curves.curves_size();
+ old_kdtree_size_ = curves.curves_num();
}
float density;
@@ -683,13 +377,6 @@ class AddOperation : public CurvesSculptStrokeOperation {
return kdtree;
}
- int float_to_int_amount(float amount_f, RandomNumberGenerator &rng)
- {
- const float add_probability = fractf(amount_f);
- const bool add_point = add_probability > rng.get_float();
- return (int)amount_f + (int)add_point;
- }
-
bool is_too_close_to_existing_point(const float3 position, const float minimum_distance) const
{
if (old_kdtree_ == nullptr) {
@@ -744,7 +431,7 @@ class AddOperation : public CurvesSculptStrokeOperation {
* the triangle directly. If the triangle is larger than the brush, distribute new points
* in a circle on the triangle plane. */
if (looptri_area < area_threshold) {
- const int amount = this->float_to_int_amount(looptri_area * density, looptri_rng);
+ const int amount = looptri_rng.round_probabilistic(looptri_area * density);
threading::parallel_for(IndexRange(amount), 512, [&](const IndexRange amount_range) {
RandomNumberGenerator point_rng{rng_base_seed + looptri_index * 1000 +
@@ -781,7 +468,7 @@ class AddOperation : public CurvesSculptStrokeOperation {
const float radius_proj = std::sqrt(radius_proj_sq);
const float circle_area = M_PI * radius_proj_sq;
- const int amount = this->float_to_int_amount(circle_area * density, rng);
+ const int amount = rng.round_probabilistic(circle_area * density);
const float3 axis_1 = math::normalize(v1 - v0) * radius_proj;
const float3 axis_2 = math::normalize(
@@ -838,7 +525,7 @@ class AddOperation : public CurvesSculptStrokeOperation {
{
Array<bool> elimination_mask(points.positions.size(), false);
- const int curves_added_previously = curves.curves_size() - old_kdtree_size_;
+ const int curves_added_previously = curves.curves_num() - old_kdtree_size_;
KDTree_3d *new_points_kdtree = this->kdtree_from_curve_roots_and_positions(
curves, IndexRange(old_kdtree_size_, curves_added_previously), points.positions);
@@ -902,14 +589,14 @@ class AddOperation : public CurvesSculptStrokeOperation {
const int tot_new_curves = new_points.positions.size();
const int points_per_curve = 8;
- curves.resize(curves.points_size() + tot_new_curves * points_per_curve,
- curves.curves_size() + tot_new_curves);
+ curves.resize(curves.points_num() + tot_new_curves * points_per_curve,
+ curves.curves_num() + tot_new_curves);
MutableSpan<int> offsets = curves.offsets();
MutableSpan<float3> positions = curves.positions();
for (const int i : IndexRange(tot_new_curves)) {
- const int curve_i = curves.curves_size() - tot_new_curves + i;
+ const int curve_i = curves.curves_num() - tot_new_curves + i;
const int first_point_i = offsets[curve_i];
offsets[curve_i + 1] = offsets[curve_i] + points_per_curve;
@@ -932,13 +619,15 @@ static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bConte
Brush &brush = *BKE_paint_brush(&curves_sculpt.paint);
switch (brush.curves_sculpt_tool) {
case CURVES_SCULPT_TOOL_COMB:
- return std::make_unique<CombOperation>();
+ return new_comb_operation();
case CURVES_SCULPT_TOOL_DELETE:
- return std::make_unique<DeleteOperation>();
+ return new_delete_operation();
case CURVES_SCULPT_TOOL_SNAKE_HOOK:
- return std::make_unique<SnakeHookOperation>();
+ return new_snake_hook_operation();
+ case CURVES_SCULPT_TOOL_ADD:
+ return new_add_operation();
case CURVES_SCULPT_TOOL_TEST1:
- return std::make_unique<AddOperation>();
+ return std::make_unique<DensityAddOperation>();
case CURVES_SCULPT_TOOL_TEST2:
return std::make_unique<ShrinkOperation>();
}
diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
new file mode 100644
index 00000000000..682cd3b47ca
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc
@@ -0,0 +1,163 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <algorithm>
+
+#include "curves_sculpt_intern.hh"
+
+#include "BLI_float4x4.hh"
+#include "BLI_index_mask_ops.hh"
+#include "BLI_kdtree.h"
+#include "BLI_rand.hh"
+#include "BLI_vector.hh"
+
+#include "PIL_time.h"
+
+#include "DEG_depsgraph.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_brush.h"
+#include "BKE_bvhutils.h"
+#include "BKE_context.h"
+#include "BKE_curves.hh"
+#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_paint.h"
+#include "BKE_spline.hh"
+
+#include "DNA_brush_enums.h"
+#include "DNA_brush_types.h"
+#include "DNA_curves_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+namespace blender::ed::sculpt_paint {
+
+using blender::bke::CurvesGeometry;
+
+/**
+ * Drags the tip point of each curve and resamples the rest of the curve.
+ */
+class SnakeHookOperation : public CurvesSculptStrokeOperation {
+ private:
+ float2 last_mouse_position_;
+
+ public:
+ void on_stroke_extended(bContext *C, const StrokeExtension &stroke_extension) override
+ {
+ BLI_SCOPED_DEFER([&]() { last_mouse_position_ = stroke_extension.mouse_position; });
+
+ if (stroke_extension.is_first) {
+ return;
+ }
+
+ Scene &scene = *CTX_data_scene(C);
+ Object &object = *CTX_data_active_object(C);
+ ARegion *region = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
+ Brush &brush = *BKE_paint_brush(&curves_sculpt.paint);
+ const float brush_radius = BKE_brush_size_get(&scene, &brush);
+ const float brush_strength = BKE_brush_alpha_get(&scene, &brush);
+
+ const float4x4 ob_mat = object.obmat;
+ const float4x4 ob_imat = ob_mat.inverted();
+
+ float4x4 projection;
+ ED_view3d_ob_project_mat_get(rv3d, &object, projection.values);
+
+ Curves &curves_id = *static_cast<Curves *>(object.data);
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+ MutableSpan<float3> positions = curves.positions();
+
+ const float2 mouse_prev = last_mouse_position_;
+ const float2 mouse_cur = stroke_extension.mouse_position;
+ const float2 mouse_diff = mouse_cur - mouse_prev;
+
+ threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
+ for (const int curve_i : curves_range) {
+ const IndexRange curve_points = curves.points_for_curve(curve_i);
+ const int last_point_i = curve_points.last();
+
+ const float3 old_position = positions[last_point_i];
+
+ float2 old_position_screen;
+ ED_view3d_project_float_v2_m4(
+ region, old_position, old_position_screen, projection.values);
+
+ const float distance_screen = math::distance(old_position_screen, mouse_prev);
+ if (distance_screen > brush_radius) {
+ continue;
+ }
+
+ const float radius_falloff = pow2f(1.0f - distance_screen / brush_radius);
+ const float weight = brush_strength * radius_falloff;
+
+ const float2 new_position_screen = old_position_screen + mouse_diff * weight;
+ float3 new_position;
+ ED_view3d_win_to_3d(v3d, region, ob_mat * old_position, new_position_screen, new_position);
+ new_position = ob_imat * new_position;
+
+ this->move_last_point_and_resample(positions, curve_points, new_position);
+ }
+ });
+
+ curves.tag_positions_changed();
+ DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
+ ED_region_tag_redraw(region);
+ }
+
+ void move_last_point_and_resample(MutableSpan<float3> positions,
+ const IndexRange curve_points,
+ const float3 &new_last_point_position) const
+ {
+ Vector<float> old_lengths;
+ old_lengths.append(0.0f);
+ /* Used to (1) normalize the segment sizes over time and (2) support making zero-length
+ * segments */
+ const float extra_length = 0.001f;
+ for (const int segment_i : IndexRange(curve_points.size() - 1)) {
+ const float3 &p1 = positions[curve_points[segment_i]];
+ const float3 &p2 = positions[curve_points[segment_i] + 1];
+ const float length = math::distance(p1, p2);
+ old_lengths.append(old_lengths.last() + length + extra_length);
+ }
+ Vector<float> point_factors;
+ for (float &old_length : old_lengths) {
+ point_factors.append(old_length / old_lengths.last());
+ }
+
+ PolySpline new_spline;
+ new_spline.resize(curve_points.size());
+ MutableSpan<float3> new_spline_positions = new_spline.positions();
+ for (const int i : IndexRange(curve_points.size() - 1)) {
+ new_spline_positions[i] = positions[curve_points[i]];
+ }
+ new_spline_positions.last() = new_last_point_position;
+ new_spline.mark_cache_invalid();
+
+ for (const int i : IndexRange(curve_points.size())) {
+ const float factor = point_factors[i];
+ const Spline::LookupResult lookup = new_spline.lookup_evaluated_factor(factor);
+ const float index_factor = lookup.evaluated_index + lookup.factor;
+ float3 p;
+ new_spline.sample_with_index_factors<float3>(
+ new_spline_positions, {&index_factor, 1}, {&p, 1});
+ positions[curve_points[i]] = p;
+ }
+ }
+};
+
+std::unique_ptr<CurvesSculptStrokeOperation> new_snake_hook_operation()
+{
+ return std::make_unique<SnakeHookOperation>();
+}
+
+} // namespace blender::ed::sculpt_paint
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index b85d2d0aec8..5e89a4823db 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -962,6 +962,7 @@ static void sculpt_gesture_trim_normals_update(SculptGestureContext *sgcontext)
trim_mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false);
BMO_op_callf(bm,
@@ -1075,7 +1076,7 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
const int trim_totpolys = (2 * (tot_screen_points - 2)) + (2 * tot_screen_points);
trim_operation->mesh = BKE_mesh_new_nomain(
trim_totverts, 0, 0, trim_totpolys * 3, trim_totpolys);
- trim_operation->true_mesh_co = MEM_malloc_arrayN(trim_totverts, 3 * sizeof(float), "mesh orco");
+ trim_operation->true_mesh_co = MEM_malloc_arrayN(trim_totverts, sizeof(float[3]), "mesh orco");
float depth_front = trim_operation->depth_front;
float depth_back = trim_operation->depth_back;
@@ -1129,7 +1130,7 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
/* Get the triangulation for the front/back poly. */
const int tot_tris_face = tot_screen_points - 2;
- uint(*r_tris)[3] = MEM_malloc_arrayN(tot_tris_face, 3 * sizeof(uint), "tris");
+ uint(*r_tris)[3] = MEM_malloc_arrayN(tot_tris_face, sizeof(uint[3]), "tris");
BLI_polyfill_calc(screen_points, tot_screen_points, 0, r_tris);
/* Write the front face triangle indices. */
@@ -1214,12 +1215,14 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
trim_mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
BM_mesh_bm_from_me(bm,
sculpt_mesh,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
const int looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 1705e36363e..0f7b8ad1f3d 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -792,7 +792,7 @@ static int paint_space_stroke(bContext *C,
Paint *paint = BKE_paint_get_active_from_context(C);
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
- int cnt = 0;
+ int count = 0;
const bool use_scene_spacing = paint_stroke_use_scene_spacing(brush, mode);
float d_world_space_position[3] = {0.0f};
@@ -855,14 +855,14 @@ static int paint_space_stroke(bContext *C,
pressure = stroke->last_pressure;
dpressure = final_pressure - stroke->last_pressure;
- cnt++;
+ count++;
}
else {
break;
}
}
- return cnt;
+ return count;
}
/**** Public API ****/
@@ -986,6 +986,11 @@ static void stroke_done(bContext *C, wmOperator *op, PaintStroke *stroke)
paint_stroke_free(C, op, stroke);
}
+static bool curves_sculpt_brush_uses_spacing(const eBrushCurvesSculptTool tool)
+{
+ return ELEM(tool, CURVES_SCULPT_TOOL_ADD);
+}
+
bool paint_space_stroke_enabled(Brush *br, ePaintMode mode)
{
if ((br->flag & BRUSH_SPACE) == 0) {
@@ -1000,7 +1005,8 @@ bool paint_space_stroke_enabled(Brush *br, ePaintMode mode)
return true;
}
- if (mode == PAINT_MODE_SCULPT_CURVES) {
+ if (mode == PAINT_MODE_SCULPT_CURVES &&
+ !curves_sculpt_brush_uses_spacing(br->curves_sculpt_tool)) {
return false;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index 70f8f2127b4..8bf09ce3d05 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -532,9 +532,8 @@ static void sculpt_boundary_bend_data_init(SculptSession *ss, SculptBoundary *bo
{
const int totvert = SCULPT_vertex_count_get(ss);
boundary->bend.pivot_rotation_axis = MEM_calloc_arrayN(
- totvert, 3 * sizeof(float), "pivot rotation axis");
- boundary->bend.pivot_positions = MEM_calloc_arrayN(
- totvert, 3 * sizeof(float), "pivot positions");
+ totvert, sizeof(float[3]), "pivot rotation axis");
+ boundary->bend.pivot_positions = MEM_calloc_arrayN(totvert, sizeof(float[3]), "pivot positions");
for (int i = 0; i < totvert; i++) {
if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) {
@@ -567,7 +566,7 @@ static void sculpt_boundary_bend_data_init(SculptSession *ss, SculptBoundary *bo
static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *boundary)
{
const int totvert = SCULPT_vertex_count_get(ss);
- boundary->slide.directions = MEM_calloc_arrayN(totvert, 3 * sizeof(float), "slide directions");
+ boundary->slide.directions = MEM_calloc_arrayN(totvert, sizeof(float[3]), "slide directions");
for (int i = 0; i < totvert; i++) {
if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) {
@@ -592,7 +591,7 @@ static void sculpt_boundary_twist_data_init(SculptSession *ss, SculptBoundary *b
{
zero_v3(boundary->twist.pivot_position);
float(*poly_verts)[3] = MEM_malloc_arrayN(
- boundary->num_vertices, sizeof(float) * 3, "poly verts");
+ boundary->num_vertices, sizeof(float[3]), "poly verts");
for (int i = 0; i < boundary->num_vertices; i++) {
add_v3_v3(boundary->twist.pivot_position, SCULPT_vertex_co_get(ss, boundary->vertices[i]));
copy_v3_v3(poly_verts[i], SCULPT_vertex_co_get(ss, boundary->vertices[i]));
diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
index 0e26eb9b4b6..58da5adc5e3 100644
--- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
@@ -147,6 +147,7 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
me,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
.use_shapekey = true,
.active_shapekey = ob->shapenr,
}));
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
index 5f6b8bf9b19..23bc9fbb54d 100644
--- a/source/blender/editors/sculpt_paint/sculpt_face_set.c
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -379,6 +379,7 @@ static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
BMIter iter;
@@ -574,6 +575,7 @@ static void sculpt_face_sets_init_flood_fill(Object *ob,
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
BLI_bitmap *visited_faces = BLI_BITMAP_NEW(mesh->totpoly, "visited faces");
@@ -652,6 +654,7 @@ static void sculpt_face_sets_init_loop(Object *ob, const int mode)
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
BMIter iter;
BMFace *f;
@@ -1184,6 +1187,7 @@ static void sculpt_face_set_delete_geometry(Object *ob,
mesh,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
BM_mesh_elem_table_init(bm, BM_FACE);
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
index 858c6c4e279..482bdf97d78 100644
--- a/source/blender/editors/sculpt_paint/sculpt_smooth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -251,7 +251,7 @@ static void SCULPT_enhance_details_brush(Sculpt *sd,
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
const int totvert = SCULPT_vertex_count_get(ss);
ss->cache->detail_directions = MEM_malloc_arrayN(
- totvert, 3 * sizeof(float), "details directions");
+ totvert, sizeof(float[3]), "details directions");
for (int i = 0; i < totvert; i++) {
float avg[3];
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index f0ada312d82..d33cf70e117 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -1706,8 +1706,8 @@ static const EnumPropertyItem prop_actkeys_snap_types[] = {
"NEAREST_FRAME",
0,
"Selection to Nearest Frame",
- "Snap selected keyframes to the nearest (whole) frame (use to fix accidental subframe "
- "offsets)"},
+ "Snap selected keyframes to the nearest (whole) frame "
+ "(use to fix accidental sub-frame offsets)"},
{ACTKEYS_SNAP_NEAREST_SECOND,
"NEAREST_SECOND",
0,
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 20e9d21455f..7eba3d49616 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -170,12 +170,8 @@ static void action_main_region_draw(const bContext *C, ARegion *region)
bAnimContext ac;
View2D *v2d = &region->v2d;
short marker_flag = 0;
- short cfra_flag = 0;
UI_view2d_view_ortho(v2d);
- if (saction->flag & SACTION_DRAWTIME) {
- cfra_flag |= DRAWCFRA_UNIT_SECONDS;
- }
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 0d1ff71e567..e7bdbfe7c68 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -271,7 +271,6 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
const int framenr = ED_space_clip_get_clip_frame_number(sc);
- bool has_selection = false;
bool changed = false;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
@@ -281,7 +280,6 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
if (TRACK_VIEW_SELECTED(sc, track)) {
MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
if (marker != NULL) {
- has_selection |= track->markersnr > 1;
clip_delete_marker(C, clip, track, marker);
changed = true;
}
@@ -878,24 +876,24 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
BKE_tracking_marker_clamp(data->marker, CLAMP_PAT_DIM);
}
else if (data->action == SLIDE_ACTION_TILT_SIZE) {
- float start[2], end[2];
- float scale = 1.0f, angle = 0.0f;
- float mval[2];
-
- if (data->accurate) {
- mval[0] = data->mval[0] + (event->mval[0] - data->mval[0]) / 5.0f;
- mval[1] = data->mval[1] + (event->mval[1] - data->mval[1]) / 5.0f;
- }
- else {
- mval[0] = event->mval[0];
- mval[1] = event->mval[1];
- }
+ const float mouse_delta[2] = {dx, dy};
+ /* Vector which connects marker position with tilt/scale sliding area before sliding
+ * began. */
+ float start[2];
sub_v2_v2v2(start, data->spos, data->old_pos);
+ start[0] *= data->width;
+ start[1] *= data->height;
- ED_clip_point_stable_pos(sc, region, mval[0], mval[1], &end[0], &end[1]);
+ /* Vector which connects marker position with tilt/scale sliding area with the sliding
+ * delta applied. */
+ float end[2];
+ add_v2_v2v2(end, data->spos, mouse_delta);
sub_v2_v2(end, data->old_pos);
+ end[0] *= data->width;
+ end[1] *= data->height;
+ float scale = 1.0f;
if (len_squared_v2(start) != 0.0f) {
scale = len_v2(end) / len_v2(start);
@@ -904,7 +902,7 @@ static int slide_marker_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
- angle = -angle_signed_v2v2(start, end);
+ const float angle = -angle_signed_v2v2(start, end);
for (int a = 0; a < 4; a++) {
float vec[2];
diff --git a/source/blender/editors/space_clip/tracking_ops_track.c b/source/blender/editors/space_clip/tracking_ops_track.c
index f9cbce40deb..d5223d57490 100644
--- a/source/blender/editors/space_clip/tracking_ops_track.c
+++ b/source/blender/editors/space_clip/tracking_ops_track.c
@@ -211,6 +211,8 @@ static void track_markers_startjob(
TrackMarkersJob *tmj = (TrackMarkersJob *)tmv;
int framenr = tmj->sfra;
+ BKE_autotrack_context_start(tmj->context);
+
while (framenr != tmj->efra) {
if (tmj->delay > 0) {
/* Tracking should happen with fixed fps. Calculate time
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index c4c6fa01025..b8c28e354da 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -79,6 +79,9 @@ if(WITH_IMAGE_HDR)
add_definitions(-DWITH_HDR)
endif()
+if(WITH_IMAGE_WEBP)
+ add_definitions(-DWITH_WEBP)
+endif()
if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 363e19a8905..ceac53bde6b 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -851,6 +851,20 @@ static bool is_filtered_file_relpath(const FileListInternEntry *file, const File
return fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) == 0;
}
+/**
+ * Apply the filter string as matching pattern on file name.
+ * \return true when the file should be in the result set, false if it should be filtered out.
+ */
+static bool is_filtered_file_name(const FileListInternEntry *file, const FileListFilter *filter)
+{
+ if (filter->filter_search[0] == '\0') {
+ return true;
+ }
+
+ /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */
+ return fnmatch(filter->filter_search, file->name, FNM_CASEFOLD) == 0;
+}
+
/** \return true when the file should be in the result set, false if it should be filtered out. */
static bool is_filtered_file_type(const FileListInternEntry *file, const FileListFilter *filter)
{
@@ -890,7 +904,8 @@ static bool is_filtered_file(FileListInternEntry *file,
const char *UNUSED(root),
FileListFilter *filter)
{
- return is_filtered_file_type(file, filter) && is_filtered_file_relpath(file, filter);
+ return is_filtered_file_type(file, filter) &&
+ (is_filtered_file_relpath(file, filter) || is_filtered_file_name(file, filter));
}
static bool is_filtered_id_file_type(const FileListInternEntry *file,
@@ -1041,10 +1056,10 @@ void filelist_tag_needs_filtering(FileList *filelist)
void filelist_filter(FileList *filelist)
{
int num_filtered = 0;
- const int num_files = filelist->filelist.nbr_entries;
+ const int num_files = filelist->filelist.entries_num;
FileListInternEntry **filtered_tmp, *file;
- if (ELEM(filelist->filelist.nbr_entries, FILEDIR_NBR_ENTRIES_UNSET, 0)) {
+ if (ELEM(filelist->filelist.entries_num, FILEDIR_NBR_ENTRIES_UNSET, 0)) {
return;
}
@@ -1084,8 +1099,8 @@ void filelist_filter(FileList *filelist)
memcpy(filelist->filelist_intern.filtered,
filtered_tmp,
sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered);
- filelist->filelist.nbr_entries_filtered = num_filtered;
- // printf("Filetered: %d over %d entries\n", num_filtered, filelist->filelist.nbr_entries);
+ filelist->filelist.entries_filtered_num = num_filtered;
+ // printf("Filetered: %d over %d entries\n", num_filtered, filelist->filelist.entries_num);
filelist_cache_clear(&filelist->filelist_cache, filelist->filelist_cache.size);
filelist->flags &= ~FL_NEED_FILTERING;
@@ -1537,8 +1552,8 @@ static void filelist_direntryarr_free(FileDirEntryArr *array)
#else
BLI_assert(BLI_listbase_is_empty(&array->entries));
#endif
- array->nbr_entries = FILEDIR_NBR_ENTRIES_UNSET;
- array->nbr_entries_filtered = FILEDIR_NBR_ENTRIES_UNSET;
+ array->entries_num = FILEDIR_NBR_ENTRIES_UNSET;
+ array->entries_filtered_num = FILEDIR_NBR_ENTRIES_UNSET;
}
static void filelist_intern_entry_free(FileListInternEntry *entry)
@@ -1859,7 +1874,7 @@ FileList *filelist_new(short type)
filelist_cache_init(&p->filelist_cache, FILELIST_ENTRYCACHESIZE_DEFAULT);
p->selection_state = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
- p->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET;
+ p->filelist.entries_num = FILEDIR_NBR_ENTRIES_UNSET;
filelist_settype(p, type);
return p;
@@ -1964,9 +1979,9 @@ static void filelist_clear_main_files(FileList *filelist,
const int removed_files = filelist_intern_free_main_files(&filelist->filelist_intern);
- filelist->filelist.nbr_entries -= removed_files;
- filelist->filelist.nbr_entries_filtered = FILEDIR_NBR_ENTRIES_UNSET;
- BLI_assert(filelist->filelist.nbr_entries > FILEDIR_NBR_ENTRIES_UNSET);
+ filelist->filelist.entries_num -= removed_files;
+ filelist->filelist.entries_filtered_num = FILEDIR_NBR_ENTRIES_UNSET;
+ BLI_assert(filelist->filelist.entries_num > FILEDIR_NBR_ENTRIES_UNSET);
if (do_selection && filelist->selection_state) {
BLI_ghash_clear(filelist->selection_state, NULL, NULL);
@@ -2152,7 +2167,7 @@ int filelist_files_ensure(FileList *filelist)
filelist_filter(filelist);
}
- return filelist->filelist.nbr_entries_filtered;
+ return filelist->filelist.entries_filtered_num;
}
static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int index)
@@ -2211,7 +2226,7 @@ FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const
const size_t cache_size = cache->size;
int old_index;
- if ((index < 0) || (index >= filelist->filelist.nbr_entries_filtered)) {
+ if ((index < 0) || (index >= filelist->filelist.entries_filtered_num)) {
return ret;
}
@@ -2259,7 +2274,7 @@ FileDirEntry *filelist_file(struct FileList *filelist, int index)
int filelist_file_find_path(struct FileList *filelist, const char *filename)
{
- if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) {
+ if (filelist->filelist.entries_filtered_num == FILEDIR_NBR_ENTRIES_UNSET) {
return -1;
}
@@ -2267,7 +2282,7 @@ int filelist_file_find_path(struct FileList *filelist, const char *filename)
* This is only used to find again renamed entry,
* annoying but looks hairy to get rid of it currently. */
- for (int fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) {
+ for (int fidx = 0; fidx < filelist->filelist.entries_filtered_num; fidx++) {
FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx];
if (STREQ(entry->relpath, filename)) {
return fidx;
@@ -2279,11 +2294,11 @@ int filelist_file_find_path(struct FileList *filelist, const char *filename)
int filelist_file_find_id(const FileList *filelist, const ID *id)
{
- if (filelist->filelist.nbr_entries_filtered == FILEDIR_NBR_ENTRIES_UNSET) {
+ if (filelist->filelist.entries_filtered_num == FILEDIR_NBR_ENTRIES_UNSET) {
return -1;
}
- for (int fidx = 0; fidx < filelist->filelist.nbr_entries_filtered; fidx++) {
+ for (int fidx = 0; fidx < filelist->filelist.entries_filtered_num; fidx++) {
FileListInternEntry *entry = filelist->filelist_intern.filtered[fidx];
if (entry->local_data.id == id) {
return fidx;
@@ -2393,23 +2408,23 @@ bool filelist_file_cache_block(struct FileList *filelist, const int index)
FileListEntryCache *cache = &filelist->filelist_cache;
const size_t cache_size = cache->size;
- const int nbr_entries = filelist->filelist.nbr_entries_filtered;
+ const int entries_num = filelist->filelist.entries_filtered_num;
int start_index = max_ii(0, index - (cache_size / 2));
- int end_index = min_ii(nbr_entries, index + (cache_size / 2));
+ int end_index = min_ii(entries_num, index + (cache_size / 2));
int i;
const bool full_refresh = (filelist->flags & FL_IS_READY) == 0;
- if ((index < 0) || (index >= nbr_entries)) {
- // printf("Wrong index %d ([%d:%d])", index, 0, nbr_entries);
+ if ((index < 0) || (index >= entries_num)) {
+ // printf("Wrong index %d ([%d:%d])", index, 0, entries_num);
return false;
}
/* Maximize cached range! */
if ((end_index - start_index) < cache_size) {
if (start_index == 0) {
- end_index = min_ii(nbr_entries, start_index + cache_size);
+ end_index = min_ii(entries_num, start_index + cache_size);
}
- else if (end_index == nbr_entries) {
+ else if (end_index == entries_num) {
start_index = max_ii(0, end_index - cache_size);
}
}
@@ -2846,7 +2861,7 @@ int ED_file_extension_icon(const char *path)
int filelist_needs_reading(FileList *filelist)
{
- return (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET) ||
+ return (filelist->filelist.entries_num == FILEDIR_NBR_ENTRIES_UNSET) ||
filelist_needs_force_reset(filelist);
}
@@ -2911,8 +2926,8 @@ void filelist_entries_select_index_range_set(
FileList *filelist, FileSelection *sel, FileSelType select, uint flag, FileCheckType check)
{
/* select all valid files between first and last indicated */
- if ((sel->first >= 0) && (sel->first < filelist->filelist.nbr_entries_filtered) &&
- (sel->last >= 0) && (sel->last < filelist->filelist.nbr_entries_filtered)) {
+ if ((sel->first >= 0) && (sel->first < filelist->filelist.entries_filtered_num) &&
+ (sel->last >= 0) && (sel->last < filelist->filelist.entries_filtered_num)) {
int current_file;
for (current_file = sel->first; current_file <= sel->last; current_file++) {
filelist_entry_select_index_set(filelist, current_file, select, flag, check);
@@ -2948,7 +2963,7 @@ uint filelist_entry_select_index_get(FileList *filelist, const int index, FileCh
bool filelist_entry_is_selected(FileList *filelist, const int index)
{
- BLI_assert(index >= 0 && index < filelist->filelist.nbr_entries_filtered);
+ BLI_assert(index >= 0 && index < filelist->filelist.entries_filtered_num);
FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index];
/* BLI_ghash_lookup returns NULL if not found, which gets mapped to 0, which gets mapped to
@@ -3015,13 +3030,13 @@ static int filelist_readjob_list_dir(const char *root,
const bool skip_currpar)
{
struct direntry *files;
- int nbr_files, nbr_entries = 0;
+ int entries_num = 0;
/* Full path of the item. */
char full_path[FILE_MAX];
- nbr_files = BLI_filelist_dir_contents(root, &files);
+ const int files_num = BLI_filelist_dir_contents(root, &files);
if (files) {
- int i = nbr_files;
+ int i = files_num;
while (i--) {
FileListInternEntry *entry;
@@ -3095,11 +3110,11 @@ static int filelist_readjob_list_dir(const char *root,
#endif
BLI_addtail(entries, entry);
- nbr_entries++;
+ entries_num++;
}
- BLI_filelist_free(files, nbr_files);
+ BLI_filelist_free(files, files_num);
}
- return nbr_entries;
+ return entries_num;
}
typedef enum ListLibOptions {
@@ -3355,13 +3370,13 @@ static void filelist_readjob_main_recursive(Main *bmain, FileList *filelist)
if (filelist->dir[0] == 0) {
/* make directories */
# ifdef WITH_FREESTYLE
- filelist->filelist.nbr_entries = 27;
+ filelist->filelist.entries_num = 27;
# else
- filelist->filelist.nbr_entries = 26;
+ filelist->filelist.entries_num = 26;
# endif
- filelist_resize(filelist, filelist->filelist.nbr_entries);
+ filelist_resize(filelist, filelist->filelist.entries_num);
- for (a = 0; a < filelist->filelist.nbr_entries; a++) {
+ for (a = 0; a < filelist->filelist.entries_num; a++) {
filelist->filelist.entries[a].typeflag |= FILE_TYPE_DIR;
}
@@ -3404,20 +3419,20 @@ static void filelist_readjob_main_recursive(Main *bmain, FileList *filelist)
return;
}
- filelist->filelist.nbr_entries = 0;
+ filelist->filelist.entries_num = 0;
for (id = lb->first; id; id = id->next) {
if (!(filelist->filter_data.flags & FLF_HIDE_DOT) || id->name[2] != '.') {
- filelist->filelist.nbr_entries++;
+ filelist->filelist.entries_num++;
}
}
/* XXX TODO: if data-browse or append/link #FLF_HIDE_PARENT has to be set. */
if (!(filelist->filter_data.flags & FLF_HIDE_PARENT)) {
- filelist->filelist.nbr_entries++;
+ filelist->filelist.entries_num++;
}
- if (filelist->filelist.nbr_entries > 0) {
- filelist_resize(filelist, filelist->filelist.nbr_entries);
+ if (filelist->filelist.entries_num > 0) {
+ filelist_resize(filelist, filelist->filelist.entries_num);
}
files = filelist->filelist.entries;
@@ -3523,11 +3538,11 @@ typedef struct FileListReadJob {
static void filelist_readjob_append_entries(FileListReadJob *job_params,
ListBase *from_entries,
- int nbr_from_entries,
+ int from_entries_num,
short *do_update)
{
- BLI_assert(BLI_listbase_count(from_entries) == nbr_from_entries);
- if (nbr_from_entries <= 0) {
+ BLI_assert(BLI_listbase_count(from_entries) == from_entries_num);
+ if (from_entries_num <= 0) {
*do_update = false;
return;
}
@@ -3535,7 +3550,7 @@ static void filelist_readjob_append_entries(FileListReadJob *job_params,
FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
BLI_mutex_lock(&job_params->lock);
BLI_movelisttolist(&filelist->filelist.entries, from_entries);
- filelist->filelist.nbr_entries += nbr_from_entries;
+ filelist->filelist.entries_num += from_entries_num;
BLI_mutex_unlock(&job_params->lock);
*do_update = true;
@@ -3591,7 +3606,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
char filter_glob[FILE_MAXFILE];
const char *root = filelist->filelist.root;
const int max_recursion = filelist->max_recursion;
- int nbr_done_dirs = 0, nbr_todo_dirs = 1;
+ int dirs_done_count = 0, dirs_todo_count = 1;
todo_dirs = BLI_stack_new(sizeof(*td_dir), __func__);
td_dir = BLI_stack_push_r(todo_dirs);
@@ -3611,7 +3626,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) {
FileListInternEntry *entry;
- int nbr_entries = 0;
+ int entries_num = 0;
char *subdir;
char rel_subdir[FILE_MAX_LIBEXTRA];
@@ -3651,15 +3666,15 @@ 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(
+ entries_num = filelist_readjob_list_lib(
subdir, &entries, list_lib_options, &indexer_runtime);
- if (nbr_entries > 0) {
+ if (entries_num > 0) {
is_lib = true;
}
}
if (!is_lib) {
- nbr_entries = filelist_readjob_list_dir(
+ entries_num = filelist_readjob_list_dir(
subdir, &entries, filter_glob, do_lib, job_params->main_name, skip_currpar);
}
@@ -3683,14 +3698,14 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib,
td_dir = BLI_stack_push_r(todo_dirs);
td_dir->level = recursion_level + 1;
td_dir->dir = BLI_strdup(dir);
- nbr_todo_dirs++;
+ dirs_todo_count++;
}
}
- filelist_readjob_append_entries(job_params, &entries, nbr_entries, do_update);
+ filelist_readjob_append_entries(job_params, &entries, entries_num, do_update);
- nbr_done_dirs++;
- *progress = (float)nbr_done_dirs / (float)nbr_todo_dirs;
+ dirs_done_count++;
+ *progress = (float)dirs_done_count / (float)dirs_todo_count;
MEM_freeN(subdir);
}
@@ -3723,10 +3738,10 @@ static void filelist_readjob_do(const bool do_lib,
// BLI_assert(filelist->filtered == NULL);
BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) &&
- (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET));
+ (filelist->filelist.entries_num == FILEDIR_NBR_ENTRIES_UNSET));
/* A valid, but empty directory from now. */
- filelist->filelist.nbr_entries = 0;
+ filelist->filelist.entries_num = 0;
filelist_readjob_recursive_dir_add_items(do_lib, job_params, stop, do_update, progress);
}
@@ -3797,7 +3812,7 @@ static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params,
FileListInternEntry *entry;
ListBase tmp_entries = {0};
ID *id_iter;
- int nbr_entries = 0;
+ int entries_num = 0;
/* Make sure no IDs are added/removed/reallocated in the main thread while this is running in
* parallel. */
@@ -3820,19 +3835,19 @@ static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params,
entry->local_data.preview_image = BKE_asset_metadata_preview_get_from_id(id_iter->asset_data,
id_iter);
entry->local_data.id = id_iter;
- nbr_entries++;
+ entries_num++;
BLI_addtail(&tmp_entries, entry);
}
FOREACH_MAIN_ID_END;
BKE_main_unlock(job_params->current_main);
- if (nbr_entries) {
+ if (entries_num) {
*do_update = true;
BLI_movelisttolist(&filelist->filelist.entries, &tmp_entries);
- filelist->filelist.nbr_entries += nbr_entries;
- filelist->filelist.nbr_entries_filtered = -1;
+ filelist->filelist.entries_num += entries_num;
+ filelist->filelist.entries_filtered_num = -1;
}
}
@@ -3857,10 +3872,10 @@ static void filelist_readjob_asset_library(FileListReadJob *job_params,
FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) &&
- (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET));
+ (filelist->filelist.entries_num == FILEDIR_NBR_ENTRIES_UNSET));
/* A valid, but empty file-list from now. */
- filelist->filelist.nbr_entries = 0;
+ filelist->filelist.entries_num = 0;
/* NOP if already read. */
filelist_readjob_load_asset_library_data(job_params, do_update);
@@ -3889,12 +3904,12 @@ static void filelist_readjob_main_assets(FileListReadJob *job_params,
{
FileList *filelist = job_params->tmp_filelist; /* Use the thread-safe filelist queue. */
BLI_assert(BLI_listbase_is_empty(&filelist->filelist.entries) &&
- (filelist->filelist.nbr_entries == FILEDIR_NBR_ENTRIES_UNSET));
+ (filelist->filelist.entries_num == FILEDIR_NBR_ENTRIES_UNSET));
filelist_readjob_load_asset_library_data(job_params, do_update);
/* A valid, but empty file-list from now. */
- filelist->filelist.nbr_entries = 0;
+ filelist->filelist.entries_num = 0;
filelist_readjob_main_assets_add_items(job_params, stop, do_update, progress);
}
@@ -3917,7 +3932,7 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update
FileListReadJob *flrj = flrjv;
// printf("START filelist reading (%d files, main thread: %d)\n",
- // flrj->filelist->filelist.nbr_entries, BLI_thread_is_main());
+ // flrj->filelist->filelist.entries_num, BLI_thread_is_main());
BLI_mutex_lock(&flrj->lock);
@@ -3926,7 +3941,7 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update
flrj->tmp_filelist = MEM_dupallocN(flrj->filelist);
BLI_listbase_clear(&flrj->tmp_filelist->filelist.entries);
- flrj->tmp_filelist->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET;
+ flrj->tmp_filelist->filelist.entries_num = FILEDIR_NBR_ENTRIES_UNSET;
flrj->tmp_filelist->filelist_intern.filtered = NULL;
BLI_listbase_clear(&flrj->tmp_filelist->filelist_intern.entries);
@@ -3958,18 +3973,18 @@ static void filelist_readjob_update(void *flrjv)
FileListReadJob *flrj = flrjv;
FileListIntern *fl_intern = &flrj->filelist->filelist_intern;
ListBase new_entries = {NULL};
- int nbr_entries, new_nbr_entries = 0;
+ int entries_num, new_entries_num = 0;
BLI_movelisttolist(&new_entries, &fl_intern->entries);
- nbr_entries = flrj->filelist->filelist.nbr_entries;
+ entries_num = flrj->filelist->filelist.entries_num;
BLI_mutex_lock(&flrj->lock);
- if (flrj->tmp_filelist->filelist.nbr_entries > 0) {
+ if (flrj->tmp_filelist->filelist.entries_num > 0) {
/* We just move everything out of 'thread context' into final list. */
- new_nbr_entries = flrj->tmp_filelist->filelist.nbr_entries;
+ new_entries_num = flrj->tmp_filelist->filelist.entries_num;
BLI_movelisttolist(&new_entries, &flrj->tmp_filelist->filelist.entries);
- flrj->tmp_filelist->filelist.nbr_entries = 0;
+ flrj->tmp_filelist->filelist.entries_num = 0;
}
if (flrj->tmp_filelist->asset_library) {
@@ -3983,7 +3998,7 @@ static void filelist_readjob_update(void *flrjv)
BLI_mutex_unlock(&flrj->lock);
- if (new_nbr_entries) {
+ if (new_entries_num) {
/* Do not clear selection cache, we can assume already 'selected' UIDs are still valid! Keep
* the asset library data we just read. */
filelist_clear_ex(flrj->filelist, false, true, false);
@@ -3991,9 +4006,9 @@ static void filelist_readjob_update(void *flrjv)
flrj->filelist->flags |= (FL_NEED_SORTING | FL_NEED_FILTERING);
}
- /* if no new_nbr_entries, this is NOP */
+ /* if no new_entries_num, this is NOP */
BLI_movelisttolist(&fl_intern->entries, &new_entries);
- flrj->filelist->filelist.nbr_entries = MAX2(nbr_entries, 0) + new_nbr_entries;
+ flrj->filelist->filelist.entries_num = MAX2(entries_num, 0) + new_entries_num;
}
static void filelist_readjob_endjob(void *flrjv)
@@ -4011,11 +4026,11 @@ static void filelist_readjob_free(void *flrjv)
{
FileListReadJob *flrj = flrjv;
- // printf("END filelist reading (%d files)\n", flrj->filelist->filelist.nbr_entries);
+ // printf("END filelist reading (%d files)\n", flrj->filelist->filelist.entries_num);
if (flrj->tmp_filelist) {
/* tmp_filelist shall never ever be filtered! */
- BLI_assert(flrj->tmp_filelist->filelist.nbr_entries == 0);
+ BLI_assert(flrj->tmp_filelist->filelist.entries_num == 0);
BLI_assert(BLI_listbase_is_empty(&flrj->tmp_filelist->filelist.entries));
filelist_freelib(flrj->tmp_filelist);
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 847bf89bba8..ae0e5b23d55 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -968,13 +968,13 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
/* Check gvfs shares. */
const char *const xdg_runtime_dir = BLI_getenv("XDG_RUNTIME_DIR");
if (xdg_runtime_dir != NULL) {
- struct direntry *dir;
+ struct direntry *dirs;
char name[FILE_MAX];
BLI_join_dirfile(name, sizeof(name), xdg_runtime_dir, "gvfs/");
- const uint dir_len = BLI_filelist_dir_contents(name, &dir);
- for (uint i = 0; i < dir_len; i++) {
- if (dir[i].type & S_IFDIR) {
- const char *dirname = dir[i].relname;
+ const uint dirs_num = BLI_filelist_dir_contents(name, &dirs);
+ for (uint i = 0; i < dirs_num; i++) {
+ if (dirs[i].type & S_IFDIR) {
+ const char *dirname = dirs[i].relname;
if (dirname[0] != '.') {
/* Dir names contain a lot of unwanted text.
* Assuming every entry ends with the share name */
@@ -992,7 +992,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
}
}
}
- BLI_filelist_free(dir, dir_len);
+ BLI_filelist_free(dirs, dirs_num);
}
# endif
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index fe8005892cf..2eb64e5b115 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -113,6 +113,7 @@ void GRAPH_OT_clean(struct wmOperatorType *ot);
void GRAPH_OT_blend_to_neighbor(struct wmOperatorType *ot);
void GRAPH_OT_breakdown(struct wmOperatorType *ot);
void GRAPH_OT_decimate(struct wmOperatorType *ot);
+void GRAPH_OT_blend_to_default(struct wmOperatorType *ot);
void GRAPH_OT_sample(struct wmOperatorType *ot);
void GRAPH_OT_bake(struct wmOperatorType *ot);
void GRAPH_OT_unbake(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index b00e069470d..128925d4591 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -457,6 +457,7 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_decimate);
WM_operatortype_append(GRAPH_OT_blend_to_neighbor);
WM_operatortype_append(GRAPH_OT_breakdown);
+ WM_operatortype_append(GRAPH_OT_blend_to_default);
WM_operatortype_append(GRAPH_OT_euler_filter);
WM_operatortype_append(GRAPH_OT_delete);
WM_operatortype_append(GRAPH_OT_duplicate);
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index 1a3355b0139..313f6ca1561 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -550,7 +550,7 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Blend To Neighbor Operator
+/** \name Blend to Neighbor Operator
* \{ */
static void blend_to_neighbor_graph_keys(bAnimContext *ac, float factor)
@@ -584,7 +584,7 @@ static void blend_to_neighbor_draw_status_header(bContext *C, tGraphSliderOp *gs
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
- strcpy(mode_str, TIP_("Blend To Neighbor"));
+ strcpy(mode_str, TIP_("Blend to Neighbor"));
if (hasNumInput(&gso->num)) {
char str_ofs[NUM_STR_REP_LEN];
@@ -652,7 +652,7 @@ static int blend_to_neighbor_exec(bContext *C, wmOperator *op)
void GRAPH_OT_blend_to_neighbor(wmOperatorType *ot)
{
/* Identifiers. */
- ot->name = "Blend To Neighbor";
+ ot->name = "Blend to Neighbor";
ot->idname = "GRAPH_OT_blend_to_neighbor";
ot->description = "Blend selected keyframes to their left or right neighbor";
@@ -802,3 +802,131 @@ void GRAPH_OT_breakdown(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend to Default Value Operator
+ * \{ */
+
+static void blend_to_default_graph_keys(bAnimContext *ac, const float factor)
+{
+ ListBase anim_data = {NULL, NULL};
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
+
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+
+ /* Check if the curves actually have any points. */
+ if (fcu == NULL || fcu->bezt == NULL || fcu->totvert == 0) {
+ continue;
+ }
+
+ PointerRNA id_ptr;
+ RNA_id_pointer_create(ale->id, &id_ptr);
+
+ blend_to_default_fcurve(&id_ptr, fcu, factor);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
+static void blend_to_default_draw_status_header(bContext *C, tGraphSliderOp *gso)
+{
+ char status_str[UI_MAX_DRAW_STR];
+ char mode_str[32];
+ char slider_string[UI_MAX_DRAW_STR];
+
+ ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
+
+ strcpy(mode_str, TIP_("Blend to Default Value"));
+
+ if (hasNumInput(&gso->num)) {
+ char str_ofs[NUM_STR_REP_LEN];
+
+ outputNumInput(&gso->num, str_ofs, &gso->scene->unit);
+
+ 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);
+ }
+
+ ED_workspace_status_text(C, status_str);
+}
+
+static void blend_to_default_modal_update(bContext *C, wmOperator *op)
+{
+ tGraphSliderOp *gso = op->customdata;
+
+ blend_to_default_draw_status_header(C, gso);
+
+ /* Set notifier that keyframes have changed. */
+ reset_bezts(gso);
+ const float factor = ED_slider_factor_get(gso->slider);
+ RNA_property_float_set(op->ptr, gso->factor_prop, factor);
+ blend_to_default_graph_keys(&gso->ac, factor);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+}
+
+static int blend_to_default_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const int invoke_result = graph_slider_invoke(C, op, event);
+
+ if (invoke_result == OPERATOR_CANCELLED) {
+ return invoke_result;
+ }
+
+ tGraphSliderOp *gso = op->customdata;
+ gso->modal_update = blend_to_default_modal_update;
+ gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
+ blend_to_default_draw_status_header(C, gso);
+
+ return invoke_result;
+}
+
+static int blend_to_default_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ if (ANIM_animdata_get_context(C, &ac) == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const float factor = RNA_float_get(op->ptr, "factor");
+
+ blend_to_default_graph_keys(&ac, factor);
+
+ /* Set notifier that keyframes have changed. */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GRAPH_OT_blend_to_default(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Blend to Default Value";
+ ot->idname = "GRAPH_OT_blend_to_default";
+ ot->description = "Blend selected keys to their default value from their current position";
+
+ /* API callbacks. */
+ ot->invoke = blend_to_default_invoke;
+ ot->modal = graph_slider_modal;
+ ot->exec = blend_to_default_exec;
+ ot->poll = graphop_editable_keyframes_poll;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_float_factor(ot->srna,
+ "factor",
+ 1.0f / 3.0f,
+ -FLT_MAX,
+ FLT_MAX,
+ "Factor",
+ "How much to blend to the default value",
+ 0.0f,
+ 1.0f);
+}
+/** \} */
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index f5cc6083b25..c385420b18e 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -60,6 +60,9 @@ if(WITH_IMAGE_CINEON)
add_definitions(-DWITH_CINEON)
endif()
+if(WITH_IMAGE_WEBP)
+ add_definitions(-DWITH_WEBP)
+endif()
blender_add_lib(bf_editor_space_image "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 0af32a717a4..208928afc1f 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -20,6 +20,7 @@
#include "BKE_context.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_node.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -957,14 +958,11 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma
{
ImageFormatData *imf = imfptr->data;
ID *id = imfptr->owner_id;
- PointerRNA display_settings_ptr;
- PropertyRNA *prop;
const int depth_ok = BKE_imtype_valid_depths(imf->imtype);
/* some settings depend on this being a scene that's rendered */
const bool is_render_out = (id && GS(id->name) == ID_SCE);
uiLayout *col;
- bool show_preview = false;
col = uiLayoutColumn(layout, false);
@@ -1004,7 +1002,6 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma
}
if (is_render_out && ELEM(imf->imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER)) {
- show_preview = true;
uiItemR(col, imfptr, "use_preview", 0, NULL, ICON_NONE);
}
@@ -1036,18 +1033,22 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, bool color_ma
uiItemR(col, imfptr, "tiff_codec", 0, NULL, ICON_NONE);
}
- /* color management */
- if (color_management && (!BKE_imtype_requires_linear_float(imf->imtype) ||
- (show_preview && imf->flag & R_IMF_FLAG_PREVIEW_JPG))) {
- prop = RNA_struct_find_property(imfptr, "display_settings");
- display_settings_ptr = RNA_property_pointer_get(imfptr, prop);
-
- col = uiLayoutColumn(layout, false);
- uiItemL(col, IFACE_("Color Management"), ICON_NONE);
-
- uiItemR(col, &display_settings_ptr, "display_device", 0, NULL, ICON_NONE);
+ /* Override color management */
+ if (color_management) {
+ uiItemS(col);
+ uiItemR(col, imfptr, "color_management", 0, NULL, ICON_NONE);
- uiTemplateColormanagedViewSettings(col, NULL, imfptr, "view_settings");
+ if (imf->color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) {
+ if (BKE_imtype_requires_linear_float(imf->imtype)) {
+ PointerRNA linear_settings_ptr = RNA_pointer_get(imfptr, "linear_colorspace_settings");
+ uiItemR(col, &linear_settings_ptr, "name", 0, IFACE_("Color Space"), ICON_NONE);
+ }
+ else {
+ PointerRNA display_settings_ptr = RNA_pointer_get(imfptr, "display_settings");
+ uiItemR(col, &display_settings_ptr, "display_device", 0, NULL, ICON_NONE);
+ uiTemplateColormanagedViewSettings(col, NULL, imfptr, "view_settings");
+ }
+ }
}
}
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 3721ea81c04..1c4a1d7e8c9 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -38,6 +38,7 @@
#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_image_save.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
@@ -53,7 +54,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_moviecache.h"
-#include "intern/openexr/openexr_multi.h"
+#include "IMB_openexr.h"
#include "RE_pipeline.h"
@@ -1736,7 +1737,7 @@ static int image_save_options_init(Main *bmain,
if (ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE)) {
/* imtype */
- opts->im_format = scene->r.im_format;
+ BKE_image_format_init_for_write(&opts->im_format, scene, NULL);
is_depth_set = true;
if (!BKE_image_is_multiview(ima)) {
/* In case multiview is disabled,
@@ -1752,14 +1753,18 @@ static int image_save_options_init(Main *bmain,
opts->im_format.planes = ibuf->planes;
}
else {
- BKE_imbuf_to_image_format(&opts->im_format, ibuf);
+ BKE_image_format_from_imbuf(&opts->im_format, ibuf);
}
/* use the multiview image settings as the default */
opts->im_format.stereo3d_format = *ima->stereo3d_format;
opts->im_format.views_format = ima->views_format;
+
+ BKE_image_format_color_management_copy_from_scene(&opts->im_format, scene);
}
+ opts->im_format.color_management = R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE;
+
if (ima->source == IMA_SRC_TILED) {
BLI_strncpy(opts->filepath, ima->filepath, sizeof(opts->filepath));
BLI_path_abs(opts->filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
@@ -1809,13 +1814,6 @@ static int image_save_options_init(Main *bmain,
STR_CONCAT(opts->filepath, len, ".<UDIM>");
}
}
-
- /* color management */
- BKE_color_managed_display_settings_copy(&opts->im_format.display_settings,
- &scene->display_settings);
-
- BKE_color_managed_view_settings_free(&opts->im_format.view_settings);
- BKE_color_managed_view_settings_copy(&opts->im_format.view_settings, &scene->view_settings);
}
BKE_image_release_ibuf(ima, ibuf, lock);
@@ -1829,8 +1827,8 @@ static void image_save_options_from_op(Main *bmain,
ImageFormatData *imf)
{
if (imf) {
- BKE_color_managed_view_settings_free(&opts->im_format.view_settings);
- opts->im_format = *imf;
+ BKE_image_format_free(&opts->im_format);
+ BKE_image_format_copy(&opts->im_format, imf);
}
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
@@ -1843,8 +1841,8 @@ static void image_save_options_to_op(ImageSaveOptions *opts, wmOperator *op)
{
if (op->customdata) {
ImageSaveData *isd = op->customdata;
- BKE_color_managed_view_settings_free(&isd->im_format.view_settings);
- isd->im_format = opts->im_format;
+ BKE_image_format_free(&isd->im_format);
+ BKE_image_format_copy(&isd->im_format, &opts->im_format);
}
RNA_string_set(op->ptr, "filepath", opts->filepath);
@@ -1878,7 +1876,7 @@ static void image_save_as_free(wmOperator *op)
{
if (op->customdata) {
ImageSaveData *isd = op->customdata;
- BKE_color_managed_view_settings_free(&isd->im_format.view_settings);
+ BKE_image_format_free(&isd->im_format);
MEM_freeN(op->customdata);
op->customdata = NULL;
@@ -1920,6 +1918,8 @@ static int image_save_as_exec(bContext *C, wmOperator *op)
BKE_image_free_packedfiles(image);
}
+ BKE_image_save_options_free(&opts);
+
image_save_as_free(op);
return OPERATOR_FINISHED;
@@ -1948,6 +1948,7 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
BKE_image_save_options_init(&opts, bmain, scene);
if (image_save_options_init(bmain, &opts, ima, iuser, true, save_as_render) == 0) {
+ BKE_image_save_options_free(&opts);
return OPERATOR_CANCELLED;
}
image_save_options_to_op(&opts, op);
@@ -1964,7 +1965,7 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
isd->image = ima;
isd->iuser = iuser;
- memcpy(&isd->im_format, &opts.im_format, sizeof(opts.im_format));
+ BKE_image_format_copy(&isd->im_format, &opts.im_format);
op->customdata = isd;
/* show multiview save options only if image has multiviews */
@@ -1974,6 +1975,7 @@ static int image_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
RNA_property_boolean_set(op->ptr, prop, BKE_image_is_multiview(ima));
image_filesel(C, op, opts.filepath);
+ BKE_image_save_options_free(&opts);
return OPERATOR_RUNNING_MODAL;
}
@@ -2001,15 +2003,21 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
ImageSaveData *isd = op->customdata;
PointerRNA imf_ptr;
const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
+ const bool use_color_management = RNA_boolean_get(op->ptr, "save_as_render");
- /* image template */
- RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &isd->im_format, &imf_ptr);
- uiTemplateImageSettings(layout, &imf_ptr, false);
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
/* main draw call */
uiDefAutoButsRNA(
layout, op->ptr, image_save_as_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
+ uiItemS(layout);
+
+ /* image template */
+ RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &isd->im_format, &imf_ptr);
+ uiTemplateImageSettings(layout, &imf_ptr, use_color_management);
+
/* multiview template */
if (is_multiview) {
uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
@@ -2132,6 +2140,7 @@ static int image_save_exec(bContext *C, wmOperator *op)
BKE_image_save_options_init(&opts, bmain, scene);
if (image_save_options_init(bmain, &opts, image, iuser, false, false) == 0) {
+ BKE_image_save_options_free(&opts);
return OPERATOR_CANCELLED;
}
image_save_options_from_op(bmain, &opts, op, NULL);
@@ -2147,7 +2156,7 @@ static int image_save_exec(bContext *C, wmOperator *op)
ok = true;
}
- BKE_color_managed_view_settings_free(&opts.im_format.view_settings);
+ BKE_image_save_options_free(&opts);
if (ok) {
return OPERATOR_FINISHED;
@@ -2399,6 +2408,7 @@ bool ED_image_save_all_modified(const bContext *C, ReportList *reports)
bool saved_successfully = BKE_image_save(reports, bmain, ima, NULL, &opts);
ok = ok && saved_successfully;
}
+ BKE_image_save_options_free(&opts);
}
}
}
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index 3e7784d0364..42d3d841f4b 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -216,7 +216,6 @@ static void nla_main_region_draw(const bContext *C, ARegion *region)
Scene *scene = CTX_data_scene(C);
bAnimContext ac;
View2D *v2d = &region->v2d;
- short cfra_flag = 0;
/* clear and setup matrix */
UI_ThemeClearColor(TH_BACK);
@@ -240,11 +239,6 @@ static void nla_main_region_draw(const bContext *C, ARegion *region)
UI_view2d_text_cache_draw(region);
}
- /* current frame */
- if (snla->flag & SNLA_DRAWTIME) {
- cfra_flag |= DRAWCFRA_UNIT_SECONDS;
- }
-
/* markers */
UI_view2d_view_orthoSpecial(region, v2d, 1);
int marker_draw_flag = DRAW_MARKERS_MARGIN;
diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc
index ccd3333fcc5..c524de2c55d 100644
--- a/source/blender/editors/space_node/link_drag_search.cc
+++ b/source/blender/editors/space_node/link_drag_search.cc
@@ -121,9 +121,6 @@ static void gather_socket_link_operations(bNodeTree &node_tree,
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;
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index 30bd0fb528b..7fb15d69ab5 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -517,113 +517,6 @@ void NODE_OT_add_object(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Add Node Texture Operator
- * \{ */
-
-static Tex *node_add_texture_get_and_poll_texture_node_tree(Main *bmain, wmOperator *op)
-{
- if (RNA_struct_property_is_set(op->ptr, "session_uuid")) {
- const uint32_t session_uuid = (uint32_t)RNA_int_get(op->ptr, "session_uuid");
- return (Tex *)BKE_libblock_find_session_uuid(bmain, ID_TE, session_uuid);
- }
-
- char name[MAX_ID_NAME - 2];
- RNA_string_get(op->ptr, "name", name);
- return (Tex *)BKE_libblock_find_name(bmain, ID_TE, name);
-}
-
-static int node_add_texture_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- SpaceNode *snode = CTX_wm_space_node(C);
- bNodeTree *ntree = snode->edittree;
- Tex *texture;
-
- if (!(texture = node_add_texture_get_and_poll_texture_node_tree(bmain, op))) {
- return OPERATOR_CANCELLED;
- }
-
- ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
-
- bNode *texture_node = node_add_node(*C,
- nullptr,
- GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE,
- snode->runtime->cursor[0],
- snode->runtime->cursor[1]);
- if (!texture_node) {
- BKE_report(op->reports, RPT_WARNING, "Could not add texture node");
- return OPERATOR_CANCELLED;
- }
-
- texture_node->id = &texture->id;
- id_us_plus(&texture->id);
-
- nodeSetActive(ntree, texture_node);
- ED_node_tree_propagate_change(C, bmain, ntree);
- DEG_relations_tag_update(bmain);
-
- return OPERATOR_FINISHED;
-}
-
-static int node_add_texture_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- ARegion *region = CTX_wm_region(C);
- SpaceNode *snode = CTX_wm_space_node(C);
-
- /* Convert mouse coordinates to v2d space. */
- UI_view2d_region_to_view(&region->v2d,
- event->mval[0],
- event->mval[1],
- &snode->runtime->cursor[0],
- &snode->runtime->cursor[1]);
-
- snode->runtime->cursor[0] /= UI_DPI_FAC;
- snode->runtime->cursor[1] /= UI_DPI_FAC;
-
- return node_add_texture_exec(C, op);
-}
-
-static bool node_add_texture_poll(bContext *C)
-{
- const SpaceNode *snode = CTX_wm_space_node(C);
- return ED_operator_node_editable(C) && ELEM(snode->nodetree->type, NTREE_GEOMETRY) &&
- !UI_but_active_drop_name(C);
-}
-
-void NODE_OT_add_texture(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name = "Add Node Texture";
- ot->description = "Add a texture to the current node editor";
- ot->idname = "NODE_OT_add_texture";
-
- /* callbacks */
- ot->exec = node_add_texture_exec;
- ot->invoke = node_add_texture_invoke;
- ot->poll = node_add_texture_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
-
- RNA_def_string(
- ot->srna, "name", "Texture", MAX_ID_NAME - 2, "Name", "Data-block name to assign");
- prop = RNA_def_int(ot->srna,
- "session_uuid",
- 0,
- INT32_MIN,
- INT32_MAX,
- "Session UUID",
- "Session UUID of the data-block to assign",
- INT32_MIN,
- INT32_MAX);
- RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE));
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Add Node Collection Operator
* \{ */
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index e638816e3fc..7f0c426922b 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -73,11 +73,10 @@
#include "node_intern.hh" /* own include */
-using blender::fn::CPPType;
+using blender::GPointer;
using blender::fn::FieldCPPType;
using blender::fn::FieldInput;
using blender::fn::GField;
-using blender::fn::GPointer;
namespace geo_log = blender::nodes::geometry_nodes_eval_log;
extern "C" {
@@ -1418,8 +1417,6 @@ static int node_error_type_to_icon(const geo_log::NodeWarningType type)
return ICON_ERROR;
case geo_log::NodeWarningType::Info:
return ICON_INFO;
- case geo_log::NodeWarningType::Legacy:
- return ICON_ERROR;
}
BLI_assert(false);
@@ -1430,8 +1427,6 @@ static uint8_t node_error_type_priority(const geo_log::NodeWarningType type)
{
switch (type) {
case geo_log::NodeWarningType::Error:
- return 4;
- case geo_log::NodeWarningType::Legacy:
return 3;
case geo_log::NodeWarningType::Warning:
return 2;
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index 1ca2f877398..956bb581ee6 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -18,6 +18,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_material.h"
@@ -274,28 +275,14 @@ static void compo_startjob(void *cjv,
/* 1 is do_previews */
if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) {
- ntreeCompositExecTree(cj->scene,
- ntree,
- &cj->scene->r,
- false,
- true,
- &scene->view_settings,
- &scene->display_settings,
- "");
+ ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, "");
}
else {
LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) {
continue;
}
- ntreeCompositExecTree(cj->scene,
- ntree,
- &cj->scene->r,
- false,
- true,
- &scene->view_settings,
- &scene->display_settings,
- srv->name);
+ ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, srv->name);
}
}
@@ -897,19 +884,15 @@ struct NodeSizeWidget {
int directions;
};
-static void node_resize_init(bContext *C,
- wmOperator *op,
- const wmEvent *UNUSED(event),
- const bNode *node,
- NodeResizeDirection dir)
+static void node_resize_init(
+ bContext *C, wmOperator *op, const float cursor[2], const bNode *node, NodeResizeDirection dir)
{
- SpaceNode *snode = CTX_wm_space_node(C);
-
NodeSizeWidget *nsw = MEM_cnew<NodeSizeWidget>(__func__);
op->customdata = nsw;
- nsw->mxstart = snode->runtime->cursor[0] * UI_DPI_FAC;
- nsw->mystart = snode->runtime->cursor[1] * UI_DPI_FAC;
+
+ nsw->mxstart = cursor[0];
+ nsw->mystart = cursor[1];
/* store old */
nsw->oldlocx = node->locx;
@@ -1068,7 +1051,7 @@ static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
- node_resize_init(C, op, event, node, dir);
+ node_resize_init(C, op, cursor, node, dir);
return OPERATOR_RUNNING_MODAL;
}
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
index 319f97e57f5..cd40573607d 100644
--- a/source/blender/editors/space_node/node_intern.hh
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -178,7 +178,6 @@ bool space_node_view_flag(
void NODE_OT_view_all(wmOperatorType *ot);
void NODE_OT_view_selected(wmOperatorType *ot);
-void NODE_OT_geometry_node_view_legacy(wmOperatorType *ot);
void NODE_OT_backimage_move(wmOperatorType *ot);
void NODE_OT_backimage_zoom(wmOperatorType *ot);
@@ -241,7 +240,6 @@ void NODE_OT_add_reroute(wmOperatorType *ot);
void NODE_OT_add_group(wmOperatorType *ot);
void NODE_OT_add_object(wmOperatorType *ot);
void NODE_OT_add_collection(wmOperatorType *ot);
-void NODE_OT_add_texture(wmOperatorType *ot);
void NODE_OT_add_file(wmOperatorType *ot);
void NODE_OT_add_mask(wmOperatorType *ot);
void NODE_OT_new_node_tree(wmOperatorType *ot);
diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc
index e9903299300..ce000aba1da 100644
--- a/source/blender/editors/space_node/node_ops.cc
+++ b/source/blender/editors/space_node/node_ops.cc
@@ -37,7 +37,6 @@ void node_operatortypes()
WM_operatortype_append(NODE_OT_view_all);
WM_operatortype_append(NODE_OT_view_selected);
- WM_operatortype_append(NODE_OT_geometry_node_view_legacy);
WM_operatortype_append(NODE_OT_mute_toggle);
WM_operatortype_append(NODE_OT_hide_toggle);
@@ -79,7 +78,6 @@ void node_operatortypes()
WM_operatortype_append(NODE_OT_add_group);
WM_operatortype_append(NODE_OT_add_object);
WM_operatortype_append(NODE_OT_add_collection);
- WM_operatortype_append(NODE_OT_add_texture);
WM_operatortype_append(NODE_OT_add_file);
WM_operatortype_append(NODE_OT_add_mask);
diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc
index 8cd87574465..b63cb2eeee5 100644
--- a/source/blender/editors/space_node/node_templates.cc
+++ b/source/blender/editors/space_node/node_templates.cc
@@ -69,11 +69,11 @@ static bool node_link_item_compare(bNode *node, NodeLinkItem *item)
return true;
}
-static void node_link_item_apply(Main *bmain, bNode *node, NodeLinkItem *item)
+static void node_link_item_apply(bNodeTree *ntree, bNode *node, NodeLinkItem *item)
{
if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
node->id = (ID *)item->ngroup;
- BKE_ntree_update_main_tree(bmain, item->ngroup, nullptr);
+ BKE_ntree_update_tag_node_property(ntree, node);
}
else {
/* nothing to do for now */
@@ -237,7 +237,8 @@ static void node_socket_add_replace(const bContext *C,
nodePositionRelative(node_from, node_to, sock_from_tmp, sock_to);
}
- node_link_item_apply(bmain, node_from, item);
+ node_link_item_apply(ntree, node_from, item);
+ ED_node_tree_propagate_change(C, bmain, ntree);
}
nodeSetActive(ntree, node_from);
diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc
index 36fdcf37fd7..f5f5a9e6f67 100644
--- a/source/blender/editors/space_node/node_view.cc
+++ b/source/blender/editors/space_node/node_view.cc
@@ -686,90 +686,4 @@ void NODE_OT_backimage_sample(wmOperatorType *ot)
/** \} */
-/* -------------------------------------------------------------------- */
-/** \name View Geometry Nodes Legacy Operator
- *
- * This operator should be removed when the 2.93 legacy nodes are removed.
- * \{ */
-
-static int space_node_view_geometry_nodes_legacy(bContext *C, SpaceNode *snode, wmOperator *op)
-{
- ARegion *region = CTX_wm_region(C);
-
- /* Only use the node editor's active node tree. Otherwise this will be too complicated. */
- bNodeTree *node_tree = snode->nodetree;
- if (node_tree == nullptr || node_tree->type != NTREE_GEOMETRY) {
- return OPERATOR_CANCELLED;
- }
-
- bool found_legacy_node = false;
- LISTBASE_FOREACH_BACKWARD (bNode *, node, &node_tree->nodes) {
- StringRef idname{node->idname};
- if (idname.find("Legacy") == StringRef::not_found) {
- node->flag &= ~NODE_SELECT;
- }
- else {
- found_legacy_node = true;
- node->flag |= NODE_SELECT;
- }
- }
-
- if (!found_legacy_node) {
- WM_report(RPT_INFO, "Legacy node not found, may be in nested node group");
- }
-
- const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
- if (space_node_view_flag(*C, *snode, *region, NODE_SELECT, smooth_viewtx)) {
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-static int geometry_node_view_legacy_exec(bContext *C, wmOperator *op)
-{
- /* Allow running this operator directly in a specific node editor. */
- if (SpaceNode *snode = CTX_wm_space_node(C)) {
- return space_node_view_geometry_nodes_legacy(C, snode, op);
- }
-
- /* Since the operator is meant to be called from a button in the modifier panel, the node tree
- * must be found from the screen, using the largest node editor if there is more than one. */
- if (ScrArea *area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_NODE, 0)) {
- if (SpaceNode *snode = static_cast<SpaceNode *>(area->spacedata.first)) {
- ScrArea *old_area = CTX_wm_area(C);
- ARegion *old_region = CTX_wm_region(C);
-
- /* Override the context since it is used by the View2D panning code. */
- CTX_wm_area_set(C, area);
- CTX_wm_region_set(C, static_cast<ARegion *>(area->regionbase.last));
- const int result = space_node_view_geometry_nodes_legacy(C, snode, op);
- CTX_wm_area_set(C, old_area);
- CTX_wm_region_set(C, old_region);
- return result;
- }
- }
-
- return OPERATOR_CANCELLED;
-}
-
-static bool geometry_node_view_legacy_poll(bContext *C)
-{
- /* Allow direct execution in a node editor, but also affecting any visible node editor. */
- return ED_operator_node_active(C) || BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_NODE, 0);
-}
-
-void NODE_OT_geometry_node_view_legacy(wmOperatorType *ot)
-{
- ot->name = "View Deprecated Geometry Nodes";
- ot->idname = "NODE_OT_geometry_node_view_legacy";
- ot->description = "Select and view legacy geometry nodes in the node editor";
-
- ot->exec = geometry_node_view_legacy_exec;
- ot->poll = geometry_node_view_legacy_poll;
-
- ot->flag = OPTYPE_INTERNAL;
-}
-
-/** \} */
-
} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc
index a1fa0517c63..82b850653be 100644
--- a/source/blender/editors/space_node/space_node.cc
+++ b/source/blender/editors/space_node/space_node.cc
@@ -622,11 +622,6 @@ static bool node_collection_drop_poll(bContext *UNUSED(C),
return WM_drag_is_ID_type(drag, ID_GR);
}
-static bool node_texture_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
-{
- return WM_drag_is_ID_type(drag, ID_TE);
-}
-
static bool node_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_PATH) {
@@ -687,12 +682,6 @@ static void node_dropboxes()
WM_drag_free_imported_drag_ID,
nullptr);
WM_dropbox_add(lb,
- "NODE_OT_add_texture",
- node_texture_drop_poll,
- node_id_drop_copy,
- WM_drag_free_imported_drag_ID,
- nullptr);
- WM_dropbox_add(lb,
"NODE_OT_add_group",
node_group_drop_poll,
node_group_drop_copy,
diff --git a/source/blender/editors/space_outliner/outliner_collections.cc b/source/blender/editors/space_outliner/outliner_collections.cc
index 716d5b67fe3..a4ff44512ef 100644
--- a/source/blender/editors/space_outliner/outliner_collections.cc
+++ b/source/blender/editors/space_outliner/outliner_collections.cc
@@ -301,7 +301,7 @@ static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *c
if (ID_IS_OVERRIDE_LIBRARY_REAL(collection)) {
if (ID_IS_OVERRIDE_LIBRARY_HIERARCHY_ROOT(collection)) {
- if (!data->is_liboverride_hierarchy_root_allowed) {
+ if (!(data->is_liboverride_hierarchy_root_allowed || data->is_liboverride_allowed)) {
return TRAVERSE_SKIP_CHILDS;
}
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc
index 4ef0bbbcde8..9857abb3da7 100644
--- a/source/blender/editors/space_outliner/outliner_draw.cc
+++ b/source/blender/editors/space_outliner/outliner_draw.cc
@@ -1082,7 +1082,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
}
BLI_assert((restrict_column_offset * UI_UNIT_X + V2D_SCROLL_WIDTH) ==
- outliner_restrict_columns_width(space_outliner));
+ outliner_right_columns_width(space_outliner));
/* Create buttons. */
uiBut *bt;
@@ -1779,11 +1779,67 @@ static void outliner_draw_userbuts(uiBlock *block,
}
}
-static bool outliner_draw_overrides_buts(uiBlock *block,
- ARegion *region,
- SpaceOutliner *space_outliner,
- ListBase *lb,
- const bool is_open)
+static void outliner_draw_overrides_rna_buts(uiBlock *block,
+ const ARegion *region,
+ const SpaceOutliner *space_outliner,
+ const ListBase *lb,
+ const int x)
+{
+ const float pad_x = 2.0f * UI_DPI_FAC;
+ const float pad_y = 0.5f * U.pixelsize;
+ const float item_max_width = round_fl_to_int(OL_RNA_COL_SIZEX - 2 * pad_x);
+ const float item_height = round_fl_to_int(UI_UNIT_Y - 2.0f * pad_y);
+
+ LISTBASE_FOREACH (const TreeElement *, te, lb) {
+ const TreeStoreElem *tselem = TREESTORE(te);
+ if (TSELEM_OPEN(tselem, space_outliner)) {
+ outliner_draw_overrides_rna_buts(block, region, space_outliner, &te->subtree, x);
+ }
+
+ if (!outliner_is_element_in_view(te, &region->v2d)) {
+ continue;
+ }
+ if (tselem->type != TSE_LIBRARY_OVERRIDE) {
+ continue;
+ }
+
+ TreeElementOverridesProperty &override_elem = *tree_element_cast<TreeElementOverridesProperty>(
+ te);
+
+ PointerRNA *ptr = &override_elem.override_rna_ptr;
+ PropertyRNA *prop = &override_elem.override_rna_prop;
+ const PropertyType prop_type = RNA_property_type(prop);
+
+ uiBut *auto_but = uiDefAutoButR(block,
+ ptr,
+ prop,
+ -1,
+ (prop_type == PROP_ENUM) ? nullptr : "",
+ ICON_NONE,
+ x + pad_x,
+ te->ys + pad_y,
+ item_max_width,
+ item_height);
+ /* Added the button successfully, nothing else to do. Otherwise, cases for multiple buttons
+ * need to be handled. */
+ if (auto_but) {
+ continue;
+ }
+
+ if (!auto_but) {
+ /* TODO what if the array is longer, and doesn't fit nicely? What about multi-dimension
+ * arrays? */
+ uiDefAutoButsArrayR(
+ block, ptr, prop, ICON_NONE, x + pad_x, te->ys + pad_y, item_max_width, item_height);
+ }
+ }
+}
+
+static bool outliner_draw_overrides_warning_buts(uiBlock *block,
+ ARegion *region,
+ SpaceOutliner *space_outliner,
+ ListBase *lb,
+ const bool is_open)
{
bool any_item_has_warnings = false;
@@ -1829,7 +1885,7 @@ static bool outliner_draw_overrides_buts(uiBlock *block,
break;
}
- const bool any_child_has_warnings = outliner_draw_overrides_buts(
+ const bool any_child_has_warnings = outliner_draw_overrides_warning_buts(
block,
region,
space_outliner,
@@ -1863,28 +1919,20 @@ static bool outliner_draw_overrides_buts(uiBlock *block,
return any_item_has_warnings;
}
-static void outliner_draw_rnacols(ARegion *region, int sizex)
+static void outliner_draw_separator(ARegion *region, const int x)
{
View2D *v2d = &region->v2d;
- float miny = v2d->cur.ymin;
- if (miny < v2d->tot.ymin) {
- miny = v2d->tot.ymin;
- }
-
GPU_line_width(1.0f);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformThemeColorShadeAlpha(TH_BACK, -15, -200);
- immBegin(GPU_PRIM_LINES, 4);
-
- immVertex2f(pos, sizex, v2d->cur.ymax);
- immVertex2f(pos, sizex, miny);
+ immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, sizex + OL_RNA_COL_SIZEX, v2d->cur.ymax);
- immVertex2f(pos, sizex + OL_RNA_COL_SIZEX, miny);
+ immVertex2f(pos, x, v2d->cur.ymax);
+ immVertex2f(pos, x, v2d->cur.ymin);
immEnd();
@@ -3637,7 +3685,7 @@ static void outliner_draw_tree(bContext *C,
const TreeViewContext *tvc,
ARegion *region,
SpaceOutliner *space_outliner,
- const float restrict_column_width,
+ const float right_column_width,
const bool use_mode_column,
const bool use_warning_column,
TreeElement **te_edit)
@@ -3672,8 +3720,8 @@ static void outliner_draw_tree(bContext *C,
/* Set scissor so tree elements or lines can't overlap restriction icons. */
int scissor[4] = {0};
- if (restrict_column_width > 0.0f) {
- int mask_x = BLI_rcti_size_x(&region->v2d.mask) - (int)restrict_column_width + 1;
+ if (right_column_width > 0.0f) {
+ int mask_x = BLI_rcti_size_x(&region->v2d.mask) - (int)right_column_width + 1;
CLAMP_MIN(mask_x, 0);
GPU_scissor_get(scissor);
@@ -3699,11 +3747,11 @@ static void outliner_draw_tree(bContext *C,
(te->flag & TE_DRAGGING) != 0,
startx,
&starty,
- restrict_column_width,
+ right_column_width,
te_edit);
}
- if (restrict_column_width > 0.0f) {
+ if (right_column_width > 0.0f) {
/* Reset scissor. */
GPU_scissor(UNPACK4(scissor));
}
@@ -3754,21 +3802,21 @@ static int outliner_data_api_buttons_start_x(int max_tree_width)
static int outliner_width(SpaceOutliner *space_outliner,
int max_tree_width,
- float restrict_column_width)
+ float right_column_width)
{
if (space_outliner->outlinevis == SO_DATA_API) {
return outliner_data_api_buttons_start_x(max_tree_width) + OL_RNA_COL_SIZEX + 10 * UI_DPI_FAC;
}
- return max_tree_width + restrict_column_width;
+ return max_tree_width + right_column_width;
}
static void outliner_update_viewable_area(ARegion *region,
SpaceOutliner *space_outliner,
int tree_width,
int tree_height,
- float restrict_column_width)
+ float right_column_width)
{
- int sizex = outliner_width(space_outliner, tree_width, restrict_column_width);
+ int sizex = outliner_width(space_outliner, tree_width, right_column_width);
int sizey = tree_height;
/* Extend size to allow for horizontal scrollbar and extra offset. */
@@ -3829,7 +3877,7 @@ void draw_outliner(const bContext *C)
space_outliner->runtime->tree_display->hasWarnings();
/* Draw outliner stuff (background, hierarchy lines and names). */
- const float restrict_column_width = outliner_restrict_columns_width(space_outliner);
+ const float right_column_width = outliner_right_columns_width(space_outliner);
outliner_back(region);
block = UI_block_begin(C, region, __func__, UI_EMBOSS);
outliner_draw_tree((bContext *)C,
@@ -3837,7 +3885,7 @@ void draw_outliner(const bContext *C)
&tvc,
region,
space_outliner,
- restrict_column_width,
+ right_column_width,
use_mode_column,
use_warning_column,
&te_edit);
@@ -3852,7 +3900,8 @@ void draw_outliner(const bContext *C)
if (space_outliner->outlinevis == SO_DATA_API) {
int buttons_start_x = outliner_data_api_buttons_start_x(tree_width);
/* draw rna buttons */
- outliner_draw_rnacols(region, buttons_start_x);
+ outliner_draw_separator(region, buttons_start_x);
+ outliner_draw_separator(region, buttons_start_x + OL_RNA_COL_SIZEX);
UI_block_emboss_set(block, UI_EMBOSS);
outliner_draw_rnabuts(block, region, space_outliner, buttons_start_x, &space_outliner->tree);
@@ -3864,9 +3913,17 @@ void draw_outliner(const bContext *C)
}
else if (space_outliner->outlinevis == SO_OVERRIDES_LIBRARY) {
/* Draw overrides status columns. */
- outliner_draw_overrides_buts(block, region, space_outliner, &space_outliner->tree, true);
+ outliner_draw_overrides_warning_buts(
+ block, region, space_outliner, &space_outliner->tree, true);
+
+ UI_block_emboss_set(block, UI_EMBOSS);
+ UI_block_flag_enable(block, UI_BLOCK_NO_DRAW_OVERRIDDEN_STATE);
+ const int x = region->v2d.cur.xmax - right_column_width;
+ outliner_draw_separator(region, x);
+ outliner_draw_overrides_rna_buts(block, region, space_outliner, &space_outliner->tree, x);
+ UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS);
}
- else if (restrict_column_width > 0.0f) {
+ else if (right_column_width > 0.0f) {
/* draw restriction columns */
RestrictPropertiesActive props_active;
memset(&props_active, 1, sizeof(RestrictPropertiesActive));
@@ -3893,7 +3950,7 @@ void draw_outliner(const bContext *C)
/* Draw edit buttons if necessary. */
if (te_edit) {
- outliner_buttons(C, block, region, restrict_column_width, te_edit);
+ outliner_buttons(C, block, region, right_column_width, te_edit);
}
UI_block_end(C, block);
@@ -3901,7 +3958,7 @@ void draw_outliner(const bContext *C)
/* Update total viewable region. */
outliner_update_viewable_area(
- region, space_outliner, tree_width, tree_height, restrict_column_width);
+ region, space_outliner, tree_width, tree_height, right_column_width);
}
/** \} */
diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc
index a60e082f6a5..ae67e7108bf 100644
--- a/source/blender/editors/space_outliner/outliner_edit.cc
+++ b/source/blender/editors/space_outliner/outliner_edit.cc
@@ -447,6 +447,17 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
(tselem->type == TSE_LAYER_COLLECTION));
UNUSED_VARS_NDEBUG(te);
+ if (ID_IS_OVERRIDE_LIBRARY(id)) {
+ if (!ID_IS_OVERRIDE_LIBRARY_REAL(id) ||
+ (id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY) == 0) {
+ BKE_reportf(reports,
+ RPT_WARNING,
+ "Cannot delete library override id '%s', it is part of an override hierarchy",
+ id->name);
+ return;
+ }
+ }
+
if (te->idcode == ID_LI && ((Library *)id)->parent != nullptr) {
BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked library '%s'", id->name);
return;
diff --git a/source/blender/editors/space_outliner/outliner_intern.hh b/source/blender/editors/space_outliner/outliner_intern.hh
index a9bdcc56787..7970841b4fd 100644
--- a/source/blender/editors/space_outliner/outliner_intern.hh
+++ b/source/blender/editors/space_outliner/outliner_intern.hh
@@ -638,7 +638,7 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
int filter_tselem_flag,
TreeTraversalFunc func,
void *customdata);
-float outliner_restrict_columns_width(const struct SpaceOutliner *space_outliner);
+float outliner_right_columns_width(const struct SpaceOutliner *space_outliner);
/**
* Find first tree element in tree with matching tree-store flag.
*/
diff --git a/source/blender/editors/space_outliner/outliner_select.cc b/source/blender/editors/space_outliner/outliner_select.cc
index a583eb0364f..a202ded6deb 100644
--- a/source/blender/editors/space_outliner/outliner_select.cc
+++ b/source/blender/editors/space_outliner/outliner_select.cc
@@ -1551,7 +1551,7 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *space_ou
const ARegion *region,
float view_co_x)
{
- return (view_co_x > region->v2d.cur.xmax - outliner_restrict_columns_width(space_outliner));
+ return (view_co_x > region->v2d.cur.xmax - outliner_right_columns_width(space_outliner));
}
bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const float view_mval[2])
diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc
index 612baaa0752..0aea4521204 100644
--- a/source/blender/editors/space_outliner/outliner_tools.cc
+++ b/source/blender/editors/space_outliner/outliner_tools.cc
@@ -1677,6 +1677,12 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot)
using OutlinerDeleteFn = void (*)(bContext *C, ReportList *reports, Scene *scene, Object *ob);
+typedef struct ObjectEditData {
+ GSet *objects_set;
+ bool is_liboverride_allowed;
+ bool is_liboverride_hierarchy_root_allowed;
+} ObjectEditData;
+
static void outliner_do_object_delete(bContext *C,
ReportList *reports,
Scene *scene,
@@ -1693,7 +1699,8 @@ static void outliner_do_object_delete(bContext *C,
static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void *customdata)
{
- GSet *objects_to_delete = (GSet *)customdata;
+ ObjectEditData *data = reinterpret_cast<ObjectEditData *>(customdata);
+ GSet *objects_to_delete = data->objects_set;
TreeStoreElem *tselem = TREESTORE(te);
if (outliner_is_collection_tree_element(te)) {
@@ -1708,9 +1715,15 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void
ID *id = tselem->id;
if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
- if (!ID_IS_OVERRIDE_LIBRARY_HIERARCHY_ROOT(id)) {
- /* Only allow deletion of liboverride objects if they are root overrides. */
- return TRAVERSE_SKIP_CHILDS;
+ if (ID_IS_OVERRIDE_LIBRARY_HIERARCHY_ROOT(id)) {
+ if (!(data->is_liboverride_hierarchy_root_allowed || data->is_liboverride_allowed)) {
+ return TRAVERSE_SKIP_CHILDS;
+ }
+ }
+ else {
+ if (!data->is_liboverride_allowed) {
+ return TRAVERSE_SKIP_CHILDS;
+ }
}
}
@@ -1732,27 +1745,31 @@ static int outliner_delete_exec(bContext *C, wmOperator *op)
/* Get selected objects skipping duplicates to prevent deleting objects linked to multiple
* collections twice */
- GSet *objects_to_delete = BLI_gset_ptr_new(__func__);
+ ObjectEditData object_delete_data = {};
+ object_delete_data.objects_set = BLI_gset_ptr_new(__func__);
+ object_delete_data.is_liboverride_allowed = false;
+ object_delete_data.is_liboverride_hierarchy_root_allowed = delete_hierarchy;
outliner_tree_traverse(space_outliner,
&space_outliner->tree,
0,
TSE_SELECTED,
outliner_find_objects_to_delete,
- objects_to_delete);
+ &object_delete_data);
if (delete_hierarchy) {
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
outliner_do_object_delete(
- C, op->reports, scene, objects_to_delete, object_batch_delete_hierarchy_fn);
+ C, op->reports, scene, object_delete_data.objects_set, object_batch_delete_hierarchy_fn);
BKE_id_multi_tagged_delete(bmain);
}
else {
- outliner_do_object_delete(C, op->reports, scene, objects_to_delete, outliner_object_delete_fn);
+ outliner_do_object_delete(
+ C, op->reports, scene, object_delete_data.objects_set, outliner_object_delete_fn);
}
- BLI_gset_free(objects_to_delete, nullptr);
+ BLI_gset_free(object_delete_data.objects_set, nullptr);
outliner_collection_delete(C, bmain, scene, op->reports, delete_hierarchy);
diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc
index 1a772287dfa..19fe40b612e 100644
--- a/source/blender/editors/space_outliner/outliner_tree.cc
+++ b/source/blender/editors/space_outliner/outliner_tree.cc
@@ -900,7 +900,6 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner,
/* ID types not (fully) ported to new design yet. */
if (te->abstract_element->expandPoll(*space_outliner)) {
outliner_add_id_contents(space_outliner, te, tselem, id);
- te->abstract_element->postExpand(*space_outliner);
}
}
else if (ELEM(type,
diff --git a/source/blender/editors/space_outliner/outliner_utils.cc b/source/blender/editors/space_outliner/outliner_utils.cc
index 556f87617f6..ed5a2108d3c 100644
--- a/source/blender/editors/space_outliner/outliner_utils.cc
+++ b/source/blender/editors/space_outliner/outliner_utils.cc
@@ -314,7 +314,7 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner,
return true;
}
-float outliner_restrict_columns_width(const SpaceOutliner *space_outliner)
+float outliner_right_columns_width(const SpaceOutliner *space_outliner)
{
int num_columns = 0;
@@ -322,8 +322,10 @@ float outliner_restrict_columns_width(const SpaceOutliner *space_outliner)
case SO_DATA_API:
case SO_SEQUENCE:
case SO_LIBRARIES:
- case SO_OVERRIDES_LIBRARY:
return 0.0f;
+ case SO_OVERRIDES_LIBRARY:
+ num_columns = OL_RNA_COL_SIZEX / UI_UNIT_X;
+ break;
case SO_ID_ORPHANS:
num_columns = 3;
break;
diff --git a/source/blender/editors/space_outliner/space_outliner.cc b/source/blender/editors/space_outliner/space_outliner.cc
index f75182d25a0..97dc659155f 100644
--- a/source/blender/editors/space_outliner/space_outliner.cc
+++ b/source/blender/editors/space_outliner/space_outliner.cc
@@ -371,7 +371,7 @@ static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *area)
static SpaceLink *outliner_duplicate(SpaceLink *sl)
{
SpaceOutliner *space_outliner = (SpaceOutliner *)sl;
- SpaceOutliner *space_outliner_new = MEM_new<SpaceOutliner>(__func__, *space_outliner);
+ SpaceOutliner *space_outliner_new = MEM_cnew<SpaceOutliner>(__func__, *space_outliner);
BLI_listbase_clear(&space_outliner_new->tree);
space_outliner_new->treestore = nullptr;
diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh
index bdca1954a9c..a60d3339042 100644
--- a/source/blender/editors/space_outliner/tree/tree_display.hh
+++ b/source/blender/editors/space_outliner/tree/tree_display.hh
@@ -136,8 +136,7 @@ class TreeDisplayOverrideLibrary final : public AbstractTreeDisplay {
ListBase buildTree(const TreeSourceData &source_data) override;
private:
- TreeElement *add_library_contents(Main &, ListBase &, Library *);
- bool override_library_id_filter_poll(const Library *lib, ID *id) const;
+ ListBase add_library_contents(Main &);
short id_filter_get() const;
};
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 f94727ba356..b5c0a10c834 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
@@ -32,72 +32,22 @@ TreeDisplayOverrideLibrary::TreeDisplayOverrideLibrary(SpaceOutliner &space_outl
ListBase TreeDisplayOverrideLibrary::buildTree(const TreeSourceData &source_data)
{
- ListBase tree = {nullptr};
-
- {
- /* current file first - mainvar provides tselem with unique pointer - not used */
- TreeElement *ten = add_library_contents(*source_data.bmain, tree, nullptr);
- TreeStoreElem *tselem;
-
- if (ten) {
- tselem = TREESTORE(ten);
- if (!tselem->used) {
- tselem->flag &= ~TSE_CLOSED;
- }
- }
- }
+ ListBase tree = add_library_contents(*source_data.bmain);
- for (ID *id : List<ID>(source_data.bmain->libraries)) {
- Library *lib = reinterpret_cast<Library *>(id);
- TreeElement *ten = add_library_contents(*source_data.bmain, tree, lib);
- /* NULL-check matters, due to filtering there may not be a new element. */
- if (ten) {
- lib->id.newid = (ID *)ten;
+ for (TreeElement *top_level_te : List<TreeElement>(tree)) {
+ TreeStoreElem *tselem = TREESTORE(top_level_te);
+ if (!tselem->used) {
+ tselem->flag &= ~TSE_CLOSED;
}
}
- /* make hierarchy */
- for (TreeElement *ten : List<TreeElement>(tree)) {
- if (ten == tree.first) {
- /* First item is main, skip. */
- continue;
- }
-
- TreeStoreElem *tselem = TREESTORE(ten);
- Library *lib = (Library *)tselem->id;
- BLI_assert(!lib || (GS(lib->id.name) == ID_LI));
- if (!lib || !lib->parent) {
- continue;
- }
-
- TreeElement *parent = (TreeElement *)lib->parent->id.newid;
-
- if (tselem->id->tag & LIB_TAG_INDIRECT) {
- /* Only remove from 'first level' if lib is not also directly used. */
- BLI_remlink(&tree, ten);
- BLI_addtail(&parent->subtree, ten);
- ten->parent = parent;
- }
- else {
- /* Else, make a new copy of the libtree for our parent. */
- TreeElement *dupten = add_library_contents(*source_data.bmain, parent->subtree, lib);
- if (dupten) {
- dupten->parent = parent;
- }
- }
- }
- /* restore newid pointers */
- for (ID *library_id : List<ID>(source_data.bmain->libraries)) {
- library_id->newid = nullptr;
- }
-
return tree;
}
-TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar,
- ListBase &lb,
- Library *lib)
+ListBase TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar)
{
+ ListBase tree = {nullptr};
+
const short filter_id_type = id_filter_get();
ListBase *lbarray[INDEX_ID_MAX];
@@ -110,7 +60,6 @@ TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar,
tot = set_listbasepointers(&mainvar, lbarray);
}
- TreeElement *tenlib = nullptr;
for (int a = 0; a < tot; a++) {
if (!lbarray[a] || !lbarray[a]->first) {
continue;
@@ -118,56 +67,51 @@ TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar,
ID *id = nullptr;
- /* check if there's data in current lib */
+ /* check if there's data in current id list */
for (ID *id_iter : List<ID>(lbarray[a])) {
- if (id_iter->lib == lib && ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) {
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) {
id = id_iter;
break;
}
}
- if (id != nullptr) {
- if (!tenlib) {
- /* Create library tree element on demand, depending if there are any data-blocks. */
- if (lib) {
- tenlib = outliner_add_element(&space_outliner_, &lb, lib, nullptr, TSE_SOME_ID, 0);
- }
- else {
- tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0);
- tenlib->name = IFACE_("Current File");
- }
- if (tenlib->flag & TE_HAS_WARNING) {
- has_warnings = true;
- }
- }
+ if (id == nullptr) {
+ continue;
+ }
- /* Create data-block list parent element on demand. */
- TreeElement *ten;
+ /* Create data-block list parent element on demand. */
+ TreeElement *id_base_te = nullptr;
+ ListBase *lb_to_expand = &tree;
- if (filter_id_type) {
- ten = tenlib;
- }
- else {
- ten = outliner_add_element(
- &space_outliner_, &tenlib->subtree, lbarray[a], nullptr, TSE_ID_BASE, 0);
- ten->directdata = lbarray[a];
- ten->name = outliner_idcode_to_plural(GS(id->name));
- }
+ if (!filter_id_type) {
+ id_base_te = outliner_add_element(
+ &space_outliner_, &tree, lbarray[a], nullptr, TSE_ID_BASE, 0);
+ id_base_te->directdata = lbarray[a];
+ id_base_te->name = outliner_idcode_to_plural(GS(id->name));
- for (ID *id : List<ID>(lbarray[a])) {
- if (override_library_id_filter_poll(lib, id)) {
- TreeElement *override_tree_element = outliner_add_element(
- &space_outliner_, &ten->subtree, id, ten, TSE_LIBRARY_OVERRIDE_BASE, 0);
+ lb_to_expand = &id_base_te->subtree;
+ }
- if (BLI_listbase_is_empty(&override_tree_element->subtree)) {
- outliner_free_tree_element(override_tree_element, &ten->subtree);
- }
+ for (ID *id : List<ID>(lbarray[a])) {
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
+ TreeElement *override_tree_element = outliner_add_element(
+ &space_outliner_, lb_to_expand, id, id_base_te, TSE_LIBRARY_OVERRIDE_BASE, 0);
+
+ if (BLI_listbase_is_empty(&override_tree_element->subtree)) {
+ outliner_free_tree_element(override_tree_element, lb_to_expand);
}
}
}
}
- return tenlib;
+ /* Remove ID base elements that turn out to be empty. */
+ LISTBASE_FOREACH_MUTABLE (TreeElement *, te, &tree) {
+ if (BLI_listbase_is_empty(&te->subtree)) {
+ outliner_free_tree_element(te, &tree);
+ }
+ }
+
+ return tree;
}
short TreeDisplayOverrideLibrary::id_filter_get() const
@@ -178,17 +122,4 @@ short TreeDisplayOverrideLibrary::id_filter_get() const
return 0;
}
-bool TreeDisplayOverrideLibrary::override_library_id_filter_poll(const Library *lib, ID *id) const
-{
- if (id->lib != lib) {
- return false;
- }
-
- if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
- return false;
- }
-
- return true;
-}
-
} // namespace blender::ed::outliner
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 0ee5059a54d..19811e45b90 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
@@ -154,15 +154,6 @@ void TreeDisplayViewLayer::add_layer_collections_recursive(ListBase &tree,
if (!exclude && show_objects_) {
add_layer_collection_objects(ten->subtree, *lc, *ten);
}
-
- const bool lib_overrides_visible = !exclude && (!SUPPORT_FILTER_OUTLINER(&space_outliner_) ||
- ((space_outliner_.filter &
- SO_FILTER_NO_LIB_OVERRIDE) == 0));
-
- if (lib_overrides_visible && ID_IS_OVERRIDE_LIBRARY_REAL(&lc->collection->id)) {
- outliner_add_element(
- &space_outliner_, &ten->subtree, &lc->collection->id, ten, TSE_LIBRARY_OVERRIDE_BASE, 0);
- }
}
}
diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc
index 3c2023d7905..ca67aad00db 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element.cc
@@ -107,7 +107,6 @@ void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner
return;
}
tree_element.expand(space_outliner);
- tree_element.postExpand(space_outliner);
}
bool tree_element_warnings_get(TreeElement *te, int *r_icon, const char **r_message)
diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh
index 2fbc86705b9..6f2d803ae96 100644
--- a/source/blender/editors/space_outliner/tree/tree_element.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element.hh
@@ -40,9 +40,6 @@ class AbstractTreeElement {
{
return true;
}
- virtual void postExpand(SpaceOutliner &) const
- {
- }
/**
* Just while transitioning to the new tree-element design: Some types are only partially ported,
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc
index 64c73f57107..ef5e056f229 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc
@@ -93,17 +93,6 @@ TreeElementID::TreeElementID(TreeElement &legacy_te, ID &id)
legacy_te_.idcode = GS(id.name);
}
-void TreeElementID::postExpand(SpaceOutliner &space_outliner) const
-{
- const bool lib_overrides_visible = !SUPPORT_FILTER_OUTLINER(&space_outliner) ||
- ((space_outliner.filter & SO_FILTER_NO_LIB_OVERRIDE) == 0);
-
- if (lib_overrides_visible && ID_IS_OVERRIDE_LIBRARY_REAL(&id_)) {
- outliner_add_element(
- &space_outliner, &legacy_te_.subtree, &id_, &legacy_te_, TSE_LIBRARY_OVERRIDE_BASE, 0);
- }
-}
-
bool TreeElementID::expandPoll(const SpaceOutliner &space_outliner) const
{
const TreeStoreElem *tsepar = legacy_te_.parent ? TREESTORE(legacy_te_.parent) : nullptr;
diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.hh b/source/blender/editors/space_outliner/tree/tree_element_id.hh
index 75dc7e737e2..b7519fe06f9 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_id.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_id.hh
@@ -24,7 +24,6 @@ class TreeElementID : public AbstractTreeElement {
static std::unique_ptr<TreeElementID> createFromID(TreeElement &legacy_te, ID &id);
- void postExpand(SpaceOutliner &) const override;
bool expandPoll(const SpaceOutliner &) const override;
/**
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
index 64c390d29b3..857f5577e59 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc
@@ -73,7 +73,8 @@ void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const
}
}
- TreeElementOverridesData data = {id, *override_prop, is_rna_path_valid};
+ TreeElementOverridesData data = {
+ id, *override_prop, override_rna_ptr, *override_rna_prop, is_rna_path_valid};
outliner_add_element(
&space_outliner, &legacy_te_.subtree, &data, &legacy_te_, TSE_LIBRARY_OVERRIDE, index++);
}
@@ -81,11 +82,13 @@ void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const
TreeElementOverridesProperty::TreeElementOverridesProperty(TreeElement &legacy_te,
TreeElementOverridesData &override_data)
- : AbstractTreeElement(legacy_te), override_prop_(override_data.override_property)
+ : AbstractTreeElement(legacy_te),
+ override_rna_ptr(override_data.override_rna_ptr),
+ override_rna_prop(override_data.override_rna_prop)
{
BLI_assert(legacy_te.store_elem->type == TSE_LIBRARY_OVERRIDE);
- legacy_te.name = override_prop_.rna_path;
+ legacy_te.name = override_data.override_property.rna_path;
/* Abusing this for now, better way to do it is also pending current refactor of the whole tree
* code to use C++. */
legacy_te.directdata = POINTER_FROM_UINT(override_data.is_rna_path_valid);
diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
index 1987efcf6f6..a2d1409f193 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
+++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh
@@ -6,13 +6,21 @@
#pragma once
+#include "RNA_types.h"
+
#include "tree_element.hh"
+struct ID;
+struct IDOverrideLibraryProperty;
+
namespace blender::ed::outliner {
struct TreeElementOverridesData {
ID &id;
IDOverrideLibraryProperty &override_property;
+ PointerRNA &override_rna_ptr;
+ PropertyRNA &override_rna_prop;
+
bool is_rna_path_valid;
};
@@ -27,7 +35,9 @@ class TreeElementOverridesBase final : public AbstractTreeElement {
};
class TreeElementOverridesProperty final : public AbstractTreeElement {
- IDOverrideLibraryProperty &override_prop_;
+ public:
+ PointerRNA override_rna_ptr;
+ PropertyRNA &override_rna_prop;
public:
TreeElementOverridesProperty(TreeElement &legacy_te, TreeElementOverridesData &override_data);
diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.cc b/source/blender/editors/space_outliner/tree/tree_element_rna.cc
index abc7cd8f8ce..914104f1f06 100644
--- a/source/blender/editors/space_outliner/tree/tree_element_rna.cc
+++ b/source/blender/editors/space_outliner/tree/tree_element_rna.cc
@@ -52,7 +52,7 @@ bool TreeElementRNACommon::isRNAValid() const
return rna_ptr_.data != nullptr;
}
-bool TreeElementRNACommon::expandPoll(const SpaceOutliner &) const
+bool TreeElementRNACommon::expandPoll(const SpaceOutliner &UNUSED(space_outliner)) const
{
return isRNAValid();
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 9370b349cb4..0ed366209f6 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -2681,7 +2681,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
Editing *ed = SEQ_editing_get(scene);
SpaceSeq *sseq = CTX_wm_space_seq(C);
View2D *v2d = &region->v2d;
- short cfra_flag = 0;
float col[3];
seq_prefetch_wm_notify(C, scene);
@@ -2728,9 +2727,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
}
UI_view2d_view_ortho(v2d);
- if ((sseq->flag & SEQ_DRAWFRAMES) == 0) {
- cfra_flag |= DRAWCFRA_UNIT_SECONDS;
- }
UI_view2d_view_orthoSpecial(region, v2d, 1);
int marker_draw_flag = DRAW_MARKERS_MARGIN;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
index 964738ff2c1..19fe61f0ed3 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -5,6 +5,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_color.hh"
+#include "BLI_cpp_type.hh"
#include "BLI_hash.hh"
#include "BLI_math_vec_types.hh"
#include "BLI_string.h"
@@ -12,14 +13,12 @@
#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)
+eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type)
{
if (type.is<bool>()) {
return SPREADSHEET_VALUE_TYPE_BOOL;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
index 454518016bc..7cf9238d34e 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh
@@ -4,15 +4,14 @@
#include "DNA_space_types.h"
+#include "BLI_generic_virtual_array.hh"
#include "BLI_string_ref.hh"
-#include "FN_generic_virtual_array.hh"
-
namespace blender::ed::spreadsheet {
struct CellDrawParams;
-eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type);
+eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type);
/**
* This represents a column in a spreadsheet. It has a name and provides a value for all the cells
@@ -22,10 +21,10 @@ class ColumnValues final {
protected:
std::string name_;
- fn::GVArray data_;
+ GVArray data_;
public:
- ColumnValues(std::string name, fn::GVArray data) : name_(std::move(name)), data_(std::move(data))
+ ColumnValues(std::string name, GVArray data) : name_(std::move(name)), data_(std::move(data))
{
/* The array should not be empty. */
BLI_assert(data_);
@@ -48,7 +47,7 @@ class ColumnValues final {
return data_.size();
}
- const fn::GVArray &data() const
+ const GVArray &data() const
{
return data_;
}
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 3c94c466da1..0ad64db1b6d 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -53,11 +53,11 @@ void ExtraColumns::foreach_default_column_ids(
std::unique_ptr<ColumnValues> ExtraColumns::get_column_values(
const SpreadsheetColumnID &column_id) const
{
- const fn::GSpan *values = columns_.lookup_ptr(column_id.name);
+ const GSpan *values = columns_.lookup_ptr(column_id.name);
if (values == nullptr) {
return {};
}
- return std::make_unique<ColumnValues>(column_id.name, fn::GVArray::ForSpan(*values));
+ return std::make_unique<ColumnValues>(column_id.name, GVArray::ForSpan(*values));
}
void GeometryDataSource::foreach_default_column_ids(
@@ -199,7 +199,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
if (!attribute) {
return {};
}
- fn::GVArray varray = std::move(attribute.varray);
+ GVArray varray = std::move(attribute.varray);
if (attribute.domain != domain_) {
return {};
}
@@ -462,7 +462,7 @@ static void find_fields_to_evaluate(const SpaceSpreadsheet *sspreadsheet,
}
if (const geo_log::GenericValueLog *generic_value_log =
dynamic_cast<const geo_log::GenericValueLog *>(value_log)) {
- fn::GPointer value = generic_value_log->value();
+ GPointer value = generic_value_log->value();
r_fields.add("Viewer", fn::make_constant_field(*value.type(), value.get()));
}
}
@@ -508,7 +508,7 @@ class GeometryComponentCacheValue : public SpreadsheetCache::Value {
public:
/* Stores the result of fields evaluated on a geometry component. Without this, fields would have
* to be reevaluated on every redraw. */
- Map<std::pair<AttributeDomain, GField>, fn::GArray<>> arrays;
+ Map<std::pair<AttributeDomain, GField>, GArray<>> arrays;
};
static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
@@ -529,8 +529,8 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet,
const GField &field = item.value;
/* Use the cached evaluated array if it exists, otherwise evaluate the field now. */
- fn::GArray<> &evaluated_array = cache.arrays.lookup_or_add_cb({domain, field}, [&]() {
- fn::GArray<> evaluated_array(field.cpp_type(), domain_size);
+ GArray<> &evaluated_array = cache.arrays.lookup_or_add_cb({domain, field}, [&]() {
+ GArray<> evaluated_array(field.cpp_type(), domain_size);
bke::GeometryComponentFieldContext field_context{component, domain};
fn::FieldEvaluator field_evaluator{field_context, domain_size};
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 303f495e3df..8b281e5a558 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh
@@ -21,10 +21,10 @@ namespace blender::ed::spreadsheet {
class ExtraColumns {
private:
/** Maps column names to their data. The data is actually stored in the spreadsheet cache. */
- Map<std::string, fn::GSpan> columns_;
+ Map<std::string, GSpan> columns_;
public:
- void add(std::string name, fn::GSpan data)
+ void add(std::string name, GSpan data)
{
columns_.add(std::move(name), data);
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index 33fd7329e6d..db466f8ccf3 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -89,7 +89,7 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
return;
}
- const fn::GVArray &data = column.data();
+ const GVArray &data = column.data();
if (data.type().is<int>()) {
const int value = data.get<int>(real_index);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index 1fddd751d78..e45317c2a5c 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -42,7 +42,7 @@ static void apply_row_filter(const SpreadsheetRowFilter &row_filter,
Vector<int64_t> &new_indices)
{
const ColumnValues &column = *columns.lookup(row_filter.column_name);
- const fn::GVArray &column_data = column.data();
+ const GVArray &column_data = column.data();
if (column_data.type().is<float>()) {
const float value = row_filter.value_float;
switch (row_filter.operation) {
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 52b4fc1d8aa..d9388bc82ef 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -43,6 +43,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -1534,7 +1535,7 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* keyingset to use (dynamic enum) */
+ /* #Object.id.name to select (dynamic enum). */
prop = RNA_def_enum(ot->srna, "name", DummyRNA_NULL_items, 0, "Object Name", "");
RNA_def_enum_funcs(prop, object_select_menu_enum_itemf);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE);
@@ -1548,16 +1549,18 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-static Base *object_mouse_select_menu(bContext *C,
- ViewContext *vc,
- const GPUSelectResult *buffer,
- const int hits,
- const int mval[2],
- bool extend,
- bool deselect,
- bool toggle)
+/**
+ * \return True when a menu was activated.
+ */
+static bool object_mouse_select_menu(bContext *C,
+ ViewContext *vc,
+ const GPUSelectResult *buffer,
+ const int hits,
+ const int mval[2],
+ const struct SelectPick_Params *params,
+ Base **r_basact)
{
- short baseCount = 0;
+ int base_count = 0;
bool ok;
LinkNodePair linklist = {NULL, NULL};
@@ -1586,23 +1589,26 @@ static Base *object_mouse_select_menu(bContext *C,
}
if (ok) {
- baseCount++;
+ base_count++;
BLI_linklist_append(&linklist, base);
- if (baseCount == SEL_MENU_SIZE) {
+ if (base_count == SEL_MENU_SIZE) {
break;
}
}
}
CTX_DATA_END;
- if (baseCount == 0) {
- return NULL;
+ *r_basact = NULL;
+
+ if (base_count == 0) {
+ return false;
}
- if (baseCount == 1) {
+ if (base_count == 1) {
Base *base = (Base *)linklist.list->link;
BLI_linklist_free(linklist.list, NULL);
- return base;
+ *r_basact = base;
+ return false;
}
/* UI, full in static array values that we later use in an enum function */
@@ -1624,22 +1630,25 @@ static Base *object_mouse_select_menu(bContext *C,
PointerRNA ptr;
WM_operator_properties_create_ptr(&ptr, ot);
- RNA_boolean_set(&ptr, "extend", extend);
- RNA_boolean_set(&ptr, "deselect", deselect);
- RNA_boolean_set(&ptr, "toggle", toggle);
+ RNA_boolean_set(&ptr, "extend", params->sel_op == SEL_OP_ADD);
+ RNA_boolean_set(&ptr, "deselect", params->sel_op == SEL_OP_SUB);
+ RNA_boolean_set(&ptr, "toggle", params->sel_op == SEL_OP_XOR);
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, NULL);
WM_operator_properties_free(&ptr);
BLI_linklist_free(linklist.list, NULL);
- return NULL;
+ return true;
}
static int bone_select_menu_exec(bContext *C, wmOperator *op)
{
const int name_index = RNA_enum_get(op->ptr, "name");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect = RNA_boolean_get(op->ptr, "deselect");
- const bool toggle = RNA_boolean_get(op->ptr, "toggle");
+
+ const struct SelectPick_Params params = {
+ .sel_op = ED_select_op_from_booleans(RNA_boolean_get(op->ptr, "extend"),
+ RNA_boolean_get(op->ptr, "deselect"),
+ RNA_boolean_get(op->ptr, "toggle")),
+ };
View3D *v3d = CTX_wm_view3d(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1653,21 +1662,20 @@ static int bone_select_menu_exec(bContext *C, wmOperator *op)
BLI_assert(BASE_SELECTABLE(v3d, basact));
- if (basact->object->mode == OB_MODE_EDIT) {
+ if (basact->object->mode & OB_MODE_EDIT) {
EditBone *ebone = (EditBone *)object_mouse_select_menu_data[name_index].item_ptr;
- ED_armature_edit_select_pick_bone(C, basact, ebone, BONE_SELECTED, extend, deselect, toggle);
+ ED_armature_edit_select_pick_bone(C, basact, ebone, BONE_SELECTED, &params);
}
else {
bPoseChannel *pchan = (bPoseChannel *)object_mouse_select_menu_data[name_index].item_ptr;
- ED_armature_pose_select_pick_bone(
- view_layer, v3d, basact->object, pchan->bone, extend, deselect, toggle);
+ ED_armature_pose_select_pick_bone(view_layer, v3d, basact->object, pchan->bone, &params);
}
/* Weak but ensures we activate the menu again before using the enum. */
memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data));
/* We make the armature selected:
- * Not-selected active object in posemode won't work well for tools. */
+ * Not-selected active object in pose-mode won't work well for tools. */
ED_object_base_select(basact, BA_SELECT);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
@@ -1675,14 +1683,22 @@ static int bone_select_menu_exec(bContext *C, wmOperator *op)
/* In weight-paint, we use selected bone to select vertex-group,
* so don't switch to new active object. */
- if (oldbasact && (oldbasact->object->mode & OB_MODE_ALL_WEIGHT_PAINT)) {
- /* Prevent activating.
- * Selection causes this to be considered the 'active' pose in weight-paint mode.
- * Eventually this limitation may be removed.
- * For now, de-select all other pose objects deforming this mesh. */
- ED_armature_pose_select_in_wpaint_mode(view_layer, basact);
-
- basact = NULL;
+ if (oldbasact) {
+ if (basact->object->mode & OB_MODE_EDIT) {
+ /* Pass. */
+ }
+ else if (oldbasact->object->mode & OB_MODE_ALL_WEIGHT_PAINT) {
+ /* Prevent activating.
+ * Selection causes this to be considered the 'active' pose in weight-paint mode.
+ * Eventually this limitation may be removed.
+ * For now, de-select all other pose objects deforming this mesh. */
+ ED_armature_pose_select_in_wpaint_mode(view_layer, basact);
+ }
+ else {
+ if (oldbasact != basact) {
+ ED_object_base_activate(C, basact);
+ }
+ }
}
/* Undo? */
@@ -1712,7 +1728,7 @@ void VIEW3D_OT_bone_select_menu(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* keyingset to use (dynamic enum) */
+ /* #Object.id.name to select (dynamic enum). */
prop = RNA_def_enum(ot->srna, "name", DummyRNA_NULL_items, 0, "Bone Name", "");
RNA_def_enum_funcs(prop, object_select_menu_enum_itemf);
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE);
@@ -1725,17 +1741,19 @@ void VIEW3D_OT_bone_select_menu(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+
+/**
+ * \return True when a menu was activated.
+ */
static bool bone_mouse_select_menu(bContext *C,
const GPUSelectResult *buffer,
const int hits,
const bool is_editmode,
- const bool extend,
- const bool deselect,
- const bool toggle)
+ const struct SelectPick_Params *params)
{
BLI_assert(buffer);
- short baseCount = 0;
+ int bone_count = 0;
LinkNodePair base_list = {NULL, NULL};
LinkNodePair bone_list = {NULL, NULL};
GSet *added_bones = BLI_gset_ptr_new("Bone mouse select menu");
@@ -1794,12 +1812,12 @@ static bool bone_mouse_select_menu(bContext *C,
const bool is_duplicate_bone = BLI_gset_haskey(added_bones, bone_ptr);
if (!is_duplicate_bone) {
- baseCount++;
+ bone_count++;
BLI_linklist_append(&base_list, bone_base);
BLI_linklist_append(&bone_list, bone_ptr);
BLI_gset_insert(added_bones, bone_ptr);
- if (baseCount == SEL_MENU_SIZE) {
+ if (bone_count == SEL_MENU_SIZE) {
break;
}
}
@@ -1807,10 +1825,10 @@ static bool bone_mouse_select_menu(bContext *C,
BLI_gset_free(added_bones, NULL);
- if (baseCount == 0) {
+ if (bone_count == 0) {
return false;
}
- if (baseCount == 1) {
+ if (bone_count == 1) {
BLI_linklist_free(base_list.list, NULL);
BLI_linklist_free(bone_list.list, NULL);
return false;
@@ -1847,9 +1865,9 @@ static bool bone_mouse_select_menu(bContext *C,
PointerRNA ptr;
WM_operator_properties_create_ptr(&ptr, ot);
- RNA_boolean_set(&ptr, "extend", extend);
- RNA_boolean_set(&ptr, "deselect", deselect);
- RNA_boolean_set(&ptr, "toggle", toggle);
+ RNA_boolean_set(&ptr, "extend", params->sel_op == SEL_OP_ADD);
+ RNA_boolean_set(&ptr, "deselect", params->sel_op == SEL_OP_SUB);
+ RNA_boolean_set(&ptr, "toggle", params->sel_op == SEL_OP_XOR);
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, NULL);
WM_operator_properties_free(&ptr);
@@ -2030,6 +2048,40 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc,
}
/**
+ * Compare result of 'GPU_select': 'GPUSelectResult',
+ * Needed for stable sorting, so cycling through all items near the cursor behaves predictably.
+ */
+static int gpu_select_buffer_depth_id_cmp(const void *sel_a_p, const void *sel_b_p)
+{
+ GPUSelectResult *a = (GPUSelectResult *)sel_a_p;
+ GPUSelectResult *b = (GPUSelectResult *)sel_b_p;
+
+ if (a->depth < b->depth) {
+ return -1;
+ }
+ if (a->depth > b->depth) {
+ return 1;
+ }
+
+ /* Depths match, sort by id. */
+ uint sel_a = a->id;
+ uint sel_b = b->id;
+
+#ifdef __BIG_ENDIAN__
+ BLI_endian_switch_uint32(&sel_a);
+ BLI_endian_switch_uint32(&sel_b);
+#endif
+
+ if (sel_a < sel_b) {
+ return -1;
+ }
+ if (sel_a > sel_b) {
+ return 1;
+ }
+ return 0;
+}
+
+/**
* \param has_bones: When true, skip non-bone hits, also allow bases to be used
* that are visible but not select-able,
* since you may be in pose mode with an un-selectable object.
@@ -2039,115 +2091,204 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc,
static Base *mouse_select_eval_buffer(ViewContext *vc,
const GPUSelectResult *buffer,
int hits,
- Base *startbase,
- bool has_bones,
bool do_nearest,
- int *r_sub_selection)
+ bool has_bones,
+ bool do_bones_get_priotity,
+ int *r_select_id_subelem)
{
ViewLayer *view_layer = vc->view_layer;
View3D *v3d = vc->v3d;
- Base *base, *basact = NULL;
int a;
- int sub_selection_id = 0;
+
+ bool found = false;
+ int select_id = 0;
+ int select_id_subelem = 0;
if (do_nearest) {
uint min = 0xFFFFFFFF;
- int selcol = 0, notcol = 0;
+ int hit_index = -1;
- if (has_bones) {
+ if (has_bones && do_bones_get_priotity) {
/* we skip non-bone hits */
for (a = 0; a < hits; a++) {
if (min > buffer[a].depth && (buffer[a].id & 0xFFFF0000)) {
min = buffer[a].depth;
- selcol = buffer[a].id & 0xFFFF;
- sub_selection_id = (buffer[a].id & 0xFFFF0000) >> 16;
+ hit_index = a;
}
}
}
else {
- /* only exclude active object when it is selected... */
- if (BASACT(view_layer) && (BASACT(view_layer)->flag & BASE_SELECTED) && hits > 1) {
- notcol = BASACT(view_layer)->object->runtime.select_id;
- }
for (a = 0; a < hits; a++) {
- if (min > buffer[a].depth && notcol != (buffer[a].id & 0xFFFF)) {
+ /* Any object. */
+ if (min > buffer[a].depth) {
min = buffer[a].depth;
- selcol = buffer[a].id & 0xFFFF;
- sub_selection_id = (buffer[a].id & 0xFFFF0000) >> 16;
+ hit_index = a;
}
}
- }
- base = FIRSTBASE(view_layer);
- while (base) {
- if (has_bones ? BASE_VISIBLE(v3d, base) : BASE_SELECTABLE(v3d, base)) {
- if (base->object->runtime.select_id == selcol) {
- break;
+ /* Find the best active & non-active hits.
+ * NOTE(@campbellbarton): Checking if `hits > 1` isn't a reliable way to know
+ * if there are multiple objects selected since it's possible the same object
+ * generates multiple hits, either from:
+ * - Multiple sub-components (bones & camera tracks).
+ * - Multiple selectable elements such as the object center and the geometry.
+ *
+ * For this reason, keep track of the best hit as well as the best hit that
+ * excludes the selected & active object, using this value when it's valid. */
+ if ((hit_index != -1) &&
+ /* Special case, cycling away from the active object should only be done when it
+ * doesn't have a bone selection, otherwise selecting sub-elements is difficult. */
+ ((buffer[hit_index].id & 0xFFFF0000) == 0) &&
+ /* Only exclude active object when it is selected. */
+ (BASACT(view_layer) && (BASACT(view_layer)->flag & BASE_SELECTED)) &&
+ /* Allow disabling this behavior entirely. */
+ (U.experimental.use_select_nearest_on_first_click == false)) {
+
+ const int select_id_active = BASACT(view_layer)->object->runtime.select_id;
+
+ /* Check if `hit_index` is the current active object. */
+ if ((buffer[hit_index].id & 0xFFFF) == select_id_active) {
+ uint min_not_active = 0xFFFFFFFF;
+ int hit_index_not_active = -1;
+ for (a = 0; a < hits; a++) {
+ /* Any object other than the active-selected. */
+ if (select_id_active == (buffer[a].id & 0xFFFF)) {
+ continue;
+ }
+ if (min_not_active > buffer[a].depth) {
+ min_not_active = buffer[a].depth;
+ hit_index_not_active = a;
+ }
+ }
+
+ /* When the active was selected, first try to use the index
+ * for the best non-active hit that was found. */
+ if (hit_index_not_active != -1) {
+ hit_index = hit_index_not_active;
+ }
}
}
- base = base->next;
}
- if (base) {
- basact = base;
+
+ if (hit_index != -1) {
+ select_id = buffer[hit_index].id & 0xFFFF;
+ select_id_subelem = (buffer[hit_index].id & 0xFFFF0000) >> 16;
+ found = true;
+ /* No need to set `min` to `buffer[hit_index].depth`, it's not used from now on. */
}
}
else {
- base = startbase;
- while (base) {
- /* skip objects with select restriction, to prevent prematurely ending this loop
- * with an un-selectable choice */
- if (has_bones ? (base->flag & BASE_VISIBLE_VIEWLAYER) == 0 :
- (base->flag & BASE_SELECTABLE) == 0) {
- base = base->next;
- if (base == NULL) {
- base = FIRSTBASE(view_layer);
- }
- if (base == startbase) {
- break;
+ {
+ GPUSelectResult *buffer_sorted = MEM_mallocN(sizeof(*buffer_sorted) * hits, __func__);
+ memcpy(buffer_sorted, buffer, sizeof(*buffer_sorted) * hits);
+ /* Remove non-bone objects. */
+ if (has_bones && do_bones_get_priotity) {
+ /* Loop backwards to reduce re-ordering. */
+ for (a = hits - 1; a >= 0; a--) {
+ if ((buffer_sorted[a].id & 0xFFFF0000) == 0) {
+ buffer_sorted[a] = buffer_sorted[--hits];
+ }
}
}
+ qsort(buffer_sorted, hits, sizeof(GPUSelectResult), gpu_select_buffer_depth_id_cmp);
+ buffer = buffer_sorted;
+ }
- if (has_bones ? BASE_VISIBLE(v3d, base) : BASE_SELECTABLE(v3d, base)) {
- for (a = 0; a < hits; a++) {
- if (has_bones) {
- /* skip non-bone objects */
- if (buffer[a].id & 0xFFFF0000) {
- if (base->object->runtime.select_id == (buffer[a].id & 0xFFFF)) {
- basact = base;
- }
- }
- }
- else {
- if (base->object->runtime.select_id == (buffer[a].id & 0xFFFF)) {
- basact = base;
- }
+ int hit_index = -1;
+
+ /* It's possible there are no hits (all objects contained bones). */
+ if (hits > 0) {
+ /* Only exclude active object when it is selected. */
+ if (BASACT(view_layer) && (BASACT(view_layer)->flag & BASE_SELECTED)) {
+ const int select_id_active = BASACT(view_layer)->object->runtime.select_id;
+ for (int i_next = 0, i_prev = hits - 1; i_next < hits; i_prev = i_next++) {
+ if ((select_id_active == (buffer[i_prev].id & 0xFFFF)) &&
+ (select_id_active != (buffer[i_next].id & 0xFFFF))) {
+ hit_index = i_next;
+ break;
}
}
}
- if (basact) {
- break;
+ /* When the active object is unselected or not in `buffer`, use the nearest. */
+ if (hit_index == -1) {
+ /* Just pick the nearest. */
+ hit_index = 0;
}
+ }
- base = base->next;
- if (base == NULL) {
- base = FIRSTBASE(view_layer);
- }
- if (base == startbase) {
- break;
- }
+ if (hit_index != -1) {
+ select_id = buffer[hit_index].id & 0xFFFF;
+ select_id_subelem = (buffer[hit_index].id & 0xFFFF0000) >> 16;
+ found = true;
}
+ MEM_freeN((void *)buffer);
}
- if (basact && r_sub_selection) {
- *r_sub_selection = sub_selection_id;
+ Base *basact = NULL;
+ if (found) {
+ for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
+ if (has_bones ? BASE_VISIBLE(v3d, base) : BASE_SELECTABLE(v3d, base)) {
+ if (base->object->runtime.select_id == select_id) {
+ basact = base;
+ break;
+ }
+ }
+ }
+
+ if (basact && r_select_id_subelem) {
+ *r_select_id_subelem = select_id_subelem;
+ }
}
return basact;
}
+static Base *mouse_select_object_center(ViewContext *vc, Base *startbase, const int mval[2])
+{
+ ARegion *region = vc->region;
+ ViewLayer *view_layer = vc->view_layer;
+ View3D *v3d = vc->v3d;
+
+ Base *oldbasact = BASACT(view_layer);
+
+ const float mval_fl[2] = {(float)mval[0], (float)mval[1]};
+ float dist = ED_view3d_select_dist_px() * 1.3333f;
+ Base *basact = NULL;
+
+ /* Put the active object at a disadvantage to cycle through other objects. */
+ const float penalty_dist = 10.0f * UI_DPI_FAC;
+ Base *base = startbase;
+ while (base) {
+ if (BASE_SELECTABLE(v3d, base)) {
+ float screen_co[2];
+ if (ED_view3d_project_float_global(
+ region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) ==
+ V3D_PROJ_RET_OK) {
+ float dist_test = len_manhattan_v2v2(mval_fl, screen_co);
+ if (base == oldbasact) {
+ dist_test += penalty_dist;
+ }
+ if (dist_test < dist) {
+ dist = dist_test;
+ basact = base;
+ }
+ }
+ }
+ base = base->next;
+
+ if (base == NULL) {
+ base = FIRSTBASE(view_layer);
+ }
+ if (base == startbase) {
+ break;
+ }
+ }
+ return basact;
+}
+
static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
const int mval[2],
int *r_material_slot)
@@ -2176,13 +2317,8 @@ static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
if (hits > 0) {
const bool has_bones = (r_material_slot == NULL) && selectbuffer_has_bones(buffer, hits);
- basact = mouse_select_eval_buffer(&vc,
- buffer,
- hits,
- vc.view_layer->object_bases.first,
- has_bones,
- do_nearest,
- r_material_slot);
+ basact = mouse_select_eval_buffer(
+ &vc, buffer, hits, do_nearest, has_bones, true, r_material_slot);
}
return basact;
@@ -2237,346 +2373,483 @@ static void deselect_all_tracks(MovieTracking *tracking)
}
}
-/* mval is region coords */
-static bool ed_object_select_pick(bContext *C,
- const int mval[2],
- bool extend,
- bool deselect,
- bool toggle,
- bool obcenter,
- bool enumerate,
- bool object)
+static bool ed_object_select_pick_camera_track(bContext *C,
+ Scene *scene,
+ Base *basact,
+ MovieClip *clip,
+ const struct GPUSelectResult *buffer,
+ const short hits,
+ const struct SelectPick_Params *params)
{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ViewContext vc;
- /* setup view context for argument to callbacks */
- ED_view3d_viewcontext_init(C, &vc, depsgraph);
+ bool changed = false;
+ bool found = false;
- const ARegion *region = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = CTX_wm_view3d(C);
- /* Don't set when the context has no active object (hidden), see: T60807. */
- const Base *oldbasact = vc.obact ? BASACT(view_layer) : NULL;
- Base *base, *startbase = NULL, *basact = NULL;
- const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT;
- bool is_obedit;
- float dist = ED_view3d_select_dist_px() * 1.3333f;
- bool retval = false;
- int hits;
- const float mval_fl[2] = {(float)mval[0], (float)mval[1]};
+ MovieTracking *tracking = &clip->tracking;
+ ListBase *tracksbase = NULL;
+ MovieTrackingTrack *track = NULL;
- is_obedit = (vc.obedit != NULL);
- if (object) {
- /* Signal for #view3d_opengl_select to skip edit-mode objects. */
- vc.obedit = NULL;
- }
+ for (int i = 0; i < hits; i++) {
+ const int hitresult = buffer[i].id;
- /* In pose mode we don't want to mess with object selection. */
- const bool is_pose_mode = (vc.obact && vc.obact->mode & OB_MODE_POSE);
+ /* If there's bundles in buffer select bundles first,
+ * so non-camera elements should be ignored in buffer. */
+ if (basact->object->runtime.select_id != (hitresult & 0xFFFF)) {
+ continue;
+ }
+ /* Index of bundle is 1<<16-based. if there's no "bone" index
+ * in height word, this buffer value belongs to camera. not to bundle. */
+ if ((hitresult & 0xFFFF0000) == 0) {
+ continue;
+ }
- /* always start list from basact in wire mode */
- startbase = FIRSTBASE(view_layer);
- if (oldbasact && oldbasact->next) {
- startbase = oldbasact->next;
+ track = BKE_tracking_track_get_indexed(&clip->tracking, hitresult >> 16, &tracksbase);
+ found = true;
+ break;
}
- /* This block uses the control key to make the object selected
- * by its center point rather than its contents */
-
- /* In edit-mode do not activate. */
- if (obcenter) {
-
- /* NOTE: shift+alt goes to group-flush-selecting. */
- if (enumerate) {
- basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, extend, deselect, toggle);
+ /* Note `params->deselect_all` is ignored for tracks as in this case
+ * all objects will be de-selected (not tracks). */
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) && TRACK_SELECTED(track)) {
+ found = false;
}
- else {
- base = startbase;
- while (base) {
- if (BASE_SELECTABLE(v3d, base)) {
- float screen_co[2];
- if (ED_view3d_project_float_global(
- region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) ==
- V3D_PROJ_RET_OK) {
- float dist_temp = len_manhattan_v2v2(mval_fl, screen_co);
- if (base == oldbasact) {
- dist_temp += 10.0f;
- }
- if (dist_temp < dist) {
- dist = dist_temp;
- basact = base;
- }
- }
- }
- base = base->next;
+ else if (found /* `|| params->deselect_all` */) {
+ /* Deselect everything. */
+ deselect_all_tracks(tracking);
+ changed = true;
+ }
+ }
- if (base == NULL) {
- base = FIRSTBASE(view_layer);
+ if (found) {
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, true);
+ break;
+ }
+ case SEL_OP_SUB: {
+ BKE_tracking_track_deselect(track, TRACK_AREA_ALL);
+ break;
+ }
+ case SEL_OP_XOR: {
+ if (TRACK_SELECTED(track)) {
+ BKE_tracking_track_deselect(track, TRACK_AREA_ALL);
}
- if (base == startbase) {
- break;
+ else {
+ BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, true);
}
+ break;
}
- }
- if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
- if (is_obedit == false) {
- if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
- if (object_mode == OB_MODE_OBJECT) {
- struct Main *bmain = CTX_data_main(C);
- ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
- }
- if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
- basact = NULL;
- }
- }
+ case SEL_OP_SET: {
+ BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, false);
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
}
}
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ DEG_id_tag_update(&clip->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_MOVIECLIP | ND_SELECT, track);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+
+ changed = true;
}
- else {
- GPUSelectResult buffer[MAXPICKELEMS];
- bool do_nearest;
- // TIMEIT_START(select_time);
+ return changed || found;
+}
- /* if objects have posemode set, the bones are in the same selection buffer */
- const eV3DSelectObjectFilter select_filter = ((object == false) ?
- ED_view3d_select_filter_from_mode(scene,
- vc.obact) :
- VIEW3D_SELECT_FILTER_NOP);
- hits = mixed_bones_object_selectbuffer_extended(
- &vc, buffer, ARRAY_SIZE(buffer), mval, select_filter, true, enumerate, &do_nearest);
+/**
+ * Cursor selection picking for object & pose-mode.
+ *
+ * \param mval: Region relative cursor coordinates.
+ * \param params: Selection parameters.
+ * \param center: Select by the cursors on-screen distances to the center/origin
+ * instead of the geometry any other contents of the item being selected.
+ * This could be used to select by bones by their origin too, currently it's only used for objects.
+ * \param enumerate: Show a menu for objects at the cursor location.
+ * Otherwise fall-through to non-menu selection.
+ * \param object_only: Only select objects (not bones / track markers).
+ */
+static bool ed_object_select_pick(bContext *C,
+ const int mval[2],
+ const struct SelectPick_Params *params,
+ const bool center,
+ const bool enumerate,
+ const bool object_only)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ViewContext vc;
+ /* Setup view context for argument to callbacks. */
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
- // TIMEIT_END(select_time);
+ Scene *scene = vc.scene;
+ View3D *v3d = vc.v3d;
- if (hits > 0) {
- /* NOTE: bundles are handling in the same way as bones. */
- const bool has_bones = object ? false : selectbuffer_has_bones(buffer, hits);
+ /* Menu activation may find a base to make active (if it only finds a single item to select). */
+ Base *basact_override = NULL;
- /* NOTE: shift+alt goes to group-flush-selecting. */
- if (enumerate) {
- if (has_bones &&
- bone_mouse_select_menu(C, buffer, hits, false, extend, deselect, toggle)) {
- basact = NULL;
+ const bool is_obedit = (vc.obedit != NULL);
+ if (object_only) {
+ /* Signal for #view3d_opengl_select to skip edit-mode objects. */
+ vc.obedit = NULL;
+ }
+
+ /* Set for GPU depth buffer picking, leave NULL when selecting by center. */
+ struct {
+ GPUSelectResult buffer[MAXPICKELEMS];
+ int hits;
+ bool do_nearest;
+ bool has_bones;
+ } *gpu = NULL;
+
+ /* First handle menu selection, early exit if a menu opens
+ * since this takes ownership of the selection action.
+ *
+ * Even when there is no menu `basact_override` may be set to avoid having to re-find
+ * the item under the cursor. */
+
+ if (center == false) {
+ gpu = MEM_mallocN(sizeof(*gpu), __func__);
+ gpu->do_nearest = false;
+ gpu->has_bones = false;
+
+ /* If objects have pose-mode set, the bones are in the same selection buffer. */
+ const eV3DSelectObjectFilter select_filter = ((object_only == false) ?
+ ED_view3d_select_filter_from_mode(scene,
+ vc.obact) :
+ VIEW3D_SELECT_FILTER_NOP);
+ gpu->hits = mixed_bones_object_selectbuffer_extended(&vc,
+ gpu->buffer,
+ ARRAY_SIZE(gpu->buffer),
+ mval,
+ select_filter,
+ true,
+ enumerate,
+ &gpu->do_nearest);
+ gpu->has_bones = (object_only && gpu->hits > 0) ?
+ false :
+ selectbuffer_has_bones(gpu->buffer, gpu->hits);
+ }
+
+ /* First handle menu selection, early exit when a menu was opened.
+ * Otherwise fall through to regular selection. */
+ if (enumerate) {
+ bool has_menu = false;
+ if (center) {
+ if (object_mouse_select_menu(C, &vc, NULL, 0, mval, params, &basact_override)) {
+ has_menu = true;
+ }
+ }
+ else {
+ if (gpu->hits != 0) {
+ if (gpu->has_bones && bone_mouse_select_menu(C, gpu->buffer, gpu->hits, false, params)) {
+ has_menu = true;
}
- else {
- basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, extend, deselect, toggle);
+ else if (object_mouse_select_menu(
+ C, &vc, gpu->buffer, gpu->hits, mval, params, &basact_override)) {
+ has_menu = true;
}
}
- else {
- basact = mouse_select_eval_buffer(
- &vc, buffer, hits, startbase, has_bones, do_nearest, NULL);
- }
-
- if (has_bones && basact) {
- if (basact->object->type == OB_CAMERA) {
- MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false);
- if (clip != NULL && oldbasact == basact) {
- bool changed = false;
-
- for (int i = 0; i < hits; i++) {
- const int hitresult = buffer[i].id;
-
- /* if there's bundles in buffer select bundles first,
- * so non-camera elements should be ignored in buffer */
- if (basact->object->runtime.select_id != (hitresult & 0xFFFF)) {
- continue;
- }
-
- /* index of bundle is 1<<16-based. if there's no "bone" index
- * in height word, this buffer value belongs to camera. not to bundle
- */
- if (hitresult & 0xFFFF0000) {
- MovieTracking *tracking = &clip->tracking;
- ListBase *tracksbase;
- MovieTrackingTrack *track;
-
- track = BKE_tracking_track_get_indexed(
- &clip->tracking, hitresult >> 16, &tracksbase);
+ }
- if (TRACK_SELECTED(track) && extend) {
- changed = false;
- BKE_tracking_track_deselect(track, TRACK_AREA_ALL);
- }
- else {
- int oldsel = TRACK_SELECTED(track) ? 1 : 0;
- if (!extend) {
- deselect_all_tracks(tracking);
- }
+ /* Let the menu handle any further actions. */
+ if (has_menu) {
+ if (gpu != NULL) {
+ MEM_freeN(gpu);
+ }
+ return false;
+ }
+ }
- BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, extend);
+ /* No menu, continue with selection. */
- if (oldsel != (TRACK_SELECTED(track) ? 1 : 0)) {
- changed = true;
- }
- }
+ ViewLayer *view_layer = vc.view_layer;
+ /* Don't set when the context has no active object (hidden), see: T60807. */
+ const Base *oldbasact = vc.obact ? BASACT(view_layer) : NULL;
+ /* Always start list from `basact` when cycling the selection. */
+ Base *startbase = (oldbasact && oldbasact->next) ? oldbasact->next : FIRSTBASE(view_layer);
- ED_object_base_select(basact, BA_SELECT);
+ /* The next object's base to make active. */
+ Base *basact = NULL;
+ const eObjectMode object_mode = oldbasact ? oldbasact->object->mode : OB_MODE_OBJECT;
- retval = true;
+ /* When enabled, don't attempt any further selection. */
+ bool handled = false;
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- DEG_id_tag_update(&clip->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_MOVIECLIP | ND_SELECT, track);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ /* Split `changed` into data-types so their associated updates can be properly performed.
+ * This is also needed as multiple changes may happen at once.
+ * Selecting a pose-bone or track can also select the object for e.g. */
+ bool changed_object = false;
+ bool changed_pose = false;
+ bool changed_track = false;
- break;
- }
- }
+ /* Handle setting the new base active (even when `handled == true`). */
+ bool use_activate_selected_base = false;
- if (!changed) {
- /* fallback to regular object selection if no new bundles were selected,
- * allows to select object parented to reconstruction object */
- basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest, NULL);
- }
+ if (center) {
+ if (basact_override) {
+ basact = basact_override;
+ }
+ else {
+ basact = mouse_select_object_center(&vc, startbase, mval);
+ }
+ }
+ else {
+ if (basact_override) {
+ basact = basact_override;
+ }
+ else {
+ /* Regarding bone priority.
+ *
+ * - When in pose-bone, it's useful that any selection containing a bone
+ * gets priority over other geometry (background scenery for example).
+ *
+ * - When in object-mode, don't prioritize bones as it would cause
+ * pose-objects behind other objects to get priority
+ * (mainly noticeable when #SCE_OBJECT_MODE_LOCK is disabled).
+ *
+ * This way prioritizing based on pose-mode has a bias to stay in pose-mode
+ * without having to enforce this through locking the object mode. */
+ bool do_bones_get_priotity = (object_mode & OB_MODE_POSE) != 0;
+
+ basact = (gpu->hits > 0) ? mouse_select_eval_buffer(&vc,
+ gpu->buffer,
+ gpu->hits,
+ gpu->do_nearest,
+ gpu->has_bones,
+ do_bones_get_priotity,
+ NULL) :
+ NULL;
+ }
+
+ /* Select pose-bones or camera-tracks. */
+ if (((gpu->hits > 0) && gpu->has_bones) ||
+ /* Special case, even when there are no hits, pose logic may de-select all bones. */
+ ((gpu->hits == 0) && (object_mode & OB_MODE_POSE))) {
+
+ if (basact && (gpu->has_bones && (basact->object->type == OB_CAMERA))) {
+ MovieClip *clip = BKE_object_movieclip_get(scene, basact->object, false);
+ if (clip != NULL) {
+ if (ed_object_select_pick_camera_track(
+ C, scene, basact, clip, gpu->buffer, gpu->hits, params)) {
+ ED_object_base_select(basact, BA_SELECT);
+ /* Don't set `handled` here as the object activation may be necessary. */
+ changed_object = true;
+
+ changed_track = true;
+ }
+ else {
+ /* Fallback to regular object selection if no new bundles were selected,
+ * allows to select object parented to reconstruction object. */
+ basact = mouse_select_eval_buffer(
+ &vc, gpu->buffer, gpu->hits, gpu->do_nearest, false, false, NULL);
}
}
- else if (ED_armature_pose_select_pick_with_buffer(view_layer,
- v3d,
- basact,
- buffer,
- hits,
- extend,
- deselect,
- toggle,
- do_nearest)) {
- /* then bone is found */
-
- /* we make the armature selected:
- * not-selected active object in posemode won't work well for tools */
+ }
+ else if (ED_armature_pose_select_pick_with_buffer(view_layer,
+ v3d,
+ basact ? basact : (Base *)oldbasact,
+ gpu->buffer,
+ gpu->hits,
+ params,
+ gpu->do_nearest)) {
+
+ changed_pose = true;
+
+ /* When there is no `baseact` this will have operated on `oldbasact`,
+ * allowing #SelectPick_Params.deselect_all work in pose-mode.
+ * In this case no object operations are needed. */
+ if (basact != NULL) {
+ /* By convention the armature-object is selected when in pose-mode.
+ * While leaving it unselected will work, leaving pose-mode would leave the object
+ * active + unselected which isn't ideal when performing other actions on the object. */
ED_object_base_select(basact, BA_SELECT);
+ changed_object = true;
- retval = true;
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, basact->object);
- DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
- /* In weight-paint, we use selected bone to select vertex-group,
- * so don't switch to new active object. */
- if (oldbasact && (oldbasact->object->mode & OB_MODE_ALL_WEIGHT_PAINT)) {
- /* Prevent activating.
- * Selection causes this to be considered the 'active' pose in weight-paint mode.
- * Eventually this limitation may be removed.
- * For now, de-select all other pose objects deforming this mesh. */
- ED_armature_pose_select_in_wpaint_mode(view_layer, basact);
+ /* In weight-paint, we use selected bone to select vertex-group.
+ * In this case the active object mustn't change as it would leave weight-paint mode. */
+ if (oldbasact) {
+ if (oldbasact->object->mode & OB_MODE_ALL_WEIGHT_PAINT) {
+ /* Prevent activating.
+ * Selection causes this to be considered the 'active' pose in weight-paint mode.
+ * Eventually this limitation may be removed.
+ * For now, de-select all other pose objects deforming this mesh. */
+ ED_armature_pose_select_in_wpaint_mode(view_layer, basact);
+
+ handled = true;
+ }
+ else if ((object_mode & OB_MODE_POSE) && (basact->object->mode & OB_MODE_POSE)) {
+ /* Within pose-mode, keep the current selection when switching pose bones,
+ * this is noticeable when in pose mode with multiple objects at once.
+ * Where selecting the bone of a different object would de-select this one.
+ * After that, exiting pose-mode would only have the active armature selected.
+ * This matches multi-object edit-mode behavior. */
+ handled = true;
+
+ if (oldbasact != basact) {
+ use_activate_selected_base = true;
+ }
+ }
+ else {
+ /* Don't set `handled` here as the object selection may be necessary
+ * when starting out in object-mode and moving into pose-mode,
+ * when moving from pose to object-mode using object selection also makes sense. */
+ }
+ }
+ }
+ }
+ /* Prevent bone/track selecting to pass on to object selecting. */
+ if (basact == oldbasact) {
+ handled = true;
+ }
+ }
+ }
+ if (handled == false) {
+ if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
+ /* No special logic in edit-mode. */
+ if (is_obedit == false) {
+ if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
+ if (object_mode == OB_MODE_OBJECT) {
+ struct Main *bmain = vc.bmain;
+ ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
+ }
+ if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
basact = NULL;
}
}
- /* prevent bone selecting to pass on to object selecting */
- if (basact == oldbasact) {
- basact = NULL;
- }
- }
- if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
- if (is_obedit == false) {
- if (basact && !BKE_object_is_mode_compat(basact->object, object_mode)) {
- if (object_mode == OB_MODE_OBJECT) {
- struct Main *bmain = CTX_data_main(C);
- ED_object_mode_generic_exit(bmain, vc.depsgraph, scene, basact->object);
- }
- if (!BKE_object_is_mode_compat(basact->object, object_mode)) {
- basact = NULL;
- }
+ /* Disallow switching modes,
+ * special exception for edit-mode - vertex-parent operator. */
+ if (basact && oldbasact) {
+ if ((oldbasact->object->mode != basact->object->mode) &&
+ (oldbasact->object->mode & basact->object->mode) == 0) {
+ basact = NULL;
}
}
}
}
}
- if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) {
- /* Disallow switching modes,
- * special exception for edit-mode - vertex-parent operator. */
- if (is_obedit == false) {
- if (oldbasact && basact) {
- if ((oldbasact->object->mode != basact->object->mode) &&
- (oldbasact->object->mode & basact->object->mode) == 0) {
- basact = NULL;
+ /* Ensure code above doesn't change the active base. This code is already fairly involved,
+ * it's best if changing the active object is localized to a single place. */
+ BLI_assert(oldbasact == (vc.obact ? BASACT(view_layer) : NULL));
+
+ bool found = (basact != NULL);
+ if ((handled == false) && (vc.obedit == NULL)) {
+ /* Object-mode (pose mode will have been handled already). */
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) && (basact->flag & BASE_SELECTED)) {
+ found = false;
+ /* NOTE(@campbellbarton): Experimental behavior to set active even keeping the selection
+ * without this it's inconvenient to set the active object. */
+ if (basact != oldbasact) {
+ use_activate_selected_base = true;
+ }
+ }
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
+ /* `basact` may be NULL. */
+ if (ED_view3d_object_deselect_all_except(view_layer, basact)) {
+ changed_object = true;
}
}
}
}
- /* Ensure code above doesn't change the active base. */
- BLI_assert(oldbasact == (vc.obact ? BASACT(view_layer) : NULL));
-
- /* so, do we have something selected? */
- if (basact) {
- retval = true;
+ if ((handled == false) && found) {
if (vc.obedit) {
- /* only do select */
+ /* Only do the select (use for setting vertex parents & hooks).
+ * In edit-mode do not activate. */
ED_view3d_object_deselect_all_except(view_layer, basact);
ED_object_base_select(basact, BA_SELECT);
+
+ changed_object = true;
}
- /* also prevent making it active on mouse selection */
+ /* Also prevent making it active on mouse selection. */
else if (BASE_SELECTABLE(v3d, basact)) {
- const bool use_activate_selected_base = (oldbasact != basact) && (is_obedit == false);
- if (extend) {
- ED_object_base_select(basact, BA_SELECT);
- }
- else if (deselect) {
- ED_object_base_select(basact, BA_DESELECT);
- }
- else if (toggle) {
- if (basact->flag & BASE_SELECTED) {
- /* Keep selected if the base is to be activated. */
- if (use_activate_selected_base == false) {
- ED_object_base_select(basact, BA_DESELECT);
- }
- }
- else {
+ use_activate_selected_base |= (oldbasact != basact) && (is_obedit == false);
+
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
ED_object_base_select(basact, BA_SELECT);
+ break;
}
- }
- else {
- /* When enabled, this puts other objects out of multi pose-mode. */
- if (is_pose_mode == false || (basact->object->mode & OB_MODE_POSE) == 0) {
+ case SEL_OP_SUB: {
+ ED_object_base_select(basact, BA_DESELECT);
+ break;
+ }
+ case SEL_OP_XOR: {
+ if (basact->flag & BASE_SELECTED) {
+ /* Keep selected if the base is to be activated. */
+ if (use_activate_selected_base == false) {
+ ED_object_base_select(basact, BA_DESELECT);
+ }
+ }
+ else {
+ ED_object_base_select(basact, BA_SELECT);
+ }
+ break;
+ }
+ case SEL_OP_SET: {
ED_view3d_object_deselect_all_except(view_layer, basact);
ED_object_base_select(basact, BA_SELECT);
+ break;
}
- }
-
- if (use_activate_selected_base) {
- ED_object_base_activate(C, basact); /* adds notifier */
- if ((scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) {
- WM_toolsystem_update_from_context_view3d(C);
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
}
}
- /* Set special modes for grease pencil
- * The grease pencil modes are not real modes, but a hack to make the interface
- * consistent, so need some tricks to keep UI synchronized */
- /* XXX: This stuff needs reviewing (Aligorith) */
- if (false && (((oldbasact) && oldbasact->object->type == OB_GPENCIL) ||
- (basact->object->type == OB_GPENCIL))) {
- /* set cursor */
- if (ELEM(basact->object->mode,
- OB_MODE_PAINT_GPENCIL,
- OB_MODE_SCULPT_GPENCIL,
- OB_MODE_WEIGHT_GPENCIL,
- OB_MODE_VERTEX_GPENCIL)) {
- ED_gpencil_toggle_brush_cursor(C, true, NULL);
- }
- else {
- /* TODO: maybe is better use restore */
- ED_gpencil_toggle_brush_cursor(C, false, NULL);
- }
- }
+ changed_object = true;
}
+ }
+ /* Perform the activation even when 'handled', since this is used to ensure
+ * the object from the pose-bone selected is also activated. */
+ if (use_activate_selected_base && (basact != NULL)) {
+ changed_object = true;
+ ED_object_base_activate(C, basact); /* adds notifier */
+ if ((scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) == 0) {
+ WM_toolsystem_update_from_context_view3d(C);
+ }
+ }
+
+ if (changed_object) {
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+
+ ED_outliner_select_sync_from_object_tag(C);
}
- return retval;
+ if (changed_pose) {
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+ }
+
+ if (gpu != NULL) {
+ MEM_freeN(gpu);
+ }
+
+ return (changed_object || changed_pose || changed_track);
}
-/* mouse selection in weight paint */
-/* gets called via generic mouse select operator */
-static bool ed_wpaint_vertex_select_pick(
- bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, Object *obact)
+/**
+ * Mouse selection in weight paint.
+ * Called via generic mouse select operator.
+ *
+ * \return True when pick finds an element or the selection changed.
+ */
+static bool ed_wpaint_vertex_select_pick(bContext *C,
+ const int mval[2],
+ const struct SelectPick_Params *params,
+ Object *obact)
{
View3D *v3d = CTX_wm_view3d(C);
const bool use_zbuf = !XRAY_ENABLED(v3d);
@@ -2584,21 +2857,44 @@ static bool ed_wpaint_vertex_select_pick(
Mesh *me = obact->data; /* already checked for NULL */
uint index = 0;
MVert *mv;
+ bool changed = false;
- if (ED_mesh_pick_vert(C, obact, mval, ED_MESH_PICK_DEFAULT_VERT_DIST, use_zbuf, &index)) {
- mv = &me->mvert[index];
- if (extend) {
- mv->flag |= SELECT;
- }
- else if (deselect) {
- mv->flag &= ~SELECT;
+ bool found = ED_mesh_pick_vert(C, obact, mval, ED_MESH_PICK_DEFAULT_VERT_DIST, use_zbuf, &index);
+
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) && (me->mvert[index].flag & SELECT)) {
+ found = false;
}
- else if (toggle) {
- mv->flag ^= SELECT;
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
+ changed |= paintface_deselect_all_visible(C, obact, SEL_DESELECT, false);
}
- else {
- paintvert_deselect_all_visible(obact, SEL_DESELECT, false);
- mv->flag |= SELECT;
+ }
+
+ if (found) {
+ mv = &me->mvert[index];
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ mv->flag |= SELECT;
+ break;
+ }
+ case SEL_OP_SUB: {
+ mv->flag &= ~SELECT;
+ break;
+ }
+ case SEL_OP_XOR: {
+ mv->flag ^= SELECT;
+ break;
+ }
+ case SEL_OP_SET: {
+ paintvert_deselect_all_visible(obact, SEL_DESELECT, false);
+ mv->flag |= SELECT;
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
+ }
}
/* update mselect */
@@ -2610,10 +2906,15 @@ static bool ed_wpaint_vertex_select_pick(
}
paintvert_flush_flags(obact);
+
+ changed = true;
+ }
+
+ if (changed) {
paintvert_tag_select_update(C, obact);
- return true;
}
- return false;
+
+ return changed || found;
}
static int view3d_select_exec(bContext *C, wmOperator *op)
@@ -2621,29 +2922,36 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
Object *obact = CTX_data_active_object(C);
- bool extend = RNA_boolean_get(op->ptr, "extend");
- bool deselect = RNA_boolean_get(op->ptr, "deselect");
- bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
- bool toggle = RNA_boolean_get(op->ptr, "toggle");
+ const struct SelectPick_Params params = {
+ .sel_op = ED_select_op_from_booleans(RNA_boolean_get(op->ptr, "extend"),
+ RNA_boolean_get(op->ptr, "deselect"),
+ RNA_boolean_get(op->ptr, "toggle")),
+ .deselect_all = RNA_boolean_get(op->ptr, "deselect_all"),
+ .select_passthrough = RNA_boolean_get(op->ptr, "select_passthrough"),
+
+ };
bool center = RNA_boolean_get(op->ptr, "center");
bool enumerate = RNA_boolean_get(op->ptr, "enumerate");
/* Only force object select for edit-mode to support vertex parenting,
* or paint-select to allow pose bone select with vert/face select. */
- bool object = (RNA_boolean_get(op->ptr, "object") &&
- (obedit || BKE_paint_select_elem_test(obact) ||
- /* so its possible to select bones in weight-paint mode (LMB select) */
- (obact && (obact->mode & OB_MODE_ALL_WEIGHT_PAINT) &&
- BKE_object_pose_armature_get(obact))));
-
- bool retval = false;
- int location[2];
+ bool object_only = (RNA_boolean_get(op->ptr, "object") &&
+ (obedit || BKE_paint_select_elem_test(obact) ||
+ /* so its possible to select bones in weight-paint mode (LMB select) */
+ (obact && (obact->mode & OB_MODE_ALL_WEIGHT_PAINT) &&
+ BKE_object_pose_armature_get(obact))));
+
+ /* This could be called "changed_or_found" since this is true when there is an element
+ * under the cursor to select, even if it happens that the selection & active state doesn't
+ * actually change. This is important so undo pushes are predictable. */
+ bool changed = false;
+ int mval[2];
- RNA_int_get_array(op->ptr, "location", location);
+ RNA_int_get_array(op->ptr, "location", mval);
view3d_operator_needs_opengl(C);
BKE_object_update_select_id(CTX_data_main(C));
- if (object) {
+ if (object_only) {
obedit = NULL;
obact = NULL;
@@ -2653,12 +2961,9 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
center = false;
}
- if (obedit && object == false) {
+ if (obedit && object_only == false) {
if (obedit->type == OB_MESH) {
- retval = EDBM_select_pick(C, location, extend, deselect, toggle);
- if (!retval && deselect_all) {
- retval = EDBM_mesh_deselect_all_multi(C);
- }
+ changed = EDBM_select_pick(C, mval, &params);
}
else if (obedit->type == OB_ARMATURE) {
if (enumerate) {
@@ -2667,107 +2972,50 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
ED_view3d_viewcontext_init(C, &vc, depsgraph);
GPUSelectResult buffer[MAXPICKELEMS];
- const int hits = mixed_bones_object_selectbuffer(&vc,
- buffer,
- ARRAY_SIZE(buffer),
- location,
- VIEW3D_SELECT_FILTER_NOP,
- false,
- true,
- false);
- retval = bone_mouse_select_menu(C, buffer, hits, true, extend, deselect, toggle);
- }
- if (!retval) {
- retval = ED_armature_edit_select_pick(C, location, extend, deselect, toggle);
+ const int hits = mixed_bones_object_selectbuffer(
+ &vc, buffer, ARRAY_SIZE(buffer), mval, VIEW3D_SELECT_FILTER_NOP, false, true, false);
+ changed = bone_mouse_select_menu(C, buffer, hits, true, &params);
}
-
- if (!retval && deselect_all) {
- retval = ED_armature_edit_deselect_all_visible_multi(C);
- }
- if (retval) {
- ED_outliner_select_sync_from_edit_bone_tag(C);
+ if (!changed) {
+ changed = ED_armature_edit_select_pick(C, mval, &params);
}
}
else if (obedit->type == OB_LATTICE) {
- retval = ED_lattice_select_pick(C, location, extend, deselect, toggle);
- if (!retval && deselect_all) {
- retval = ED_lattice_deselect_all_multi(C);
- }
+ changed = ED_lattice_select_pick(C, mval, &params);
}
else if (ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) {
- retval = ED_curve_editnurb_select_pick(C, location, extend, deselect, toggle);
- if (!retval && deselect_all) {
- retval = ED_curve_deselect_all_multi(C);
- }
+ changed = ED_curve_editnurb_select_pick(C, mval, &params);
}
else if (obedit->type == OB_MBALL) {
- retval = ED_mball_select_pick(C, location, extend, deselect, toggle);
- if (!retval && deselect_all) {
- retval = ED_mball_deselect_all_multi(C);
- }
+ changed = ED_mball_select_pick(C, mval, &params);
}
else if (obedit->type == OB_FONT) {
- retval = ED_curve_editfont_select_pick(C, location, extend, deselect, toggle);
- if (!retval && deselect_all) {
- /* pass */
- }
- }
- if (retval) {
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ changed = ED_curve_editfont_select_pick(C, mval, &params);
}
}
else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
- retval = PE_mouse_particles(C, location, extend, deselect, toggle);
- if (!retval && deselect_all) {
- retval = PE_deselect_all_visible(C);
- }
+ changed = PE_mouse_particles(C, mval, &params);
}
else if (obact && BKE_paint_select_face_test(obact)) {
- retval = paintface_mouse_select(C, obact, location, extend, deselect, toggle);
- if (!retval && deselect_all) {
- retval = paintface_deselect_all_visible(C, CTX_data_active_object(C), SEL_DESELECT, true);
- }
+ changed = paintface_mouse_select(C, mval, &params, obact);
}
else if (BKE_paint_select_vert_test(obact)) {
- retval = ed_wpaint_vertex_select_pick(C, location, extend, deselect, toggle, obact);
- if (!retval && deselect_all) {
- retval = paintvert_deselect_all_visible(obact, SEL_DESELECT, false);
- if (retval) {
- paintvert_tag_select_update(C, obact);
- }
- }
+ changed = ed_wpaint_vertex_select_pick(C, mval, &params, obact);
}
else {
- retval = ed_object_select_pick(
- C, location, extend, deselect, toggle, center, enumerate, object);
- if (!retval && deselect_all) {
- if (ED_pose_object_from_context(C)) {
- retval = ED_pose_deselect_all_multi(C, SEL_DESELECT, false);
- }
- else {
- retval = ED_object_base_deselect_all(
- CTX_data_view_layer(C), CTX_wm_view3d(C), SEL_DESELECT);
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- }
- }
-
- if (retval) {
- if (obact && obact->mode & OB_MODE_POSE) {
- ED_outliner_select_sync_from_pose_bone_tag(C);
- }
- else {
- ED_outliner_select_sync_from_object_tag(C);
- }
- }
+ changed = ed_object_select_pick(C, mval, &params, center, enumerate, object_only);
}
+ /* Pass-through flag may be cleared, see #WM_operator_flag_only_pass_through_on_press. */
+
/* Pass-through allows tweaks
* FINISHED to signal one operator worked */
- if (retval) {
+ if (changed) {
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
- return OPERATOR_PASS_THROUGH; /* nothing selected, just passthrough */
+ /* Nothing selected, just passthrough. */
+ return OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED;
}
static int view3d_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 92d312cebce..975f4370425 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1519,12 +1519,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
wmMsgParams_RNA msg_key_params = {{0}};
RNA_pointer_create(&t->scene->id, &RNA_ToolSettings, ts, &msg_key_params.ptr);
- _WM_MESSAGE_EXTERN_BEGIN;
- extern PropertyRNA rna_ToolSettings_use_snap;
- extern PropertyRNA rna_ToolSettings_use_snap_node;
- extern PropertyRNA rna_ToolSettings_use_snap_sequencer;
- extern PropertyRNA rna_ToolSettings_use_snap_uv;
- _WM_MESSAGE_EXTERN_END;
if (t->spacetype == SPACE_NODE) {
snap_flag_ptr = &ts->snap_flag_node;
msg_key_params.prop = &rna_ToolSettings_use_snap_node;
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 7ace6343985..bf898b9053f 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -567,10 +567,10 @@ static char snap_flag_from_spacetype(TransInfo *t)
if (t->spacetype == SPACE_NODE) {
return ts->snap_flag_node;
}
- else if (t->spacetype == SPACE_IMAGE) {
+ if (t->spacetype == SPACE_IMAGE) {
return ts->snap_uv_flag;
}
- else if (t->spacetype == SPACE_SEQ) {
+ if (t->spacetype == SPACE_SEQ) {
return ts->snap_flag_seq;
}
return ts->snap_flag;
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 8b7133892ff..87053fe03d1 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -440,6 +440,44 @@ typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
bool is_object_active,
void *data);
+static bool snap_object_is_snappable(const SnapObjectContext *sctx,
+ const eSnapSelect snap_select,
+ const Base *base_act,
+ const Base *base,
+ const bool is_in_object_mode)
+{
+ if (!BASE_VISIBLE(sctx->runtime.v3d, base)) {
+ return false;
+ }
+
+ if ((snap_select == SNAP_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
+ return true;
+ }
+
+ if (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) {
+ return false;
+ }
+
+ if (snap_select == SNAP_NOT_ACTIVE) {
+ return base_act == base;
+ }
+
+ if (snap_select == SNAP_NOT_SELECTED) {
+ if (is_in_object_mode) {
+ return !((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL));
+ }
+
+ /* What is selectable or not is part of the object and depends on the mode. */
+ return true;
+ }
+
+ if (snap_select == SNAP_SELECTABLE) {
+ return (base->flag & BASE_SELECTABLE) != 0;
+ }
+
+ return true;
+}
+
/**
* Walks through all objects in the scene to create the list of objects to snap.
*/
@@ -458,38 +496,13 @@ static void iter_snap_objects(SnapObjectContext *sctx,
return;
}
+ const bool is_in_object_mode = !base_act || base_act->object->mode == OB_MODE_OBJECT;
for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) {
- if (!BASE_VISIBLE(sctx->runtime.v3d, base)) {
- continue;
- }
-
- if ((snap_select == SNAP_ALL) || (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) {
- /* pass */
- }
- else if (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) {
+ if (!snap_object_is_snappable(sctx, snap_select, base_act, base, is_in_object_mode)) {
continue;
}
const bool is_object_active = (base == base_act);
- if (snap_select == SNAP_NOT_ACTIVE) {
- if (is_object_active) {
- continue;
- }
- }
- else if (snap_select == SNAP_NOT_SELECTED) {
- if (is_object_active && base->object->mode != OB_MODE_OBJECT) {
- /* Pass. Consider the selection of elements being edited. */
- }
- else if ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL)) {
- continue;
- }
- }
- else if (snap_select == SNAP_SELECTABLE) {
- if (!(base->flag & BASE_SELECTABLE)) {
- continue;
- }
- }
-
Object *obj_eval = DEG_get_evaluated_object(sctx->runtime.depsgraph, base->object);
if (obj_eval->transflag & OB_DUPLI || BKE_object_has_geometry_set_instances(obj_eval)) {
ListBase *lb = object_duplilist(sctx->runtime.depsgraph, sctx->scene, obj_eval);
diff --git a/source/blender/editors/util/select_utils.c b/source/blender/editors/util/select_utils.c
index b6893c3032a..380c7ed0e43 100644
--- a/source/blender/editors/util/select_utils.c
+++ b/source/blender/editors/util/select_utils.c
@@ -112,3 +112,17 @@ bool ED_select_similar_compare_float_tree(const KDTree_1d *tree,
return false;
}
+
+eSelectOp ED_select_op_from_booleans(const bool extend, const bool deselect, const bool toggle)
+{
+ if (extend) {
+ return SEL_OP_ADD;
+ }
+ if (deselect) {
+ return SEL_OP_SUB;
+ }
+ if (toggle) {
+ return SEL_OP_XOR;
+ }
+ return SEL_OP_SET;
+}
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 3f7c7745bff..5ad326c19e5 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -4021,7 +4021,7 @@ static void p_smooth(PChart *chart)
PFace *f;
int j, it2, maxiter2, it;
int nedges = chart->nedges, nwheel, gridx, gridy;
- int edgesx, edgesy, nsize, esize, i, x, y, maxiter, totiter;
+ int edgesx, edgesy, nsize, esize, i, x, y, maxiter;
float minv[2], maxv[2], median, invmedian, avglen2d, avglen3d;
float center[2], dx, dy, *nodes, dlimit, d, *oldnodesx, *oldnodesy;
float *nodesx, *nodesy, *hedges, *vedges, climit, moved, padding;
@@ -4185,7 +4185,6 @@ static void p_smooth(PChart *chart)
/* smooth the grid */
maxiter = 10;
- totiter = 0;
climit = 0.00001f * nsize;
for (it = 0; it < maxiter; it++) {
@@ -4210,7 +4209,6 @@ static void p_smooth(PChart *chart)
for (it2 = 0; it2 < maxiter2; it2++) {
d = 0.0f;
- totiter += 1;
memcpy(oldnodesx, nodesx, sizeof(float) * nsize);
memcpy(oldnodesy, nodesy, sizeof(float) * nsize);
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 938b798f4b6..ed4aa6985c4 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -2388,12 +2388,11 @@ void UV_OT_select_all(wmOperatorType *ot)
/** \name Mouse Select Operator
* \{ */
-static int uv_mouse_select_multi(bContext *C,
- Object **objects,
- uint objects_len,
- const float co[2],
- const bool extend,
- const bool deselect_all)
+static bool uv_mouse_select_multi(bContext *C,
+ Object **objects,
+ uint objects_len,
+ const float co[2],
+ const struct SelectPick_Params *params)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
const ARegion *region = CTX_wm_region(C);
@@ -2477,117 +2476,145 @@ static int uv_mouse_select_multi(bContext *C,
}
}
- if (!found_item) {
- if (deselect_all) {
- uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ bool found = found_item;
+ bool changed = false;
+
+ bool is_selected = false;
+ if (found) {
+ Object *obedit = hit.ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ if (selectmode == UV_SELECT_FACE) {
+ is_selected = uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset);
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ is_selected = uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset);
+ }
+ else { /* Vertex or island. */
+ is_selected = uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
+ }
+ }
+ if (params->sel_op == SEL_OP_SET) {
+ if ((found && params->select_passthrough) && is_selected) {
+ found = false;
+ }
+ else if (found || params->deselect_all) {
+ /* Deselect everything. */
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
uv_select_tag_update_for_object(depsgraph, ts, obedit);
}
-
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
+ changed = true;
}
- return OPERATOR_CANCELLED;
}
- Object *obedit = hit.ob;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ if (found) {
+ Object *obedit = hit.ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- /* do selection */
- if (selectmode == UV_SELECT_ISLAND) {
- if (!extend) {
- uv_select_all_perform_multi_ex(scene, objects, objects_len, SEL_DESELECT, obedit);
- }
- /* Current behavior of 'extend'
- * is actually toggling, so pass extend flag as 'toggle' here */
- uv_select_linked_multi(scene, objects, objects_len, &hit, false, false, extend, false);
- }
- else if (extend) {
- bool select = true;
- if (selectmode == UV_SELECT_VERTEX) {
- /* (de)select uv vertex */
- select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
- uvedit_uv_select_set_with_sticky(scene, em, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* (de)select edge */
- select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset));
- uvedit_edge_select_set_with_sticky(scene, em, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* (de)select face */
- select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset));
- uvedit_face_select_set_with_sticky(scene, em, hit.efa, select, true, cd_loop_uv_offset);
- flush = -1;
+ if (selectmode == UV_SELECT_ISLAND) {
+ const bool extend = params->sel_op == SEL_OP_ADD;
+ const bool deselect = params->sel_op == SEL_OP_SUB;
+ const bool toggle = params->sel_op == SEL_OP_XOR;
+ /* Current behavior of 'extend'
+ * is actually toggling, so pass extend flag as 'toggle' here */
+ uv_select_linked_multi(scene, objects, objects_len, &hit, extend, deselect, toggle, false);
+ /* TODO: check if this actually changed. */
+ changed = true;
}
+ else {
+ BLI_assert(ELEM(selectmode, UV_SELECT_VERTEX, UV_SELECT_EDGE, UV_SELECT_FACE));
+ bool select_value = false;
+ switch (params->sel_op) {
+ case SEL_OP_ADD: {
+ select_value = true;
+ break;
+ }
+ case SEL_OP_SUB: {
+ select_value = false;
+ break;
+ }
+ case SEL_OP_XOR: {
+ select_value = !is_selected;
+ break;
+ }
+ case SEL_OP_SET: {
+ /* Deselect has already been performed. */
+ select_value = true;
+ break;
+ }
+ case SEL_OP_AND: {
+ BLI_assert_unreachable(); /* Doesn't make sense for picking. */
+ break;
+ }
+ }
- /* de-selecting an edge may deselect a face too - validate */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (select == false) {
- BM_select_history_validate(em->bm);
+ if (selectmode == UV_SELECT_FACE) {
+ uvedit_face_select_set_with_sticky(
+ scene, em, hit.efa, select_value, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ uvedit_edge_select_set_with_sticky(
+ scene, em, hit.l, select_value, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_VERTEX) {
+ uvedit_uv_select_set_with_sticky(scene, em, hit.l, select_value, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else {
+ BLI_assert_unreachable();
}
- }
- /* (de)select sticky uv nodes */
- if (sticky != SI_STICKY_DISABLE) {
- flush = select ? 1 : -1;
- }
- }
- else {
- const bool select = true;
- /* deselect all */
- uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ /* De-selecting an edge may deselect a face too - validate. */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (select_value == false) {
+ BM_select_history_validate(em->bm);
+ }
+ }
- if (selectmode == UV_SELECT_VERTEX) {
- /* select vertex */
- uvedit_uv_select_set_with_sticky(scene, em, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* select edge */
- uvedit_edge_select_set_with_sticky(scene, em, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* select face */
- uvedit_face_select_set_with_sticky(scene, em, hit.efa, select, true, cd_loop_uv_offset);
- flush = 1;
+ /* (de)select sticky UV nodes. */
+ if (sticky != SI_STICKY_DISABLE) {
+ flush = select_value ? 1 : -1;
+ }
+
+ changed = true;
}
- }
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (flush != 0) {
- EDBM_selectmode_flush(em);
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (flush != 0) {
+ EDBM_selectmode_flush(em);
+ }
+ }
+ else {
+ /* Setting the selection implies a single element, which doesn't need to be flushed. */
+ if (params->sel_op != SEL_OP_SET) {
+ ED_uvedit_selectmode_flush(scene, em);
+ }
}
- }
- /* #extend=false implies single vertex selection, which doesn't need to be flushed. */
- else if (extend) {
- ED_uvedit_selectmode_flush(scene, em);
}
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obiter = objects[ob_index];
- uv_select_tag_update_for_object(depsgraph, ts, obiter);
+ if (changed && found) {
+ /* Only update the `hit` object as de-selecting all will have refreshed the others. */
+ Object *obedit = hit.ob;
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
}
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
+ return changed || found;
}
-static int uv_mouse_select(bContext *C,
- const float co[2],
- const bool extend,
- const bool deselect_all)
+static bool uv_mouse_select(bContext *C, const float co[2], const struct SelectPick_Params *params)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
- int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all);
+ bool changed = uv_mouse_select_multi(C, objects, objects_len, co, params);
MEM_freeN(objects);
- return ret;
+ return changed;
}
static int uv_select_exec(bContext *C, wmOperator *op)
@@ -2595,10 +2622,20 @@ static int uv_select_exec(bContext *C, wmOperator *op)
float co[2];
RNA_float_get_array(op->ptr, "location", co);
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+ const struct SelectPick_Params params = {
+ .sel_op = ED_select_op_from_booleans(RNA_boolean_get(op->ptr, "extend"),
+ RNA_boolean_get(op->ptr, "deselect"),
+ RNA_boolean_get(op->ptr, "toggle")),
+ .deselect_all = RNA_boolean_get(op->ptr, "deselect_all"),
+ .select_passthrough = RNA_boolean_get(op->ptr, "select_passthrough"),
+ };
- return uv_mouse_select(C, co, extend, deselect_all);
+ const bool changed = uv_mouse_select(C, co, &params);
+
+ if (changed) {
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ }
+ return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -2629,18 +2666,8 @@ void UV_OT_select(wmOperatorType *ot)
/* properties */
PropertyRNA *prop;
- prop = RNA_def_boolean(ot->srna,
- "extend",
- 0,
- "Extend",
- "Extend selection rather than clearing the existing selection");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna,
- "deselect_all",
- false,
- "Deselect On Nothing",
- "Deselect all when nothing under the cursor");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ WM_operator_properties_mouse_select(ot);
prop = RNA_def_float_vector(
ot->srna,
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 3ed99052753..63300656fda 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -2969,6 +2969,7 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob)
me,
(&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
/* select all uv loops first - pack parameters needs this to make sure charts are registered */
ED_uvedit_select_all(bm);
diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt
index 2a5a2d0d957..c2fad9fef3a 100644
--- a/source/blender/freestyle/CMakeLists.txt
+++ b/source/blender/freestyle/CMakeLists.txt
@@ -508,8 +508,6 @@ set(SRC
intern/view_map/ViewMapAdvancedIterators.h
intern/view_map/ViewMapBuilder.cpp
intern/view_map/ViewMapBuilder.h
- intern/view_map/ViewMapIO.cpp
- intern/view_map/ViewMapIO.h
intern/view_map/ViewMapIterators.h
intern/view_map/ViewMapTesselator.cpp
intern/view_map/ViewMapTesselator.h
diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp
index 024bc80f3fa..cc815b5317f 100644
--- a/source/blender/freestyle/intern/application/Controller.cpp
+++ b/source/blender/freestyle/intern/application/Controller.cpp
@@ -36,7 +36,6 @@ extern "C" {
#include "../view_map/SteerableViewMap.h"
#include "../view_map/ViewMap.h"
-#include "../view_map/ViewMapIO.h"
#include "../view_map/ViewMapTesselator.h"
#include "../winged_edge/Curvature.h"
@@ -1099,13 +1098,10 @@ void Controller::init_options()
Config::Path *cpath = Config::Path::getInstance();
// Directories
- ViewMapIO::Options::setModelsPath(cpath->getModelsPath());
TextureManager::Options::setPatternsPath(cpath->getPatternsPath());
TextureManager::Options::setBrushesPath(cpath->getModelsPath());
// ViewMap Format
- ViewMapIO::Options::rmFlags(ViewMapIO::Options::FLOAT_VECTORS);
- ViewMapIO::Options::rmFlags(ViewMapIO::Options::NO_OCCLUDERS);
setComputeSteerableViewMapFlag(false);
// Visibility
diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
index 63585df97a9..96bab8c2028 100644
--- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
@@ -31,6 +31,13 @@
#include "BPy_ViewMap.h"
#include "BPy_ViewShape.h"
+#include "BKE_appdir.h"
+#include "DNA_scene_types.h"
+#include "FRS_freestyle.h"
+#include "RNA_access.h"
+#include "RNA_prototypes.h"
+#include "bpy_rna.h" /* pyrna_struct_CreatePyObject() */
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -39,13 +46,6 @@ extern "C" {
//------------------------ MODULE FUNCTIONS ----------------------------------
-#include "BKE_appdir.h"
-#include "DNA_scene_types.h"
-#include "FRS_freestyle.h"
-#include "RNA_access.h"
-#include "RNA_prototypes.h"
-#include "bpy_rna.h" /* pyrna_struct_CreatePyObject() */
-
static char Freestyle_getCurrentScene___doc__[] =
".. function:: getCurrentScene()\n"
"\n"
diff --git a/source/blender/freestyle/intern/python/BPy_MediumType.cpp b/source/blender/freestyle/intern/python/BPy_MediumType.cpp
index 494e01967d6..cf8e900e003 100644
--- a/source/blender/freestyle/intern/python/BPy_MediumType.cpp
+++ b/source/blender/freestyle/intern/python/BPy_MediumType.cpp
@@ -21,7 +21,7 @@ using namespace Freestyle;
PyDoc_STRVAR(MediumType_doc,
"Class hierarchy: int > :class:`MediumType`\n"
"\n"
- "The different blending modes available to similate the interaction\n"
+ "The different blending modes available to simulate the interaction\n"
"media-medium:\n"
"\n"
"* Stroke.DRY_MEDIUM: To simulate a dry medium such as Pencil or Charcoal.\n"
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
index dc3b7d9795a..5642a80e77f 100644
--- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
@@ -430,8 +430,8 @@ static void computeCumulativeVisibility(ViewMap *ioViewMap,
int nSamples = 0;
vector<WFace *> wFaces;
WFace *wFace = nullptr;
- unsigned cnt = 0;
- unsigned cntStep = (unsigned)ceil(0.01f * vedges.size());
+ unsigned count = 0;
+ unsigned count_step = (unsigned)ceil(0.01f * vedges.size());
unsigned tmpQI = 0;
unsigned qiClasses[256];
unsigned maxIndex, maxCard;
@@ -441,13 +441,13 @@ static void computeCumulativeVisibility(ViewMap *ioViewMap,
if (iRenderMonitor->testBreak()) {
break;
}
- if (cnt % cntStep == 0) {
+ if (count % count_step == 0) {
stringstream ss;
- ss << "Freestyle: Visibility computations " << (100 * cnt / vedges.size()) << "%";
+ ss << "Freestyle: Visibility computations " << (100 * count / vedges.size()) << "%";
iRenderMonitor->setInfo(ss.str());
- iRenderMonitor->progress((float)cnt / vedges.size());
+ iRenderMonitor->progress((float)count / vedges.size());
}
- cnt++;
+ count++;
}
#if LOGGING
if (_global.debug & G_DEBUG_FREESTYLE) {
@@ -621,9 +621,9 @@ static void computeCumulativeVisibility(ViewMap *ioViewMap,
}
if (iRenderMonitor && !vedges.empty()) {
stringstream ss;
- ss << "Freestyle: Visibility computations " << (100 * cnt / vedges.size()) << "%";
+ ss << "Freestyle: Visibility computations " << (100 * count / vedges.size()) << "%";
iRenderMonitor->setInfo(ss.str());
- iRenderMonitor->progress((float)cnt / vedges.size());
+ iRenderMonitor->progress((float)count / vedges.size());
}
}
diff --git a/source/blender/freestyle/intern/view_map/ViewMapIO.cpp b/source/blender/freestyle/intern/view_map/ViewMapIO.cpp
deleted file mode 100644
index 47d9e61ba2f..00000000000
--- a/source/blender/freestyle/intern/view_map/ViewMapIO.cpp
+++ /dev/null
@@ -1,1294 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-/** \file
- * \ingroup freestyle
- * \brief Functions to manage I/O for the view map
- */
-
-#include <climits>
-
-#include "ViewMapIO.h"
-
-#ifdef IRIX
-# define WRITE(n) Internal::write<sizeof((n))>(out, (const char *)(&(n)))
-# define READ(n) Internal::read<sizeof((n))>(in, (char *)(&(n)))
-#else
-# define WRITE(n) out.write((const char *)(&(n)), sizeof((n)))
-# define READ(n) in.read((char *)(&(n)), sizeof((n)))
-#endif
-
-#define WRITE_IF_NON_NULL(ptr) \
- if (ptr) { \
- WRITE((ptr)->userdata); \
- } \
- else { \
- WRITE(ZERO); \
- } \
- (void)0
-
-#define READ_IF_NON_NULL(ptr, array) \
- READ(tmp); \
- if (tmp) { \
- (ptr) = (array)[tmp]; \
- } \
- else { \
- (ptr) = NULL; \
- } \
- (void)0
-
-namespace Freestyle::ViewMapIO {
-
-namespace Internal {
-
-static ViewMap *g_vm;
-
-//////////////////// 'load' Functions ////////////////////
-
-inline int load(istream &in, Vec3r &v)
-{
- if (Options::getFlags() & Options::FLOAT_VECTORS) {
- float tmp;
- READ(tmp);
- v[0] = tmp;
- READ(tmp);
- v[1] = tmp;
- READ(tmp);
- v[2] = tmp;
- }
- else {
- Vec3r::value_type tmp;
- READ(tmp);
- v[0] = tmp;
- READ(tmp);
- v[1] = tmp;
- READ(tmp);
- v[2] = tmp;
- }
- return 0;
-}
-
-inline int load(istream &in, Polygon3r &p)
-{
- unsigned tmp;
-
- // Id
- READ(tmp);
- p.setId(tmp);
-
- // vertices (List)
- vector<Vec3r> tmp_vec;
- Vec3r v;
- READ(tmp);
- for (unsigned int i = 0; i < tmp; i++) {
- load(in, v);
- tmp_vec.push_back(v);
- }
- p.setVertices(tmp_vec);
-
- // min & max
- // Already computed (in the SetVertices() method)
-
- return 0;
-}
-
-inline int load(istream &in, FrsMaterial &m)
-{
- float tmp_array[4];
- int i;
-
- // Diffuse
- for (i = 0; i < 4; i++) {
- READ(tmp_array[i]);
- }
- m.setDiffuse(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]);
-
- // Specular
- for (i = 0; i < 4; i++) {
- READ(tmp_array[i]);
- }
- m.setSpecular(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]);
-
- // Ambient
- for (i = 0; i < 4; i++) {
- READ(tmp_array[i]);
- }
- m.setAmbient(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]);
-
- // Emission
- for (i = 0; i < 4; i++) {
- READ(tmp_array[i]);
- }
- m.setEmission(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]);
-
- // Shininess
- READ(tmp_array[0]);
- m.setShininess(tmp_array[0]);
-
- return 0;
-}
-
-static int load(istream &in, ViewShape *vs)
-{
- if (!vs || !vs->sshape()) {
- return 1;
- }
-
- // SShape
-
- // -> Id
- Id::id_type id1, id2;
- READ(id1);
- READ(id2);
- vs->sshape()->setId(Id(id1, id2));
-
- // -> Importance
- float importance;
- READ(importance);
- vs->sshape()->setImportance(importance);
-
- // -> BBox
- // Not necessary (only used during view map computatiom)
-
- unsigned i, size, tmp;
-
- // -> Material
- READ(size);
- vector<FrsMaterial> frs_materials;
- FrsMaterial m;
- for (i = 0; i < size; ++i) {
- load(in, m);
- frs_materials.push_back(m);
- }
- vs->sshape()->setFrsMaterials(frs_materials);
-
- // -> VerticesList (List)
- READ(size);
- for (i = 0; i < size; i++) {
- SVertex *sv;
- READ_IF_NON_NULL(sv, g_vm->SVertices());
- vs->sshape()->AddNewVertex(sv);
- }
-
- // -> Chains (List)
- READ(size);
- for (i = 0; i < size; i++) {
- FEdge *fe;
- READ_IF_NON_NULL(fe, g_vm->FEdges());
- vs->sshape()->AddChain(fe);
- }
-
- // -> EdgesList (List)
- READ(size);
- for (i = 0; i < size; i++) {
- FEdge *fe;
- READ_IF_NON_NULL(fe, g_vm->FEdges());
- vs->sshape()->AddEdge(fe);
- }
-
- // ViewEdges (List)
- READ(size);
- for (i = 0; i < size; i++) {
- ViewEdge *ve;
- READ_IF_NON_NULL(ve, g_vm->ViewEdges());
- vs->AddEdge(ve);
- }
-
- // ViewVertices (List)
- READ(size);
- for (i = 0; i < size; i++) {
- ViewVertex *vv;
- READ_IF_NON_NULL(vv, g_vm->ViewVertices());
- vs->AddVertex(vv);
- }
-
- return 0;
-}
-
-static int load(istream &in, FEdge *fe)
-{
- if (!fe) {
- return 1;
- }
-
- bool b;
-
- FEdgeSmooth *fesmooth = nullptr;
- FEdgeSharp *fesharp = nullptr;
- if (fe->isSmooth()) {
- fesmooth = dynamic_cast<FEdgeSmooth *>(fe);
- }
- else {
- fesharp = dynamic_cast<FEdgeSharp *>(fe);
- }
-
- // Id
- Id::id_type id1, id2;
- READ(id1);
- READ(id2);
- fe->setId(Id(id1, id2));
-
- // Nature
- Nature::EdgeNature nature;
- READ(nature);
- fe->setNature(nature);
-
-#if 0 // hasVisibilityPoint
- bool b;
- READ(b);
- fe->setHasVisibilityPoint(b);
-#endif
-
- Vec3r v;
- unsigned int matindex;
-
-#if 0
- // VisibilityPointA
- load(in, v);
- fe->setVisibilityPointA(v);
-
- // VisibilityPointB
- load(in, v);
- fe->setVisibilityPointB(v);
-#endif
-
- if (fe->isSmooth()) {
- // Normal
- load(in, v);
- fesmooth->setNormal(v);
-
- // Material
- READ(matindex);
- fesmooth->setFrsMaterialIndex(matindex);
- }
- else {
- // aNormal
- load(in, v);
- fesharp->setNormalA(v);
-
- // bNormal
- load(in, v);
- fesharp->setNormalB(v);
-
- // Materials
- READ(matindex);
- fesharp->setaFrsMaterialIndex(matindex);
- READ(matindex);
- fesharp->setbFrsMaterialIndex(matindex);
- }
-
- unsigned tmp;
-
- // VertexA
- SVertex *sva;
- READ_IF_NON_NULL(sva, g_vm->SVertices());
- fe->setVertexA(sva);
-
- // VertexB
- SVertex *svb;
- READ_IF_NON_NULL(svb, g_vm->SVertices());
- fe->setVertexB(svb);
-
- // NextEdge
- FEdge *nfe;
- READ_IF_NON_NULL(nfe, g_vm->FEdges());
- fe->setNextEdge(nfe);
-
- // PreviousEdge
- FEdge *pfe;
- READ_IF_NON_NULL(pfe, g_vm->FEdges());
- fe->setPreviousEdge(pfe);
-
- // ViewEdge
- ViewEdge *ve;
- READ_IF_NON_NULL(ve, g_vm->ViewEdges());
- fe->setViewEdge(ve);
-
- // Face
- // Not necessary (only used during view map computatiom)
-
- Polygon3r p;
-
- // aFace
- load(in, p);
- fe->setaFace(p);
-
- // occludeeEmpty
- READ(b);
- fe->setOccludeeEmpty(b);
-
- // occludeeIntersection
- load(in, v);
- fe->setOccludeeIntersection(v);
-
- return 0;
-}
-
-static int load(istream &in, SVertex *sv)
-{
- if (!sv) {
- return 1;
- }
-
- // Id
- Id::id_type id1, id2;
- READ(id1);
- READ(id2);
- sv->setId(Id(id1, id2));
-
- Vec3r v;
-
- // Point3D
- load(in, v);
- sv->setPoint3D(v);
-
- // Point2D
- load(in, v);
- sv->setPoint2D(v);
-
- unsigned tmp;
-
- // Shape
- ViewShape *vs;
- READ_IF_NON_NULL(vs, g_vm->ViewShapes());
- sv->setShape(vs->sshape());
-
- // pViewVertex
- ViewVertex *vv;
- READ_IF_NON_NULL(vv, g_vm->ViewVertices());
- sv->setViewVertex(vv);
-
- unsigned i, size;
-
- // Normals (List)
- READ(size);
- for (i = 0; i < size; i++) {
- load(in, v);
- sv->AddNormal(v);
- }
-
- // FEdges (List)
- READ(size);
- FEdge *fe;
- for (i = 0; i < size; i++) {
- READ_IF_NON_NULL(fe, g_vm->FEdges());
- sv->AddFEdge(fe);
- }
-
- return 0;
-}
-
-static int load(istream &in, ViewEdge *ve)
-{
- if (!ve) {
- return 1;
- }
-
- unsigned tmp;
-
- // Id
- Id::id_type id1, id2;
- READ(id1);
- READ(id2);
- ve->setId(Id(id1, id2));
-
- // Nature
- Nature::EdgeNature nature;
- READ(nature);
- ve->setNature(nature);
-
- // QI
- READ(tmp);
- ve->setQI(tmp);
-
- // Shape
- ViewShape *vs;
- READ_IF_NON_NULL(vs, g_vm->ViewShapes());
- ve->setShape(vs);
-
- // aShape
- ViewShape *avs;
- READ_IF_NON_NULL(avs, g_vm->ViewShapes());
- ve->setaShape(avs);
-
- // FEdgeA
- FEdge *fea;
- READ_IF_NON_NULL(fea, g_vm->FEdges());
- ve->setFEdgeA(fea);
-
- // FEdgeB
- FEdge *feb;
- READ_IF_NON_NULL(feb, g_vm->FEdges());
- ve->setFEdgeB(feb);
-
- // A
- ViewVertex *vva;
- READ_IF_NON_NULL(vva, g_vm->ViewVertices());
- ve->setA(vva);
-
- // B
- ViewVertex *vvb;
- READ_IF_NON_NULL(vvb, g_vm->ViewVertices());
- ve->setB(vvb);
-
- // Occluders (List)
- if (!(Options::getFlags() & Options::NO_OCCLUDERS)) {
- unsigned size;
- READ(size);
- ViewShape *vso;
- for (unsigned int i = 0; i < size; i++) {
- READ_IF_NON_NULL(vso, g_vm->ViewShapes());
- ve->AddOccluder(vso);
- }
- }
-
- return 0;
-}
-
-static int load(istream &in, ViewVertex *vv)
-{
- if (!vv) {
- return 1;
- }
-
- unsigned tmp;
- bool b;
-
- // Nature
- Nature::VertexNature nature;
- READ(nature);
- vv->setNature(nature);
-
- if (vv->getNature() & Nature::T_VERTEX) {
- TVertex *tv = dynamic_cast<TVertex *>(vv);
-
- // Id
- Id::id_type id1, id2;
- READ(id1);
- READ(id2);
- tv->setId(Id(id1, id2));
-
- // FrontSVertex
- SVertex *fsv;
- READ_IF_NON_NULL(fsv, g_vm->SVertices());
- tv->setFrontSVertex(fsv);
-
- // BackSVertex
- SVertex *bsv;
- READ_IF_NON_NULL(bsv, g_vm->SVertices());
- tv->setBackSVertex(bsv);
-
- // FrontEdgeA
- ViewEdge *fea;
- READ_IF_NON_NULL(fea, g_vm->ViewEdges());
- READ(b);
- tv->setFrontEdgeA(fea, b);
-
- // FrontEdgeB
- ViewEdge *feb;
- READ_IF_NON_NULL(feb, g_vm->ViewEdges());
- READ(b);
- tv->setFrontEdgeB(feb, b);
-
- // BackEdgeA
- ViewEdge *bea;
- READ_IF_NON_NULL(bea, g_vm->ViewEdges());
- READ(b);
- tv->setBackEdgeA(bea, b);
-
- // BackEdgeB
- ViewEdge *beb;
- READ_IF_NON_NULL(beb, g_vm->ViewEdges());
- READ(b);
- tv->setBackEdgeB(beb, b);
- }
- else if (vv->getNature() & Nature::NON_T_VERTEX) {
- NonTVertex *ntv = dynamic_cast<NonTVertex *>(vv);
-
- // SVertex
- SVertex *sv;
- READ_IF_NON_NULL(sv, g_vm->SVertices());
- ntv->setSVertex(sv);
-
- // ViewEdges (List)
- unsigned size;
- READ(size);
- ViewEdge *ve;
- for (unsigned int i = 0; i < size; i++) {
- READ_IF_NON_NULL(ve, g_vm->ViewEdges());
- READ(b);
- ntv->AddViewEdge(ve, b);
- }
- }
-
- return 0;
-}
-
-//////////////////// 'save' Functions ////////////////////
-
-inline int save(ostream &out, const Vec3r &v)
-{
- if (Options::getFlags() & Options::FLOAT_VECTORS) {
- float tmp;
-
- tmp = v[0];
- WRITE(tmp);
- tmp = v[1];
- WRITE(tmp);
- tmp = v[2];
- WRITE(tmp);
- }
- else {
- Vec3r::value_type tmp;
-
- tmp = v[0];
- WRITE(tmp);
- tmp = v[1];
- WRITE(tmp);
- tmp = v[2];
- WRITE(tmp);
- }
- return 0;
-}
-
-inline int save(ostream &out, const Polygon3r &p)
-{
- unsigned tmp;
-
- // Id
- tmp = p.getId();
- WRITE(tmp);
-
- // vertices (List)
- tmp = p.getVertices().size();
- WRITE(tmp);
- for (vector<Vec3r>::const_iterator i = p.getVertices().begin(); i != p.getVertices().end();
- i++) {
- save(out, *i);
- }
-
- // min & max
- // Do not need to be saved
-
- return 0;
-}
-
-inline int save(ostream &out, const FrsMaterial &m)
-{
- unsigned i;
-
- // Diffuse
- for (i = 0; i < 4; i++) {
- WRITE(m.diffuse()[i]);
- }
-
- // Specular
- for (i = 0; i < 4; i++) {
- WRITE(m.specular()[i]);
- }
-
- // Ambient
- for (i = 0; i < 4; i++) {
- WRITE(m.ambient()[i]);
- }
-
- // Emission
- for (i = 0; i < 4; i++) {
- WRITE(m.emission()[i]);
- }
-
- // Shininess
- float shininess = m.shininess();
- WRITE(shininess);
-
- return 0;
-}
-
-static int save(ostream &out, ViewShape *vs)
-{
- if (!vs || !vs->sshape()) {
- cerr << "Warning: null ViewShape" << endl;
- return 1;
- }
-
- unsigned tmp;
-
- // SShape
-
- // -> Id
- Id::id_type id = vs->sshape()->getId().getFirst();
- WRITE(id);
- id = vs->sshape()->getId().getSecond();
- WRITE(id);
-
- // -> Importance
- float importance = vs->sshape()->importance();
- WRITE(importance);
-
- // -> BBox
- // Not necessary (only used during view map computatiom)
-
- // -> Material
- unsigned int size = vs->sshape()->frs_materials().size();
- WRITE(size);
- for (unsigned int i = 0; i < size; ++i) {
- save(out, vs->sshape()->frs_material(i));
- }
-
- // -> VerticesList (List)
- tmp = vs->sshape()->getVertexList().size();
- WRITE(tmp);
- for (vector<SVertex *>::const_iterator i1 = vs->sshape()->getVertexList().begin();
- i1 != vs->sshape()->getVertexList().end();
- i1++) {
- WRITE_IF_NON_NULL(*i1);
- }
-
- // -> Chains (List)
- tmp = vs->sshape()->getChains().size();
- WRITE(tmp);
- for (vector<FEdge *>::const_iterator i2 = vs->sshape()->getChains().begin();
- i2 != vs->sshape()->getChains().end();
- i2++) {
- WRITE_IF_NON_NULL(*i2);
- }
-
- // -> EdgesList (List)
- tmp = vs->sshape()->getEdgeList().size();
- WRITE(tmp);
- for (vector<FEdge *>::const_iterator i3 = vs->sshape()->getEdgeList().begin();
- i3 != vs->sshape()->getEdgeList().end();
- i3++) {
- WRITE_IF_NON_NULL(*i3);
- }
-
- // ViewEdges (List)
- tmp = vs->edges().size();
- WRITE(tmp);
- for (vector<ViewEdge *>::const_iterator i4 = vs->edges().begin(); i4 != vs->edges().end();
- i4++) {
- WRITE_IF_NON_NULL(*i4);
- }
-
- // ViewVertices (List)
- tmp = vs->vertices().size();
- WRITE(tmp);
- for (vector<ViewVertex *>::const_iterator i5 = vs->vertices().begin();
- i5 != vs->vertices().end();
- i5++) {
- WRITE_IF_NON_NULL(*i5);
- }
-
- return 0;
-}
-
-static int save(ostream &out, FEdge *fe)
-{
- if (!fe) {
- cerr << "Warning: null FEdge" << endl;
- return 1;
- }
-
- FEdgeSmooth *fesmooth = dynamic_cast<FEdgeSmooth *>(fe);
- FEdgeSharp *fesharp = dynamic_cast<FEdgeSharp *>(fe);
-
- // Id
- Id::id_type id = fe->getId().getFirst();
- WRITE(id);
- id = fe->getId().getSecond();
- WRITE(id);
-
- // Nature
- Nature::EdgeNature nature = fe->getNature();
- WRITE(nature);
-
- bool b;
-
-#if 0
- // hasVisibilityPoint
- b = fe->hasVisibilityPoint();
- WRITE(b);
-
- // VisibilityPointA
- save(out, fe->visibilityPointA());
-
- // VisibilityPointB
- save(out, fe->visibilityPointB());
-#endif
-
- unsigned index;
- if (fe->isSmooth()) {
- // normal
- save(out, fesmooth->normal());
- // material
- index = fesmooth->frs_materialIndex();
- WRITE(index);
- }
- else {
- // aNormal
- save(out, fesharp->normalA());
- // bNormal
- save(out, fesharp->normalB());
- // aMaterial
- index = fesharp->aFrsMaterialIndex();
- WRITE(index);
- // bMaterial
- index = fesharp->bFrsMaterialIndex();
- WRITE(index);
- }
-
- // VertexA
- WRITE_IF_NON_NULL(fe->vertexA());
-
- // VertexB
- WRITE_IF_NON_NULL(fe->vertexB());
-
- // NextEdge
- WRITE_IF_NON_NULL(fe->nextEdge());
-
- // PreviousEdge
- WRITE_IF_NON_NULL(fe->previousEdge());
-
- // ViewEdge
- WRITE_IF_NON_NULL(fe->viewedge());
-
- // Face
- // Not necessary (only used during view map computatiom)
-
- // aFace
- save(out, (Polygon3r &)fe->aFace());
-
- // occludeeEmpty
- b = fe->getOccludeeEmpty();
- WRITE(b);
-
- // occludeeIntersection
- save(out, fe->getOccludeeIntersection());
-
- return 0;
-}
-
-static int save(ostream &out, SVertex *sv)
-{
- if (!sv) {
- cerr << "Warning: null SVertex" << endl;
- return 1;
- }
-
- unsigned tmp;
-
- // Id
- Id::id_type id = sv->getId().getFirst();
- WRITE(id);
- id = sv->getId().getSecond();
- WRITE(id);
-
- Vec3r v;
-
- // Point3D
- v = sv->point3D();
- save(out, sv->point3D());
-
- // Point2D
- v = sv->point2D();
- save(out, v);
-
- // Shape
- WRITE_IF_NON_NULL(sv->shape());
-
- // pViewVertex
- WRITE_IF_NON_NULL(sv->viewvertex());
-
- // Normals (List)
- // NOTE: the 'size()' method of a set doesn't seem to return the actual size of the given set, so
- // we have to hack it...
- set<Vec3r>::const_iterator i;
- for (i = sv->normals().begin(), tmp = 0; i != sv->normals().end(); i++, tmp++) {
- /* pass */
- }
- WRITE(tmp);
- for (i = sv->normals().begin(); i != sv->normals().end(); i++) {
- save(out, *i);
- }
-
- // FEdges (List)
- tmp = sv->fedges().size();
- WRITE(tmp);
- for (vector<FEdge *>::const_iterator j = sv->fedges_begin(); j != sv->fedges_end(); j++) {
- WRITE_IF_NON_NULL(*j);
- }
-
- return 0;
-}
-
-static int save(ostream &out, ViewEdge *ve)
-{
- if (!ve) {
- cerr << "Warning: null ViewEdge" << endl;
- return 1;
- }
-
- unsigned tmp;
-
- // Id
- Id::id_type id = ve->getId().getFirst();
- WRITE(id);
- id = ve->getId().getSecond();
- WRITE(id);
-
- // Nature
- Nature::EdgeNature nature = ve->getNature();
- WRITE(nature);
-
- // QI
- unsigned qi = ve->qi();
- WRITE(qi);
-
- // Shape
- WRITE_IF_NON_NULL(ve->shape());
-
- // aShape
- WRITE_IF_NON_NULL(ve->aShape());
-
- // FEdgeA
- WRITE_IF_NON_NULL(ve->fedgeA());
-
- // FEdgeB
- WRITE_IF_NON_NULL(ve->fedgeB());
-
- // A
- WRITE_IF_NON_NULL(ve->A());
-
- // B
- WRITE_IF_NON_NULL(ve->B());
-
- // Occluders (List)
- if (!(Options::getFlags() & Options::NO_OCCLUDERS)) {
- tmp = ve->occluders().size();
- WRITE(tmp);
- for (vector<ViewShape *>::const_iterator i = ve->occluders().begin();
- i != ve->occluders().end();
- i++) {
- WRITE_IF_NON_NULL((*i));
- }
- }
-
- return 0;
-}
-
-static int save(ostream &out, ViewVertex *vv)
-{
- if (!vv) {
- cerr << "Warning: null ViewVertex" << endl;
- return 1;
- }
-
- // Nature
- Nature::VertexNature nature = vv->getNature();
- WRITE(nature);
-
- if (vv->getNature() & Nature::T_VERTEX) {
- TVertex *tv = dynamic_cast<TVertex *>(vv);
-
- // Id
- Id::id_type id = tv->getId().getFirst();
- WRITE(id);
- id = tv->getId().getSecond();
- WRITE(id);
-
- // FrontSVertex
- WRITE_IF_NON_NULL(tv->frontSVertex());
-
- // BackSVertex
- WRITE_IF_NON_NULL(tv->backSVertex());
-
- // FrontEdgeA
- WRITE_IF_NON_NULL(tv->frontEdgeA().first);
- WRITE(tv->frontEdgeA().second);
-
- // FrontEdgeB
- WRITE_IF_NON_NULL(tv->frontEdgeB().first);
- WRITE(tv->frontEdgeB().second);
-
- // BackEdgeA
- WRITE_IF_NON_NULL(tv->backEdgeA().first);
- WRITE(tv->backEdgeA().second);
-
- // BackEdgeB
- WRITE_IF_NON_NULL(tv->backEdgeB().first);
- WRITE(tv->backEdgeB().second);
- }
- else if (vv->getNature() & Nature::NON_T_VERTEX) {
- NonTVertex *ntv = dynamic_cast<NonTVertex *>(vv);
-
- // SVertex
- WRITE_IF_NON_NULL(ntv->svertex());
-
- // ViewEdges (List)
- unsigned size = ntv->viewedges().size();
- WRITE(size);
- vector<ViewVertex::directedViewEdge>::const_iterator i = ntv->viewedges().begin();
- for (; i != ntv->viewedges().end(); i++) {
- WRITE_IF_NON_NULL(i->first);
- WRITE(i->second);
- }
- }
- else {
- cerr << "Warning: unexpected ViewVertex nature" << endl;
- return 1;
- }
-
- return 0;
-}
-
-} // End of namespace Internal
-
-//////////////////// "Public" 'load' and 'save' functions ////////////////////
-
-#define SET_PROGRESS(n) \
- if (pb) { \
- pb->setProgress((n)); \
- } \
- (void)0
-
-int load(istream &in, ViewMap *vm, ProgressBar *pb)
-{
- if (!vm) {
- return 1;
- }
-
- // soc unused - unsigned tmp;
- int err = 0;
- Internal::g_vm = vm;
-
- // Management of the progress bar (if present)
- if (pb) {
- pb->reset();
- pb->setLabelText("Loading View Map...");
- pb->setTotalSteps(6);
- pb->setProgress(0);
- }
-
- // Read and set the options
- unsigned char flags;
- READ(flags);
- Options::setFlags(flags);
-
- // Read the size of the five ViewMap's lists (with some extra information for the ViewVertices)
- // and instantiate them (with default costructors)
- unsigned vs_s, fe_s, fe_rle1, fe_rle2, sv_s, ve_s, vv_s, vv_rle1, vv_rle2;
- READ(vs_s);
- READ(fe_s);
-
- if (fe_s) {
- bool b;
- READ(b);
- /* NOLINTNEXTLINE: bugprone-infinite-loop */
- for (READ(fe_rle1), fe_rle2 = 0; fe_rle1 <= fe_s; fe_rle2 = fe_rle1, READ(fe_rle1)) {
- if (b) {
- for (unsigned int i = fe_rle2; i < fe_rle1; i++) {
- FEdgeSmooth *fes = new FEdgeSmooth;
- vm->AddFEdge(fes);
- }
- b = !b;
- }
- else if (!b) {
- for (unsigned int i = fe_rle2; i < fe_rle1; i++) {
- FEdgeSharp *fes = new FEdgeSharp;
- vm->AddFEdge(fes);
- }
- b = !b;
- }
- }
- }
-
- READ(sv_s);
- READ(ve_s);
- READ(vv_s);
-
- if (vv_s) {
- Nature::VertexNature nature;
- READ(nature);
- /* NOLINTNEXTLINE: bugprone-infinite-loop */
- for (READ(vv_rle1), vv_rle2 = 0; vv_rle1 <= vv_s; vv_rle2 = vv_rle1, READ(vv_rle1)) {
- if (nature & Nature::T_VERTEX) {
- for (unsigned int i = vv_rle2; i < vv_rle1; i++) {
- TVertex *tv = new TVertex();
- vm->AddViewVertex(tv);
- }
- nature = Nature::NON_T_VERTEX;
- }
- else if (nature & Nature::NON_T_VERTEX) {
- for (unsigned int i = vv_rle2; i < vv_rle1; i++) {
- NonTVertex *ntv = new NonTVertex();
- vm->AddViewVertex(ntv);
- }
- nature = Nature::T_VERTEX;
- }
- }
- }
-
- for (unsigned int i0 = 0; i0 < vs_s; i0++) {
- SShape *ss = new SShape();
- ViewShape *vs = new ViewShape();
- vs->setSShape(ss);
- ss->setViewShape(vs);
- vm->AddViewShape(vs);
- }
-#if 0
- for (unsigned int i1 = 0; i1 < fe_s; i1++) {
- FEdge *fe = new FEdge();
- vm->AddFEdge(fe);
- }
-#endif
- for (unsigned int i2 = 0; i2 < sv_s; i2++) {
- SVertex *sv = new SVertex();
- vm->AddSVertex(sv);
- }
- for (unsigned int i3 = 0; i3 < ve_s; i3++) {
- ViewEdge *ve = new ViewEdge();
- vm->AddViewEdge(ve);
- }
-
- // Read the values for all the objects created above
- SET_PROGRESS(1);
- for (vector<ViewShape *>::const_iterator i4 = vm->ViewShapes().begin();
- i4 != vm->ViewShapes().end();
- i4++) {
- err += Internal::load(in, *i4);
- }
- SET_PROGRESS(2);
- for (vector<FEdge *>::const_iterator i5 = vm->FEdges().begin(); i5 != vm->FEdges().end(); i5++) {
- err += Internal::load(in, *i5);
- }
- SET_PROGRESS(3);
- for (vector<SVertex *>::const_iterator i6 = vm->SVertices().begin(); i6 != vm->SVertices().end();
- i6++) {
- err += Internal::load(in, *i6);
- }
- SET_PROGRESS(4);
- for (vector<ViewEdge *>::const_iterator i7 = vm->ViewEdges().begin();
- i7 != vm->ViewEdges().end();
- i7++) {
- err += Internal::load(in, *i7);
- }
- SET_PROGRESS(5);
- for (vector<ViewVertex *>::const_iterator i8 = vm->ViewVertices().begin();
- i8 != vm->ViewVertices().end();
- i8++) {
- err += Internal::load(in, *i8);
- }
- SET_PROGRESS(6);
-
- // Read the shape id to index mapping
- unsigned map_s;
- READ(map_s);
- unsigned id, index;
- for (unsigned int i4 = 0; i4 < map_s; ++i4) {
- READ(id);
- READ(index);
- vm->shapeIdToIndexMap()[id] = index;
- }
-
- return err;
-}
-
-int save(ostream &out, ViewMap *vm, ProgressBar *pb)
-{
- if (!vm) {
- return 1;
- }
-
- int err = 0;
-
- // Management of the progress bar (if present)
- if (pb) {
- pb->reset();
- pb->setLabelText("Saving View Map...");
- pb->setTotalSteps(6);
- pb->setProgress(0);
- }
-
- // For every object, initialize its userdata member to its index in the ViewMap list
- for (unsigned int i0 = 0; i0 < vm->ViewShapes().size(); i0++) {
- vm->ViewShapes()[i0]->userdata = POINTER_FROM_UINT(i0);
- vm->ViewShapes()[i0]->sshape()->userdata = POINTER_FROM_UINT(i0);
- }
- for (unsigned int i1 = 0; i1 < vm->FEdges().size(); i1++) {
- vm->FEdges()[i1]->userdata = POINTER_FROM_UINT(i1);
- }
- for (unsigned int i2 = 0; i2 < vm->SVertices().size(); i2++) {
- vm->SVertices()[i2]->userdata = POINTER_FROM_UINT(i2);
- }
- for (unsigned int i3 = 0; i3 < vm->ViewEdges().size(); i3++) {
- vm->ViewEdges()[i3]->userdata = POINTER_FROM_UINT(i3);
- }
- for (unsigned int i4 = 0; i4 < vm->ViewVertices().size(); i4++) {
- vm->ViewVertices()[i4]->userdata = POINTER_FROM_UINT(i4);
- }
-
- // Write the current options
- unsigned char flags = Options::getFlags();
- WRITE(flags);
-
- // Write the size of the five lists (with some extra information for the ViewVertices)
- unsigned size;
- size = vm->ViewShapes().size();
- WRITE(size);
- size = vm->FEdges().size();
- WRITE(size);
- if (size) {
- bool b = vm->FEdges()[0]->isSmooth();
- WRITE(b);
- for (unsigned int i = 0; i < size; i++) {
- while (i < size && (vm->FEdges()[i]->isSmooth() == b)) {
- i++;
- }
- if (i < size) {
- WRITE(i);
- b = !b;
- }
- }
- WRITE(size);
- size++;
- WRITE(size);
- }
- size = vm->SVertices().size();
- WRITE(size);
- size = vm->ViewEdges().size();
- WRITE(size);
- size = vm->ViewVertices().size();
- WRITE(size);
- if (size) {
- Nature::VertexNature nature = vm->ViewVertices()[0]->getNature();
- WRITE(nature);
- nature &= ~Nature::VIEW_VERTEX;
- for (unsigned int i = 0; i < size; i++) {
- while (i < size && (vm->ViewVertices()[i]->getNature() & nature)) {
- i++;
- }
- if (i < size) {
- WRITE(i);
- nature = vm->ViewVertices()[i]->getNature() & ~Nature::VIEW_VERTEX;
- }
- }
- WRITE(size);
- size++;
- WRITE(size);
- }
-
- // Write all the elts of the ViewShapes List
- SET_PROGRESS(1);
- for (vector<ViewShape *>::const_iterator i5 = vm->ViewShapes().begin();
- i5 != vm->ViewShapes().end();
- i5++) {
- err += Internal::save(out, *i5);
- }
- SET_PROGRESS(2);
- for (vector<FEdge *>::const_iterator i6 = vm->FEdges().begin(); i6 != vm->FEdges().end(); i6++) {
- err += Internal::save(out, *i6);
- }
- SET_PROGRESS(3);
- for (vector<SVertex *>::const_iterator i7 = vm->SVertices().begin(); i7 != vm->SVertices().end();
- i7++) {
- err += Internal::save(out, *i7);
- }
- SET_PROGRESS(4);
- for (vector<ViewEdge *>::const_iterator i8 = vm->ViewEdges().begin();
- i8 != vm->ViewEdges().end();
- i8++) {
- err += Internal::save(out, *i8);
- }
- SET_PROGRESS(5);
- for (vector<ViewVertex *>::const_iterator i9 = vm->ViewVertices().begin();
- i9 != vm->ViewVertices().end();
- i9++) {
- err += Internal::save(out, *i9);
- }
-
- // Write the shape id to index mapping
- size = vm->shapeIdToIndexMap().size();
- WRITE(size);
- unsigned int id, index;
- for (ViewMap::id_to_index_map::iterator mit = vm->shapeIdToIndexMap().begin(),
- mitend = vm->shapeIdToIndexMap().end();
- mit != mitend;
- ++mit) {
- id = mit->first;
- index = mit->second;
- WRITE(id);
- WRITE(index);
- }
-
- // Reset 'userdata' members
- for (vector<ViewShape *>::const_iterator j0 = vm->ViewShapes().begin();
- j0 != vm->ViewShapes().end();
- j0++) {
- (*j0)->userdata = nullptr;
- (*j0)->sshape()->userdata = nullptr;
- }
- for (vector<FEdge *>::const_iterator j1 = vm->FEdges().begin(); j1 != vm->FEdges().end(); j1++) {
- (*j1)->userdata = nullptr;
- }
- for (vector<SVertex *>::const_iterator j2 = vm->SVertices().begin(); j2 != vm->SVertices().end();
- j2++) {
- (*j2)->userdata = nullptr;
- }
- for (vector<ViewEdge *>::const_iterator j3 = vm->ViewEdges().begin();
- j3 != vm->ViewEdges().end();
- j3++) {
- (*j3)->userdata = nullptr;
- }
- for (vector<ViewVertex *>::const_iterator j4 = vm->ViewVertices().begin();
- j4 != vm->ViewVertices().end();
- j4++) {
- (*j4)->userdata = nullptr;
- }
- SET_PROGRESS(6);
-
- return err;
-}
-
-//////////////////// Options ////////////////////
-
-namespace Options {
-
-namespace Internal {
-
-static unsigned char g_flags = 0;
-static string g_models_path;
-
-} // End of namespace Internal
-
-void setFlags(const unsigned char flags)
-{
- Internal::g_flags = flags;
-}
-
-void addFlags(const unsigned char flags)
-{
- Internal::g_flags |= flags;
-}
-
-void rmFlags(const unsigned char flags)
-{
- Internal::g_flags &= ~flags;
-}
-
-unsigned char getFlags()
-{
- return Internal::g_flags;
-}
-
-void setModelsPath(const string &path)
-{
- Internal::g_models_path = path;
-}
-
-string getModelsPath()
-{
- return Internal::g_models_path;
-}
-
-} // namespace Options
-
-} // namespace Freestyle::ViewMapIO
diff --git a/source/blender/freestyle/intern/view_map/ViewMapIO.h b/source/blender/freestyle/intern/view_map/ViewMapIO.h
deleted file mode 100644
index 4796b28a38a..00000000000
--- a/source/blender/freestyle/intern/view_map/ViewMapIO.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#pragma once
-
-/** \file
- * \ingroup freestyle
- * \brief Functions to manage I/O for the view map
- */
-
-#include <fstream>
-#include <string>
-
-#include "ViewMap.h"
-
-#include "../system/FreestyleConfig.h"
-#include "../system/ProgressBar.h"
-
-namespace Freestyle {
-
-namespace ViewMapIO {
-
-static const unsigned ZERO = UINT_MAX;
-
-int load(istream &in, ViewMap *vm, ProgressBar *pb = NULL);
-
-int save(ostream &out, ViewMap *vm, ProgressBar *pb = NULL);
-
-namespace Options {
-
-static const unsigned char FLOAT_VECTORS = 1;
-static const unsigned char NO_OCCLUDERS = 2;
-
-void setFlags(unsigned char flags);
-
-void addFlags(unsigned char flags);
-
-void rmFlags(unsigned char flags);
-
-unsigned char getFlags();
-
-void setModelsPath(const string &path);
-
-string getModelsPath();
-
-}; // namespace Options
-
-#ifdef IRIX
-
-namespace Internal {
-
-template<unsigned S> ostream &write(ostream &out, const char *str)
-{
- out.put(str[S - 1]);
- return write<S - 1>(out, str);
-}
-
-template<> ostream &write<1>(ostream &out, const char *str)
-{
- return out.put(str[0]);
-}
-
-template<> ostream &write<0>(ostream &out, const char *)
-{
- return out;
-}
-
-template<unsigned S> istream &read(istream &in, char *str)
-{
- in.get(str[S - 1]);
- return read<S - 1>(in, str);
-}
-
-template<> istream &read<1>(istream &in, char *str)
-{
- return in.get(str[0]);
-}
-
-template<> istream &read<0>(istream &in, char *)
-{
- return in;
-}
-
-} // End of namespace Internal
-
-#endif // IRIX
-
-} // End of namespace ViewMapIO
-
-} /* namespace Freestyle */
diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.h b/source/blender/freestyle/intern/winged_edge/WEdge.h
index 6d39446056f..00f4c537d4a 100644
--- a/source/blender/freestyle/intern/winged_edge/WEdge.h
+++ b/source/blender/freestyle/intern/winged_edge/WEdge.h
@@ -143,12 +143,14 @@ class WVertex {
public:
/** Iterator to iterate over a vertex incoming edges in the CCW order. */
-#if defined(__GNUC__) && (__GNUC__ < 3)
- class incoming_edge_iterator : public input_iterator<WOEdge *, ptrdiff_t>
-#else
- class incoming_edge_iterator : public iterator<input_iterator_tag, WOEdge *, ptrdiff_t>
-#endif
- {
+ class incoming_edge_iterator {
+ public:
+ using iterator_category = input_iterator_tag;
+ using value_type = WOEdge *;
+ using difference_type = ptrdiff_t;
+ using pointer = value_type *;
+ using reference = value_type &;
+
private:
WVertex *_vertex;
//
@@ -156,25 +158,12 @@ class WVertex {
WOEdge *_current;
public:
-#if defined(__GNUC__) && (__GNUC__ < 3)
- inline incoming_edge_iterator() : input_iterator<WOEdge *, ptrdiff_t>()
- {
- }
-#else
- inline incoming_edge_iterator() : iterator<input_iterator_tag, WOEdge *, ptrdiff_t>()
- {
- }
-#endif
- virtual ~incoming_edge_iterator(){}; // soc
+ inline incoming_edge_iterator() = default;
+ virtual ~incoming_edge_iterator() = default;
protected:
friend class WVertex;
inline incoming_edge_iterator(WVertex *iVertex, WOEdge *iBegin, WOEdge *iCurrent)
-#if defined(__GNUC__) && (__GNUC__ < 3)
- : input_iterator<WOEdge *, ptrdiff_t>()
-#else
- : iterator<input_iterator_tag, WOEdge *, ptrdiff_t>()
-#endif
{
_vertex = iVertex;
_begin = iBegin;
@@ -183,11 +172,6 @@ class WVertex {
public:
inline incoming_edge_iterator(const incoming_edge_iterator &iBrother)
-#if defined(__GNUC__) && (__GNUC__ < 3)
- : input_iterator<WOEdge *, ptrdiff_t>(iBrother)
-#else
- : iterator<input_iterator_tag, WOEdge *, ptrdiff_t>(iBrother)
-#endif
{
_vertex = iBrother._vertex;
_begin = iBrother._begin;
@@ -233,47 +217,30 @@ class WVertex {
#endif
};
- /** Iterator to iterate over a vertex faces in the CCW order */
-#if defined(__GNUC__) && (__GNUC__ < 3)
- class face_iterator : public input_iterator<WFace *, ptrdiff_t>
-#else
- class face_iterator : public iterator<input_iterator_tag, WFace *, ptrdiff_t>
-#endif
- {
+ class face_iterator {
+ public:
+ using iterator_category = input_iterator_tag;
+ using value_type = WFace *;
+ using difference_type = ptrdiff_t;
+ using pointer = value_type *;
+ using reference = value_type &;
+
private:
incoming_edge_iterator _edge_it;
public:
-#if defined(__GNUC__) && (__GNUC__ < 3)
- inline face_iterator() : input_iterator<WFace *, ptrdiff_t>()
- {
- }
-#else
- inline face_iterator() : iterator<input_iterator_tag, WFace *, ptrdiff_t>()
- {
- }
-#endif
- virtual ~face_iterator(){}; // soc
+ inline face_iterator() = default;
+ virtual ~face_iterator() = default;
protected:
friend class WVertex;
inline face_iterator(incoming_edge_iterator it)
-#if defined(__GNUC__) && (__GNUC__ < 3)
- : input_iterator<WFace *, ptrdiff_t>()
-#else
- : iterator<input_iterator_tag, WFace *, ptrdiff_t>()
-#endif
{
_edge_it = it;
}
public:
inline face_iterator(const face_iterator &iBrother)
-#if defined(__GNUC__) && (__GNUC__ < 3)
- : input_iterator<WFace *, ptrdiff_t>(iBrother)
-#else
- : iterator<input_iterator_tag, WFace *, ptrdiff_t>(iBrother)
-#endif
{
_edge_it = iBrother._edge_it;
}
diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index 55432003010..f1298a7f5b7 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -13,9 +13,6 @@ set(INC_SYS
set(SRC
intern/cpp_types.cc
intern/field.cc
- intern/generic_vector_array.cc
- intern/generic_virtual_array.cc
- intern/generic_virtual_vector_array.cc
intern/multi_function.cc
intern/multi_function_builder.cc
intern/multi_function_params.cc
@@ -24,17 +21,8 @@ set(SRC
intern/multi_function_procedure_executor.cc
intern/multi_function_procedure_optimization.cc
- FN_cpp_type.hh
- FN_cpp_type_make.hh
FN_field.hh
FN_field_cpp_type.hh
- FN_generic_array.hh
- FN_generic_pointer.hh
- FN_generic_span.hh
- FN_generic_value_map.hh
- FN_generic_vector_array.hh
- FN_generic_virtual_array.hh
- FN_generic_virtual_vector_array.hh
FN_multi_function.hh
FN_multi_function_builder.hh
FN_multi_function_context.hh
@@ -72,11 +60,7 @@ blender_add_lib(bf_functions "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
if(WITH_GTESTS)
set(TEST_SRC
- tests/FN_cpp_type_test.cc
tests/FN_field_test.cc
- tests/FN_generic_array_test.cc
- tests/FN_generic_span_test.cc
- tests/FN_generic_vector_array_test.cc
tests/FN_multi_function_procedure_test.cc
tests/FN_multi_function_test.cc
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index 2cba833ce64..5a27cda0787 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -33,11 +33,11 @@
*/
#include "BLI_function_ref.hh"
+#include "BLI_generic_virtual_array.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"
namespace blender::fn {
@@ -119,7 +119,7 @@ template<typename NodePtr> class GFieldBase {
return get_default_hash_2(*node_, node_output_index_);
}
- const fn::CPPType &cpp_type() const
+ const CPPType &cpp_type() const
{
return node_->output_cpp_type(node_output_index_);
}
@@ -476,13 +476,13 @@ template<typename T> T evaluate_constant_field(const Field<T> &field)
return value;
}
+GField make_constant_field(const CPPType &type, const void *value);
+
template<typename T> Field<T> make_constant_field(T value)
{
return make_constant_field(CPPType::get<T>(), &value);
}
-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.
diff --git a/source/blender/functions/FN_field_cpp_type.hh b/source/blender/functions/FN_field_cpp_type.hh
index 24477246582..63a648f3202 100644
--- a/source/blender/functions/FN_field_cpp_type.hh
+++ b/source/blender/functions/FN_field_cpp_type.hh
@@ -6,7 +6,7 @@
* \ingroup fn
*/
-#include "FN_cpp_type_make.hh"
+#include "BLI_cpp_type_make.hh"
#include "FN_field.hh"
namespace blender::fn {
@@ -127,16 +127,14 @@ class ValueOrFieldCPPType : public CPPType {
} // namespace blender::fn
#define MAKE_FIELD_CPP_TYPE(DEBUG_NAME, FIELD_TYPE) \
- template<> \
- const blender::fn::CPPType &blender::fn::CPPType::get_impl<blender::fn::Field<FIELD_TYPE>>() \
+ template<> const blender::CPPType &blender::CPPType::get_impl<blender::fn::Field<FIELD_TYPE>>() \
{ \
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>>() \
+ const blender::CPPType &blender::CPPType::get_impl<blender::fn::ValueOrField<FIELD_TYPE>>() \
{ \
static blender::fn::ValueOrFieldCPPType cpp_type{ \
blender::fn::FieldCPPTypeParam<blender::fn::ValueOrField<FIELD_TYPE>>(), \
diff --git a/source/blender/functions/FN_multi_function.hh b/source/blender/functions/FN_multi_function.hh
index cca6955aeb0..015df179ef0 100644
--- a/source/blender/functions/FN_multi_function.hh
+++ b/source/blender/functions/FN_multi_function.hh
@@ -154,9 +154,6 @@ inline MFParamsBuilder::MFParamsBuilder(const MultiFunction &fn, const IndexMask
}
namespace multi_function_types {
-using fn::CPPType;
-using fn::GMutableSpan;
-using fn::GSpan;
using fn::MFContext;
using fn::MFContextBuilder;
using fn::MFDataType;
diff --git a/source/blender/functions/FN_multi_function_data_type.hh b/source/blender/functions/FN_multi_function_data_type.hh
index a0ded253d26..d63e0faaca5 100644
--- a/source/blender/functions/FN_multi_function_data_type.hh
+++ b/source/blender/functions/FN_multi_function_data_type.hh
@@ -10,7 +10,7 @@
* is possible when necessary.
*/
-#include "FN_cpp_type.hh"
+#include "BLI_cpp_type.hh"
namespace blender::fn {
diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh
index 38736527771..67f31a61dc4 100644
--- a/source/blender/functions/FN_multi_function_params.hh
+++ b/source/blender/functions/FN_multi_function_params.hh
@@ -13,11 +13,11 @@
#include <mutex>
+#include "BLI_generic_pointer.hh"
+#include "BLI_generic_vector_array.hh"
+#include "BLI_generic_virtual_vector_array.hh"
#include "BLI_resource_scope.hh"
-#include "FN_generic_pointer.hh"
-#include "FN_generic_vector_array.hh"
-#include "FN_generic_virtual_vector_array.hh"
#include "FN_multi_function_signature.hh"
namespace blender::fn {
diff --git a/source/blender/functions/intern/cpp_types.cc b/source/blender/functions/intern/cpp_types.cc
index 5606f660237..a2adc2ea8b6 100644
--- a/source/blender/functions/intern/cpp_types.cc
+++ b/source/blender/functions/intern/cpp_types.cc
@@ -1,38 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "FN_cpp_type_make.hh"
-#include "FN_field_cpp_type.hh"
-
#include "BLI_color.hh"
+#include "BLI_cpp_type_make.hh"
#include "BLI_float4x4.hh"
#include "BLI_math_vec_types.hh"
-namespace blender::fn {
-
-MAKE_CPP_TYPE(bool, bool, CPPTypeFlags::BasicType)
-
-MAKE_CPP_TYPE(float, float, CPPTypeFlags::BasicType)
-MAKE_CPP_TYPE(float2, blender::float2, CPPTypeFlags::BasicType)
-MAKE_CPP_TYPE(float3, blender::float3, CPPTypeFlags::BasicType)
-MAKE_CPP_TYPE(float4x4, blender::float4x4, CPPTypeFlags::BasicType)
-
-MAKE_CPP_TYPE(int32, int32_t, CPPTypeFlags::BasicType)
-MAKE_CPP_TYPE(int8, int8_t, CPPTypeFlags::BasicType)
-MAKE_CPP_TYPE(uint32, uint32_t, CPPTypeFlags::BasicType)
-MAKE_CPP_TYPE(uint8, uint8_t, CPPTypeFlags::BasicType)
-
-MAKE_CPP_TYPE(ColorGeometry4f, blender::ColorGeometry4f, CPPTypeFlags::BasicType)
-MAKE_CPP_TYPE(ColorGeometry4b, blender::ColorGeometry4b, CPPTypeFlags::BasicType)
-
-MAKE_CPP_TYPE(string, std::string, CPPTypeFlags::BasicType)
+#include "FN_field_cpp_type.hh"
MAKE_FIELD_CPP_TYPE(FloatField, float);
-MAKE_FIELD_CPP_TYPE(Float2Field, float2);
-MAKE_FIELD_CPP_TYPE(Float3Field, float3);
+MAKE_FIELD_CPP_TYPE(Float2Field, blender::float2);
+MAKE_FIELD_CPP_TYPE(Float3Field, blender::float3);
MAKE_FIELD_CPP_TYPE(ColorGeometry4fField, blender::ColorGeometry4f);
MAKE_FIELD_CPP_TYPE(BoolField, bool);
MAKE_FIELD_CPP_TYPE(Int8Field, int8_t);
MAKE_FIELD_CPP_TYPE(Int32Field, int32_t);
MAKE_FIELD_CPP_TYPE(StringField, std::string);
-
-} // namespace blender::fn
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index 7b514b6a49b..9f742f11ce4 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_index_mask_ops.hh"
#include "BLI_map.hh"
#include "BLI_multi_value_map.hh"
#include "BLI_set.hh"
@@ -692,29 +693,21 @@ GPointer FieldConstant::value() const
* FieldEvaluator.
*/
-static Vector<int64_t> indices_from_selection(IndexMask mask, const VArray<bool> &selection)
+static IndexMask index_mask_from_selection(const IndexMask full_mask,
+ VArray<bool> &selection,
+ ResourceScope &scope)
{
- /* 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. */
- BLI_assert(!selection.is_single());
-
- Vector<int64_t> indices;
if (selection.is_span()) {
Span<bool> span = selection.get_internal_span();
- for (const int64_t i : mask) {
- if (span[i]) {
- indices.append(i);
- }
- }
+ return index_mask_ops::find_indices_based_on_predicate(
+ full_mask, 4096, scope.construct<Vector<int64_t>>(), [&](const int curve_index) {
+ return span[curve_index];
+ });
}
- else {
- for (const int i : mask) {
- if (selection[i]) {
- indices.append(i);
- }
- }
- }
- return indices;
+ return index_mask_ops::find_indices_based_on_predicate(
+ full_mask, 1024, scope.construct<Vector<int64_t>>(), [&](const int curve_index) {
+ return selection[curve_index];
+ });
}
int FieldEvaluator::add_with_destination(GField field, GVMutableArray dst)
@@ -763,7 +756,7 @@ static IndexMask evaluate_selection(const Field<bool> &selection_field,
}
return IndexRange(0);
}
- return scope.add_value(indices_from_selection(full_mask, selection)).as_span();
+ return index_mask_from_selection(full_mask, selection, scope);
}
return full_mask;
}
@@ -799,8 +792,7 @@ IndexMask FieldEvaluator::get_evaluated_as_mask(const int field_index)
}
return IndexRange(0);
}
-
- return scope_.add_value(indices_from_selection(mask_, varray)).as_span();
+ return index_mask_from_selection(mask_, varray, scope_);
}
IndexMask FieldEvaluator::get_evaluated_selection_as_mask()
diff --git a/source/blender/functions/tests/FN_field_test.cc b/source/blender/functions/tests/FN_field_test.cc
index 6417066b47b..ea3c0471411 100644
--- a/source/blender/functions/tests/FN_field_test.cc
+++ b/source/blender/functions/tests/FN_field_test.cc
@@ -2,7 +2,7 @@
#include "testing/testing.h"
-#include "FN_cpp_type.hh"
+#include "BLI_cpp_type.hh"
#include "FN_field.hh"
#include "FN_multi_function_builder.hh"
#include "FN_multi_function_test_common.hh"
diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc
index 0c2377fde6d..5ba9bc066fd 100644
--- a/source/blender/geometry/intern/mesh_to_curve_convert.cc
+++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc
@@ -32,7 +32,7 @@ static void copy_with_map(const VArray<T> &src, Span<int> map, MutableSpan<T> ds
static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_component,
const Span<int> vert_indices,
const Span<int> curve_offsets,
- const IndexRange cyclic_splines)
+ const IndexRange cyclic_curves)
{
Curves *curves_id = bke::curves_new_nomain(vert_indices.size(), curve_offsets.size());
bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
@@ -41,7 +41,7 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen
curves.curve_types().fill(CURVE_TYPE_POLY);
curves.cyclic().fill(false);
- curves.cyclic().slice(cyclic_splines).fill(true);
+ curves.cyclic().slice(cyclic_curves).fill(true);
Set<bke::AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids();
@@ -59,15 +59,15 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen
continue;
}
- const fn::GVArray mesh_attribute = mesh_component.attribute_try_get_for_read(
- attribute_id, ATTR_DOMAIN_POINT);
+ const GVArray mesh_attribute = mesh_component.attribute_try_get_for_read(attribute_id,
+ ATTR_DOMAIN_POINT);
/* Some attributes might not exist if they were builtin attribute on domains that don't
* have any elements, i.e. a face attribute on the output of the line primitive node. */
if (!mesh_attribute) {
continue;
}
- /* Copy attribute based on the map for this spline. */
+ /* Copy attribute based on the map for this curve. */
attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) {
using T = decltype(dummy);
bke::OutputAttribute_Typed<T> attribute =
@@ -81,12 +81,12 @@ static Curves *create_curve_from_vert_indices(const MeshComponent &mesh_componen
}
struct CurveFromEdgesOutput {
- /** The indices in the mesh for each control point of each result splines. */
+ /** The indices in the mesh for each control point of each result curves. */
Vector<int> vert_indices;
/** The first index of each curve in the result. */
Vector<int> curve_offsets;
- /** A subset of splines that should be set cyclic. */
- IndexRange cyclic_splines;
+ /** A subset of curves that should be set cyclic. */
+ IndexRange cyclic_curves;
};
static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
@@ -128,7 +128,7 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
Array<int> unused_edges = std::move(used_slots);
for (const int start_vert : verts.index_range()) {
- /* The vertex will be part of a cyclic spline. */
+ /* The vertex will be part of a cyclic curve. */
if (neighbor_count[start_vert] == 2) {
continue;
}
@@ -171,10 +171,10 @@ static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
}
}
- /* All splines added after this are cyclic. */
+ /* All curves added after this are cyclic. */
const int cyclic_start = curve_offsets.size();
- /* All remaining edges are part of cyclic splines (we skipped vertices with two edges before). */
+ /* All remaining edges are part of cyclic curves (we skipped vertices with two edges before). */
for (const int start_vert : verts.index_range()) {
if (unused_edges[start_vert] != 2) {
continue;
@@ -230,7 +230,7 @@ Curves *mesh_to_curve_convert(const MeshComponent &mesh_component, const IndexMa
selected_edges);
return create_curve_from_vert_indices(
- mesh_component, output.vert_indices, output.curve_offsets, output.cyclic_splines);
+ mesh_component, output.vert_indices, output.curve_offsets, output.cyclic_curves);
}
} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
index 32bad07de4f..8d186edc607 100644
--- a/source/blender/geometry/intern/realize_instances.cc
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -18,7 +18,6 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
#include "BKE_type_conversions.hh"
namespace blender::geometry {
@@ -30,12 +29,6 @@ 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.
@@ -274,7 +267,7 @@ static void threaded_copy(const GSpan src, GMutableSpan dst)
});
}
-static void threaded_fill(const fn::GPointer value, GMutableSpan dst)
+static void threaded_fill(const GPointer value, GMutableSpan dst)
{
BLI_assert(*value.type() == dst.type());
threading::parallel_for(IndexRange(dst.size()), 1024, [&](const IndexRange range) {
@@ -1146,8 +1139,8 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
const Curves &curves_id = *curves_info.curves;
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- const IndexRange dst_point_range{task.start_indices.point, curves.points_size()};
- const IndexRange dst_curve_range{task.start_indices.curve, curves.curves_size()};
+ const IndexRange dst_point_range{task.start_indices.point, curves.points_num()};
+ const IndexRange dst_curve_range{task.start_indices.curve, curves.curves_num()};
copy_transformed_positions(
curves.positions(), task.transform, dst_curves.positions().slice(dst_point_range));
@@ -1201,9 +1194,9 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
[&](const AttributeDomain domain) {
switch (domain) {
case ATTR_DOMAIN_POINT:
- return IndexRange(task.start_indices.point, curves.points_size());
+ return IndexRange(task.start_indices.point, curves.points_num());
case ATTR_DOMAIN_CURVE:
- return IndexRange(task.start_indices.curve, curves.curves_size());
+ return IndexRange(task.start_indices.curve, curves.curves_num());
default:
BLI_assert_unreachable();
return IndexRange();
diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt
index 752d4aea61c..6108629183c 100644
--- a/source/blender/gpencil_modifiers/CMakeLists.txt
+++ b/source/blender/gpencil_modifiers/CMakeLists.txt
@@ -37,6 +37,7 @@ set(SRC
intern/MOD_gpencilbuild.c
intern/MOD_gpencilcolor.c
intern/MOD_gpencildash.c
+ intern/MOD_gpencilenvelope.c
intern/MOD_gpencilhook.c
intern/MOD_gpencillattice.c
intern/MOD_gpencillength.c
diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
index ff280b9ca0d..e88d864a86e 100644
--- a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
+++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h
@@ -35,6 +35,7 @@ extern GpencilModifierTypeInfo modifierType_Gpencil_WeightAngle;
extern GpencilModifierTypeInfo modifierType_Gpencil_Lineart;
extern GpencilModifierTypeInfo modifierType_Gpencil_Dash;
extern GpencilModifierTypeInfo modifierType_Gpencil_Shrinkwrap;
+extern GpencilModifierTypeInfo modifierType_Gpencil_Envelope;
/* MOD_gpencil_util.c */
void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index e766615101a..6cf7f6f11e5 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -56,6 +56,7 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
INIT_GP_TYPE(Lineart);
INIT_GP_TYPE(Dash);
INIT_GP_TYPE(Shrinkwrap);
+ INIT_GP_TYPE(Envelope);
#undef INIT_GP_TYPE
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
index 439073752da..25c7fdca9f6 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c
@@ -97,12 +97,13 @@ static bool stroke_dash(const bGPDstroke *gps,
int new_stroke_offset = 0;
int trim_start = 0;
+ int sequence_length = 0;
for (int i = 0; i < dmd->segments_len; i++) {
- if (dmd->segments[i].dash + real_gap(&dmd->segments[i]) < 1) {
- BLI_assert_unreachable();
- /* This means there's a part that doesn't have any length, can't do dot-dash. */
- return false;
- }
+ sequence_length += dmd->segments[i].dash + real_gap(&dmd->segments[i]);
+ }
+ if (sequence_length < 1) {
+ /* This means the whole segment has no length, can't do dot-dash. */
+ return false;
}
const DashGpencilModifierSegment *const first_segment = &dmd->segments[0];
@@ -204,9 +205,10 @@ static void apply_dash_for_frame(
dmd->flag & GP_LENGTH_INVERT_PASS,
dmd->flag & GP_LENGTH_INVERT_LAYERPASS,
dmd->flag & GP_LENGTH_INVERT_MATERIAL)) {
- stroke_dash(gps, dmd, &result);
- BLI_remlink(&gpf->strokes, gps);
- BKE_gpencil_free_stroke(gps);
+ if (stroke_dash(gps, dmd, &result)) {
+ BLI_remlink(&gpf->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
+ }
}
}
bGPDstroke *gps_dash;
@@ -232,6 +234,18 @@ static void bakeModifier(Main *UNUSED(bmain),
/* -------------------------------- */
+static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams))
+{
+ DashGpencilModifierData *dmd = (DashGpencilModifierData *)md;
+
+ int sequence_length = 0;
+ for (int i = 0; i < dmd->segments_len; i++) {
+ sequence_length += dmd->segments[i].dash + real_gap(&dmd->segments[i]);
+ }
+ /* This means the whole segment has no length, can't do dot-dash. */
+ return sequence_length < 1;
+}
+
/* Generic "generateStrokes" callback */
static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob)
{
@@ -362,7 +376,7 @@ GpencilModifierTypeInfo modifierType_Gpencil_Dash = {
/* initData */ initData,
/* freeData */ freeData,
- /* isDisabled */ NULL,
+ /* isDisabled */ isDisabled,
/* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* foreachIDLink */ foreachIDLink,
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c
new file mode 100644
index 00000000000..f8ac8d95493
--- /dev/null
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c
@@ -0,0 +1,628 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2017 Blender Foundation. */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include <stdio.h>
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_geom.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_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_deform.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_modifier.h"
+#include "BKE_lib_query.h"
+#include "BKE_modifier.h"
+#include "BKE_screen.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.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 "MEM_guardedalloc.h"
+
+static void initData(GpencilModifierData *md)
+{
+ EnvelopeGpencilModifierData *gpmd = (EnvelopeGpencilModifierData *)md;
+
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
+
+ MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(EnvelopeGpencilModifierData), modifier);
+}
+
+static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
+{
+ BKE_gpencil_modifier_copydata_generic(md, target);
+}
+
+static float calc_min_radius_v3v3(float p1[3], float p2[3], float dir[3])
+{
+ /* Use plane-conic-intersections to choose the maximal radius.
+ * The conic is defined in 4D as f({x,y,z,t}) = x*x + y*y + z*z - t*t = 0
+ * Then a plane is defined parametrically as
+ * {p}(u, v) = {p1,0}*u + {p2,0}*(1-u) + {dir,1}*v with 0 <= u <= 1 and v >= 0
+ * Now compute the intersection point with the smallest t.
+ * To do so, compute the parameters u, v such that f(p(u, v)) = 0 and v is minimal.
+ * This can be done analytically and the solution is:
+ * u = -dot(p2,dir) / dot(p1-p2, dir) +/- sqrt((dot(p2,dir) / dot(p1-p2, dir))^2 -
+ * (2*dot(p1-p2,p2)*dot(p2,dir)-dot(p2,p2)*dot(p1-p2,dir))/(dot(p1-p2,dir)*dot(p1-p2,p1-p2)));
+ * v = ({p1}u + {p2}*(1-u))^2 / (2*(dot(p1,dir)*u + dot(p2,dir)*(1-u)));
+ */
+ float diff[3];
+ float p1_dir = dot_v3v3(p1, dir);
+ float p2_dir = dot_v3v3(p2, dir);
+ float p2_sqr = len_squared_v3(p2);
+ float diff_dir = p1_dir - p2_dir;
+ float u = 0.5f;
+ if (diff_dir != 0.0f) {
+ float p = p2_dir / diff_dir;
+ sub_v3_v3v3(diff, p1, p2);
+ float diff_sqr = len_squared_v3(diff);
+ float diff_p2 = dot_v3v3(diff, p2);
+ float q = (2 * diff_p2 * p2_dir - p2_sqr * diff_dir) / (diff_dir * diff_sqr);
+ if (p * p - q >= 0) {
+ u = -p - sqrtf(p * p - q) * copysign(1.0f, p);
+ CLAMP(u, 0.0f, 1.0f);
+ }
+ else {
+ u = 0.5f - copysign(0.5f, p);
+ }
+ }
+ else {
+ float p1_sqr = len_squared_v3(p1);
+ u = p1_sqr < p2_sqr ? 1.0f : 0.0f;
+ }
+ float p[3];
+ interp_v3_v3v3(p, p2, p1, u);
+ /* v is the determined minimal radius. In case p1 and p2 are the same, there is a
+ * simple proof for the following formula using the geometric mean theorem and Thales theorem. */
+ float v = len_squared_v3(p) / (2 * interpf(p1_dir, p2_dir, u));
+ if (v < 0 || !isfinite(v)) {
+ /* No limit to the radius from this segment. */
+ return 1e16f;
+ }
+ return v;
+}
+
+static float calc_radius_limit(
+ bGPDstroke *gps, bGPDspoint *points, float dir[3], int spread, const int i)
+{
+ const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0;
+ bGPDspoint *pt = &points[i];
+
+ /* NOTE this part is the second performance critical part. Improvements are welcome. */
+ float radius_limit = 1e16f;
+ float p1[3], p2[3];
+ if (is_cyclic) {
+ if (gps->totpoints / 2 < spread) {
+ spread = gps->totpoints / 2;
+ }
+ const int start = i + gps->totpoints;
+ for (int j = -spread; j <= spread; j++) {
+ j += (j == 0);
+ const int i1 = (start + j) % gps->totpoints;
+ const int i2 = (start + j + (j > 0) - (j < 0)) % gps->totpoints;
+ sub_v3_v3v3(p1, &points[i1].x, &pt->x);
+ sub_v3_v3v3(p2, &points[i2].x, &pt->x);
+ float r = calc_min_radius_v3v3(p1, p2, dir);
+ radius_limit = min_ff(radius_limit, r);
+ }
+ }
+ else {
+ const int start = max_ii(-spread, 1 - i);
+ const int end = min_ii(spread, gps->totpoints - 2 - i);
+ for (int j = start; j <= end; j++) {
+ if (j == 0) {
+ continue;
+ }
+ const int i1 = i + j;
+ const int i2 = i + j + (j > 0) - (j < 0);
+ sub_v3_v3v3(p1, &points[i1].x, &pt->x);
+ sub_v3_v3v3(p2, &points[i2].x, &pt->x);
+ float r = calc_min_radius_v3v3(p1, p2, dir);
+ radius_limit = min_ff(radius_limit, r);
+ }
+ }
+ return radius_limit;
+}
+
+static void apply_stroke_envelope(
+ bGPDstroke *gps, int spread, const int def_nr, const bool invert_vg, const float thickness)
+{
+ const bool is_cyclic = (gps->flag & GP_STROKE_CYCLIC) != 0;
+ if (is_cyclic) {
+ const int half = gps->totpoints / 2;
+ spread = abs(((spread + half) % gps->totpoints) - half);
+ }
+ else {
+ spread = min_ii(spread, gps->totpoints - 1);
+ }
+
+ const int spread_left = (spread + 2) / 2;
+ const int spread_right = (spread + 1) / 2;
+
+ /* Copy the point data. Only need positions, but extracting them
+ * is probably just as expensive as a full copy. */
+ bGPDspoint *old_points = (bGPDspoint *)MEM_dupallocN(gps->points);
+
+ /* Deform the stroke to match the envelope shape. */
+ for (int i = 0; i < gps->totpoints; i++) {
+ MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL;
+
+ /* Verify in vertex group. */
+ float weight = get_modifier_point_weight(dvert, invert_vg, def_nr);
+ if (weight < 0.0f) {
+ continue;
+ }
+
+ int index1 = i - spread_left;
+ int index2 = i + spread_right;
+ CLAMP(index1, 0, gps->totpoints - 1);
+ CLAMP(index2, 0, gps->totpoints - 1);
+
+ bGPDspoint *point = &gps->points[i];
+ point->pressure *= interpf(thickness, 1.0f, weight);
+
+ float closest[3];
+ float closest2[3];
+ copy_v3_v3(closest2, &point->x);
+ float dist = 0.0f;
+ float dist2 = 0.0f;
+ /* Create plane from point and neighbors and intersect that with the line. */
+ float v1[3], v2[3], plane_no[3];
+ sub_v3_v3v3(
+ v1,
+ &old_points[is_cyclic ? (i - 1 + gps->totpoints) % gps->totpoints : max_ii(0, i - 1)].x,
+ &old_points[i].x);
+ sub_v3_v3v3(
+ v2,
+ &old_points[is_cyclic ? (i + 1) % gps->totpoints : min_ii(gps->totpoints - 1, i + 1)].x,
+ &old_points[i].x);
+ normalize_v3(v1);
+ normalize_v3(v2);
+ sub_v3_v3v3(plane_no, v1, v2);
+ if (normalize_v3(plane_no) == 0.0f) {
+ continue;
+ }
+ /* Now find the intersections with the plane. */
+ /* NOTE this part is the first performance critical part. Improvements are welcome. */
+ float tmp_closest[3];
+ for (int j = -spread_right; j <= spread_left; j++) {
+ const int i1 = is_cyclic ? (i + j - spread_left + gps->totpoints) % gps->totpoints :
+ max_ii(0, i + j - spread_left);
+ const int i2 = is_cyclic ? (i + j + spread_right) % gps->totpoints :
+ min_ii(gps->totpoints - 1, i + j + spread_right);
+ /*bool side = dot_v3v3(&old_points[i1].x, plane_no) < dot_v3v3(plane_no, &old_points[i2].x);
+ if (side) {
+ continue;
+ }*/
+ float lambda = line_plane_factor_v3(
+ &point->x, plane_no, &old_points[i1].x, &old_points[i2].x);
+ if (lambda <= 0.0f || lambda >= 1.0f) {
+ continue;
+ }
+ interp_v3_v3v3(tmp_closest, &old_points[i1].x, &old_points[i2].x, lambda);
+
+ float dir[3];
+ sub_v3_v3v3(dir, tmp_closest, &point->x);
+ float d = len_v3(dir);
+ /* Use a formula to find the diameter of the circle that would touch the line. */
+ float cos_angle = fabsf(dot_v3v3(plane_no, &old_points[i1].x) -
+ dot_v3v3(plane_no, &old_points[i2].x)) /
+ len_v3v3(&old_points[i1].x, &old_points[i2].x);
+ d *= 2 * cos_angle / (1 + cos_angle);
+ float to_closest[3];
+ sub_v3_v3v3(to_closest, closest, &point->x);
+ if (dist == 0.0f) {
+ dist = d;
+ copy_v3_v3(closest, tmp_closest);
+ }
+ else if (dot_v3v3(to_closest, dir) >= 0) {
+ if (d > dist) {
+ dist = d;
+ copy_v3_v3(closest, tmp_closest);
+ }
+ }
+ else {
+ if (d > dist2) {
+ dist2 = d;
+ copy_v3_v3(closest2, tmp_closest);
+ }
+ }
+ }
+ if (dist == 0.0f) {
+ copy_v3_v3(closest, &point->x);
+ }
+ if (dist2 == 0.0f) {
+ copy_v3_v3(closest2, &point->x);
+ }
+ dist = dist + dist2;
+
+ if (dist < FLT_EPSILON) {
+ continue;
+ }
+
+ float use_dist = dist;
+
+ /* Apply radius limiting to not cross existing lines. */
+ float dir[3], new_center[3];
+ interp_v3_v3v3(new_center, closest2, closest, 0.5f);
+ sub_v3_v3v3(dir, new_center, &point->x);
+ if (normalize_v3(dir) != 0.0f && (is_cyclic || (i > 0 && i < gps->totpoints - 1))) {
+ const float max_radius = calc_radius_limit(gps, old_points, dir, spread, i);
+ use_dist = min_ff(use_dist, 2 * max_radius);
+ }
+
+ float fac = use_dist * weight;
+ /* The 50 is an internal constant for the default pixel size. The result can be messed up if
+ * #bGPdata.pixfactor is not default, but I think modifiers shouldn't access that. */
+ point->pressure += fac * 50.0f * GP_DEFAULT_PIX_FACTOR;
+ interp_v3_v3v3(&point->x, &point->x, new_center, fac / len_v3v3(closest, closest2));
+ }
+
+ MEM_freeN(old_points);
+}
+
+/**
+ * Apply envelope effect to the stroke.
+ */
+static void deformStroke(GpencilModifierData *md,
+ Depsgraph *UNUSED(depsgraph),
+ Object *ob,
+ bGPDlayer *gpl,
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps)
+{
+ EnvelopeGpencilModifierData *mmd = (EnvelopeGpencilModifierData *)md;
+ if (mmd->mode != GP_ENVELOPE_DEFORM) {
+ return;
+ }
+ 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,
+ 3,
+ gpl,
+ gps,
+ mmd->flag & GP_ENVELOPE_INVERT_LAYER,
+ mmd->flag & GP_ENVELOPE_INVERT_PASS,
+ mmd->flag & GP_ENVELOPE_INVERT_LAYERPASS,
+ mmd->flag & GP_ENVELOPE_INVERT_MATERIAL)) {
+ return;
+ }
+
+ if (mmd->spread <= 0) {
+ return;
+ }
+
+ apply_stroke_envelope(
+ gps, mmd->spread, def_nr, (mmd->flag & GP_ENVELOPE_INVERT_VGROUP) != 0, mmd->thickness);
+}
+
+static void add_stroke(Object *ob,
+ bGPDstroke *gps,
+ const int point_index,
+ const int connection_index,
+ const int size,
+ const int mat_nr,
+ const float thickness,
+ const float strength,
+ ListBase *results)
+{
+ bGPdata *gpd = ob->data;
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_new(mat_nr, size, gps->thickness);
+
+ const int size1 = size == 4 ? 2 : 1;
+ const int size2 = size - size1;
+
+ memcpy(&gps_dst->points[0], &gps->points[connection_index], size1 * sizeof(bGPDspoint));
+ memcpy(&gps_dst->points[size1], &gps->points[point_index], size2 * sizeof(bGPDspoint));
+
+ for (int i = 0; i < size; i++) {
+ gps_dst->points[i].pressure *= thickness;
+ gps_dst->points[i].strength *= strength;
+ memset(&gps_dst->points[i].runtime, 0, sizeof(bGPDspoint_Runtime));
+ }
+
+ if (gps->dvert != NULL) {
+ gps_dst->dvert = MEM_malloc_arrayN(size, sizeof(MDeformVert), __func__);
+ BKE_defvert_array_copy(&gps_dst->dvert[0], &gps->dvert[connection_index], size1);
+ BKE_defvert_array_copy(&gps_dst->dvert[size1], &gps->dvert[point_index], size2);
+ }
+
+ BLI_addtail(results, gps_dst);
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, gps_dst);
+}
+
+static void add_stroke_cyclic(Object *ob,
+ bGPDstroke *gps,
+ const int point_index,
+ const int connection_index,
+ const int mat_nr,
+ const float thickness,
+ const float strength,
+ ListBase *results)
+{
+ bGPdata *gpd = ob->data;
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_new(mat_nr, 4, gps->thickness);
+
+ int connection_index2 = (connection_index + 1) % gps->totpoints;
+ int point_index2 = (point_index + 1) % gps->totpoints;
+
+ gps_dst->points[0] = gps->points[connection_index];
+ gps_dst->points[1] = gps->points[connection_index2];
+ gps_dst->points[2] = gps->points[point_index];
+ gps_dst->points[3] = gps->points[point_index2];
+ for (int i = 0; i < 4; i++) {
+ gps_dst->points[i].pressure *= thickness;
+ gps_dst->points[i].strength *= strength;
+ memset(&gps_dst->points[i].runtime, 0, sizeof(bGPDspoint_Runtime));
+ }
+
+ if (gps->dvert != NULL) {
+ gps_dst->dvert = MEM_malloc_arrayN(4, sizeof(MDeformVert), __func__);
+ BKE_defvert_array_copy(&gps_dst->dvert[0], &gps->dvert[connection_index], 1);
+ BKE_defvert_array_copy(&gps_dst->dvert[1], &gps->dvert[connection_index2], 1);
+ BKE_defvert_array_copy(&gps_dst->dvert[2], &gps->dvert[point_index], 1);
+ BKE_defvert_array_copy(&gps_dst->dvert[3], &gps->dvert[point_index2], 1);
+ }
+
+ BLI_addtail(results, gps_dst);
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, gps_dst);
+}
+
+static void add_stroke_simple(Object *ob,
+ bGPDstroke *gps,
+ const int point_index,
+ const int connection_index,
+ const int mat_nr,
+ const float thickness,
+ const float strength,
+ ListBase *results)
+{
+ bGPdata *gpd = ob->data;
+ bGPDstroke *gps_dst = BKE_gpencil_stroke_new(mat_nr, 2, gps->thickness);
+
+ gps_dst->points[0] = gps->points[connection_index];
+ gps_dst->points[0].pressure *= thickness;
+ gps_dst->points[0].strength *= strength;
+ memset(&gps_dst->points[0].runtime, 0, sizeof(bGPDspoint_Runtime));
+ gps_dst->points[1] = gps->points[point_index];
+ gps_dst->points[1].pressure *= thickness;
+ gps_dst->points[1].strength *= strength;
+ memset(&gps_dst->points[1].runtime, 0, sizeof(bGPDspoint_Runtime));
+
+ if (gps->dvert != NULL) {
+ gps_dst->dvert = MEM_malloc_arrayN(2, sizeof(MDeformVert), __func__);
+ BKE_defvert_array_copy(&gps_dst->dvert[0], &gps->dvert[connection_index], 1);
+ BKE_defvert_array_copy(&gps_dst->dvert[1], &gps->dvert[point_index], 1);
+ }
+
+ BLI_addtail(results, gps_dst);
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gpd, gps_dst);
+}
+
+static void generate_geometry(GpencilModifierData *md, Object *ob, bGPDlayer *gpl, bGPDframe *gpf)
+{
+ EnvelopeGpencilModifierData *mmd = (EnvelopeGpencilModifierData *)md;
+ ListBase duplicates = {0};
+ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
+ if (!is_stroke_affected_by_modifier(ob,
+ mmd->layername,
+ mmd->material,
+ mmd->pass_index,
+ mmd->layer_pass,
+ 3,
+ gpl,
+ gps,
+ mmd->flag & GP_ENVELOPE_INVERT_LAYER,
+ mmd->flag & GP_ENVELOPE_INVERT_PASS,
+ mmd->flag & GP_ENVELOPE_INVERT_LAYERPASS,
+ mmd->flag & GP_ENVELOPE_INVERT_MATERIAL)) {
+ continue;
+ }
+
+ const int mat_nr = mmd->mat_nr < 0 ? gps->mat_nr : min_ii(mmd->mat_nr, ob->totcol - 1);
+ if (mmd->mode == GP_ENVELOPE_FILLS) {
+ if (gps->flag & GP_STROKE_CYCLIC) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ const int connection_index = (i + mmd->spread) % gps->totpoints;
+ add_stroke_cyclic(
+ ob, gps, i, connection_index, mat_nr, mmd->thickness, mmd->strength, &duplicates);
+ }
+ }
+ else {
+ for (int i = 1; i < gps->totpoints - 1 && i < mmd->spread + 1; i++) {
+ add_stroke(ob, gps, i, 0, 3, mat_nr, mmd->thickness, mmd->strength, &duplicates);
+ }
+ for (int i = 0; i < gps->totpoints - 1; i++) {
+ const int connection_index = min_ii(i + mmd->spread, gps->totpoints - 1);
+ const int size = i == gps->totpoints - 2 ? 2 :
+ connection_index < gps->totpoints - 1 ? 4 :
+ 3;
+ add_stroke(ob,
+ gps,
+ i,
+ connection_index,
+ size,
+ mat_nr,
+ mmd->thickness,
+ mmd->strength,
+ &duplicates);
+ }
+ }
+ BLI_remlink(&gpf->strokes, gps);
+ BKE_gpencil_free_stroke(gps);
+ }
+ else {
+ BLI_assert(mmd->mode == GP_ENVELOPE_SEGMENTS);
+ if (gps->flag & GP_STROKE_CYCLIC) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ const int connection_index = (i + 1 + mmd->spread) % gps->totpoints;
+ add_stroke_simple(
+ ob, gps, i, connection_index, mat_nr, mmd->thickness, mmd->strength, &duplicates);
+ }
+ }
+ else {
+ for (int i = -mmd->spread; i < gps->totpoints - 1; i++) {
+ const int connection_index = min_ii(i + 1 + mmd->spread, gps->totpoints - 1);
+ add_stroke_simple(ob,
+ gps,
+ max_ii(0, i),
+ connection_index,
+ mat_nr,
+ mmd->thickness,
+ mmd->strength,
+ &duplicates);
+ }
+ }
+ }
+ }
+ if (!BLI_listbase_is_empty(&duplicates)) {
+ /* Add strokes to the start of the stroke list to ensure the new lines are drawn underneath the
+ * original line. */
+ BLI_movelisttolist_reverse(&gpf->strokes, &duplicates);
+ }
+}
+
+/**
+ * Apply envelope effect to the strokes.
+ */
+static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob)
+{
+ EnvelopeGpencilModifierData *mmd = (EnvelopeGpencilModifierData *)md;
+ if (mmd->mode == GP_ENVELOPE_DEFORM || mmd->spread <= 0) {
+ return;
+ }
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl);
+ if (gpf == NULL) {
+ continue;
+ }
+ generate_geometry(md, ob, gpl, gpf);
+ }
+}
+
+static void bakeModifier(struct Main *UNUSED(bmain),
+ Depsgraph *depsgraph,
+ GpencilModifierData *md,
+ Object *ob)
+{
+ EnvelopeGpencilModifierData *mmd = (EnvelopeGpencilModifierData *)md;
+ if (mmd->mode == GP_ENVELOPE_DEFORM) {
+ generic_bake_deform_stroke(depsgraph, md, ob, false, deformStroke);
+ }
+ else {
+ bGPdata *gpd = ob->data;
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
+ generate_geometry(md, ob, gpl, gpf);
+ }
+ }
+ }
+}
+
+static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ EnvelopeGpencilModifierData *mmd = (EnvelopeGpencilModifierData *)md;
+
+ walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
+}
+
+static void 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, "mode", 0, NULL, ICON_NONE);
+
+ uiItemR(layout, ptr, "spread", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "thickness", 0, NULL, ICON_NONE);
+
+ const int mode = RNA_enum_get(ptr, "mode");
+ if (mode != GP_ENVELOPE_DEFORM) {
+ uiItemR(layout, ptr, "strength", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mat_nr", 0, NULL, 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_Envelope, panel_draw);
+ gpencil_modifier_subpanel_register(
+ region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type);
+}
+
+GpencilModifierTypeInfo modifierType_Gpencil_Envelope = {
+ /* name */ "Envelope",
+ /* structName */ "EnvelopeGpencilModifierData",
+ /* structSize */ sizeof(EnvelopeGpencilModifierData),
+ /* type */ eGpencilModifierTypeType_Gpencil,
+ /* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
+
+ /* copyData */ copyData,
+
+ /* deformStroke */ deformStroke,
+ /* generateStrokes */ generateStrokes,
+ /* bakeModifier */ bakeModifier,
+ /* remapTime */ NULL,
+
+ /* initData */ initData,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* foreachIDLink */ foreachIDLink,
+ /* foreachTexLink */ NULL,
+ /* panelRegister */ panelRegister,
+};
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index 2f648d7ed4b..c96321b67aa 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -1753,6 +1753,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *obi, LineartRenderBu
obi->original_me,
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
}));
}
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c
index 93a3b33e713..4ea17b25995 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_util.c
@@ -244,4 +244,6 @@ void lineart_count_and_print_render_buffer_memory(LineartRenderBuffer *rb)
total += sum_this;
sum_this = 0;
count_this = 0;
+
+ (void)total; /* Ignored. */
}
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 3ad43ef05af..1840b5447e3 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -2,16 +2,17 @@
# Copyright 2006 Blender Foundation. All rights reserved.
# WITH_OPENGL limits the visibility of the opengl headers to just GPU and bg_gpu,
-# to more easily highlight codepadths in other libraries that need to be refactored,
+# to more easily highlight code-paths in other libraries that need to be refactored,
# bf_gpu is allowed to have opengl regardless of this option.
-if(NOT WITH_OPENGL)
+if(NOT WITH_OPENGL AND NOT WITH_METAL_BACKEND)
add_definitions(-DWITH_OPENGL)
endif()
set(INC
.
intern
+ metal
opengl
../blenkernel
../blenlib
@@ -71,32 +72,13 @@ set(SRC
intern/gpu_shader_interface.cc
intern/gpu_shader_log.cc
intern/gpu_state.cc
+ intern/gpu_storage_buffer.cc
intern/gpu_texture.cc
intern/gpu_uniform_buffer.cc
intern/gpu_vertex_buffer.cc
intern/gpu_vertex_format.cc
intern/gpu_viewport.c
- opengl/gl_backend.cc
- opengl/gl_batch.cc
- opengl/gl_compute.cc
- opengl/gl_context.cc
- opengl/gl_debug.cc
- opengl/gl_debug_layer.cc
- opengl/gl_drawlist.cc
- opengl/gl_framebuffer.cc
- opengl/gl_immediate.cc
- opengl/gl_index_buffer.cc
- opengl/gl_query.cc
- opengl/gl_shader.cc
- opengl/gl_shader_interface.cc
- opengl/gl_shader_log.cc
- opengl/gl_state.cc
- opengl/gl_texture.cc
- opengl/gl_uniform_buffer.cc
- opengl/gl_vertex_array.cc
- opengl/gl_vertex_buffer.cc
-
GPU_batch.h
GPU_batch_presets.h
GPU_batch_utils.h
@@ -122,6 +104,7 @@ set(SRC
GPU_shader.h
GPU_shader_shared.h
GPU_state.h
+ GPU_storage_buffer.h
GPU_texture.h
GPU_uniform_buffer.h
GPU_vertex_buffer.h
@@ -151,10 +134,35 @@ set(SRC
intern/gpu_shader_interface.hh
intern/gpu_shader_private.hh
intern/gpu_state_private.hh
+ intern/gpu_storage_buffer_private.hh
intern/gpu_texture_private.hh
intern/gpu_uniform_buffer_private.hh
intern/gpu_vertex_buffer_private.hh
intern/gpu_vertex_format_private.h
+)
+
+set(OPENGL_SRC
+
+ opengl/gl_backend.cc
+ opengl/gl_batch.cc
+ opengl/gl_compute.cc
+ opengl/gl_context.cc
+ opengl/gl_debug.cc
+ opengl/gl_debug_layer.cc
+ opengl/gl_drawlist.cc
+ opengl/gl_framebuffer.cc
+ opengl/gl_immediate.cc
+ opengl/gl_index_buffer.cc
+ opengl/gl_query.cc
+ opengl/gl_shader.cc
+ opengl/gl_shader_interface.cc
+ opengl/gl_shader_log.cc
+ opengl/gl_state.cc
+ opengl/gl_storage_buffer.cc
+ opengl/gl_texture.cc
+ opengl/gl_uniform_buffer.cc
+ opengl/gl_vertex_array.cc
+ opengl/gl_vertex_buffer.cc
opengl/gl_backend.hh
opengl/gl_batch.hh
@@ -170,12 +178,29 @@ set(SRC
opengl/gl_shader.hh
opengl/gl_shader_interface.hh
opengl/gl_state.hh
+ opengl/gl_storage_buffer.hh
opengl/gl_texture.hh
opengl/gl_uniform_buffer.hh
opengl/gl_vertex_array.hh
opengl/gl_vertex_buffer.hh
)
+set(METAL_SRC
+ metal/mtl_backend.mm
+
+ metal/mtl_backend.hh
+ metal/mtl_capabilities.hh
+)
+
+# Select Backend source based on availability
+if(WITH_OPENGL)
+ list(APPEND SRC ${OPENGL_SRC})
+endif()
+
+if(WITH_METAL_BACKEND)
+ list(APPEND SRC ${METAL_SRC})
+endif()
+
set(LIB
${BLENDER_GL_LIBRARIES}
)
@@ -188,6 +213,7 @@ endif()
set(GLSL_SRC
GPU_shader_shared.h
+ shaders/opengl/glsl_shader_defines.glsl
shaders/gpu_shader_depth_only_frag.glsl
shaders/gpu_shader_uniform_color_frag.glsl
@@ -386,6 +412,8 @@ list(APPEND SRC ${glsl_source_list_file})
list(APPEND INC ${CMAKE_CURRENT_BINARY_DIR})
set(SRC_SHADER_CREATE_INFOS
+ ../draw/engines/gpencil/shaders/infos/gpencil_info.hh
+ ../draw/engines/gpencil/shaders/infos/gpencil_vfx_info.hh
../draw/engines/workbench/shaders/infos/workbench_composite_info.hh
../draw/engines/workbench/shaders/infos/workbench_effect_antialiasing_info.hh
../draw/engines/workbench/shaders/infos/workbench_effect_cavity_info.hh
@@ -398,9 +426,9 @@ set(SRC_SHADER_CREATE_INFOS
../draw/engines/workbench/shaders/infos/workbench_volume_info.hh
../draw/engines/image/shaders/infos/engine_image_info.hh
../draw/intern/shaders/draw_fullscreen_info.hh
+ ../draw/intern/shaders/draw_hair_refine_info.hh
../draw/intern/shaders/draw_object_infos_info.hh
../draw/intern/shaders/draw_view_info.hh
- ../draw/intern/shaders/draw_hair_refine_info.hh
shaders/infos/gpu_clip_planes_info.hh
shaders/infos/gpu_shader_2D_area_borders_info.hh
diff --git a/source/blender/gpu/GPU_capabilities.h b/source/blender/gpu/GPU_capabilities.h
index 672139aa407..0d0542aa528 100644
--- a/source/blender/gpu/GPU_capabilities.h
+++ b/source/blender/gpu/GPU_capabilities.h
@@ -29,6 +29,7 @@ int GPU_max_batch_indices(void);
int GPU_max_batch_vertices(void);
int GPU_max_vertex_attribs(void);
int GPU_max_varying_floats(void);
+int GPU_max_shader_storage_buffer_bindings(void);
int GPU_extensions_len(void);
const char *GPU_extension_get(int i);
diff --git a/source/blender/gpu/GPU_compute.h b/source/blender/gpu/GPU_compute.h
index 437b0223303..6dfd6f73ae8 100644
--- a/source/blender/gpu/GPU_compute.h
+++ b/source/blender/gpu/GPU_compute.h
@@ -9,6 +9,7 @@
#include "BLI_sys_types.h"
#include "GPU_shader.h"
+#include "GPU_storage_buffer.h"
#ifdef __cplusplus
extern "C" {
@@ -19,6 +20,8 @@ void GPU_compute_dispatch(GPUShader *shader,
uint groups_y_len,
uint groups_z_len);
+void GPU_compute_dispatch_indirect(GPUShader *shader, GPUStorageBuf *indirect_buf);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h
index 85433913456..f3b7f8c29bf 100644
--- a/source/blender/gpu/GPU_context.h
+++ b/source/blender/gpu/GPU_context.h
@@ -11,18 +11,15 @@
#include "GPU_batch.h"
#include "GPU_common.h"
+#include "GPU_platform.h"
#ifdef __cplusplus
extern "C" {
#endif
-typedef enum eGPUBackendType {
- GPU_BACKEND_NONE = 0,
- GPU_BACKEND_OPENGL,
-} eGPUBackendType;
-
void GPU_backend_init(eGPUBackendType backend);
void GPU_backend_exit(void);
+bool GPU_backend_supported(eGPUBackendType type);
eGPUBackendType GPU_backend_get_type(void);
@@ -49,6 +46,14 @@ GPUContext *GPU_context_active_get(void);
void GPU_context_main_lock(void);
void GPU_context_main_unlock(void);
+/* GPU Begin/end work blocks */
+void GPU_render_begin(void);
+void GPU_render_end(void);
+
+/* For operations which need to run exactly once per frame -- even if there are no render updates.
+ */
+void GPU_render_step(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/GPU_platform.h b/source/blender/gpu/GPU_platform.h
index d5a0fcfa921..d999216c7ff 100644
--- a/source/blender/gpu/GPU_platform.h
+++ b/source/blender/gpu/GPU_platform.h
@@ -12,6 +12,13 @@
/* GPU platform support */
+typedef enum eGPUBackendType {
+ GPU_BACKEND_NONE = 0,
+ GPU_BACKEND_OPENGL = 1 << 0,
+ GPU_BACKEND_METAL = 1 << 1,
+ GPU_BACKEND_ANY = 0xFFFFFFFFu
+} eGPUBackendType;
+
/* GPU Types */
typedef enum eGPUDeviceType {
GPU_DEVICE_NVIDIA = (1 << 0),
@@ -51,8 +58,13 @@ extern "C" {
#endif
/* GPU Types */
-
+/* TODO: Verify all use-cases of GPU_type_matches to determine which graphics API it should apply
+ * to, and replace with `GPU_type_matches_ex` where appropriate. */
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver);
+bool GPU_type_matches_ex(eGPUDeviceType device,
+ eGPUOSType os,
+ eGPUDriverType driver,
+ eGPUBackendType backend);
eGPUSupportLevel GPU_platform_support_level(void);
const char *GPU_platform_vendor(void);
diff --git a/source/blender/gpu/GPU_storage_buffer.h b/source/blender/gpu/GPU_storage_buffer.h
new file mode 100644
index 00000000000..1478d490e23
--- /dev/null
+++ b/source/blender/gpu/GPU_storage_buffer.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup gpu
+ *
+ * Storage buffers API. Used to handle many way bigger buffers than Uniform buffers update at once.
+ * Make sure that the data structure is compatible with what the implementation expect.
+ * (see "7.8 Shader Buffer Variables and Shader Storage Blocks" from the OpenGL spec for more info
+ * about std430 layout)
+ * Rule of thumb: Padding to 16bytes, don't use vec3.
+ */
+
+#pragma once
+
+#include "GPU_texture.h"
+#include "GPU_vertex_buffer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ListBase;
+
+/** Opaque type hiding blender::gpu::StorageBuf. */
+typedef struct GPUStorageBuf GPUStorageBuf;
+
+GPUStorageBuf *GPU_storagebuf_create_ex(size_t size,
+ const void *data,
+ GPUUsageType usage,
+ const char *name);
+
+#define GPU_storagebuf_create(size) \
+ GPU_storagebuf_create_ex(size, NULL, GPU_USAGE_DYNAMIC, __func__);
+
+void GPU_storagebuf_free(GPUStorageBuf *ssbo);
+
+void GPU_storagebuf_update(GPUStorageBuf *ssbo, const void *data);
+
+void GPU_storagebuf_bind(GPUStorageBuf *ssbo, int slot);
+void GPU_storagebuf_unbind(GPUStorageBuf *ssbo);
+void GPU_storagebuf_unbind_all(void);
+
+void GPU_storagebuf_clear(GPUStorageBuf *ssbo,
+ eGPUTextureFormat internal_format,
+ eGPUDataFormat data_format,
+ void *data);
+void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 734d407d011..37edc2abeb2 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -230,6 +230,7 @@ GPUTexture *GPU_texture_create_error(int dimension, bool array);
* Create an alias of the source texture data.
* If \a src is freed, the texture view will continue to be valid.
* If \a mip_start or \a mip_len is bigger than available mips they will be clamped.
+ * If \a cube_as_array is true, then the texture cube (array) becomes a 2D array texture.
* TODO(@fclem): Target conversion is not implemented yet.
*/
GPUTexture *GPU_texture_create_view(const char *name,
@@ -238,7 +239,8 @@ GPUTexture *GPU_texture_create_view(const char *name,
int mip_start,
int mip_len,
int layer_start,
- int layer_len);
+ int layer_len,
+ bool cube_as_array);
void GPU_texture_update_mipmap(GPUTexture *tex,
int miplvl,
@@ -299,6 +301,11 @@ void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter);
void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter);
void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat, bool use_clamp);
void GPU_texture_swizzle_set(GPUTexture *tex, const char swizzle[4]);
+/**
+ * Set depth stencil texture sampling behavior. Can work on texture views.
+ * If stencil sampling is enabled, an unsigned integer sampler is required.
+ */
+void GPU_texture_stencil_texture_mode_set(GPUTexture *tex, bool use_stencil);
/**
* Return the number of dimensions of the texture ignoring dimension of layers (1, 2 or 3).
@@ -308,6 +315,8 @@ int GPU_texture_dimensions(const GPUTexture *tex);
int GPU_texture_width(const GPUTexture *tex);
int GPU_texture_height(const GPUTexture *tex);
+int GPU_texture_layer_count(const GPUTexture *tex);
+int GPU_texture_mip_count(const GPUTexture *tex);
int GPU_texture_orig_width(const GPUTexture *tex);
int GPU_texture_orig_height(const GPUTexture *tex);
void GPU_texture_orig_size_set(GPUTexture *tex, int w, int h);
diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh
index 2b6e485f152..6e07e6c3229 100644
--- a/source/blender/gpu/intern/gpu_backend.hh
+++ b/source/blender/gpu/intern/gpu_backend.hh
@@ -9,6 +9,8 @@
#pragma once
+#include "GPU_vertex_buffer.h"
+
namespace blender {
namespace gpu {
@@ -22,6 +24,7 @@ class QueryPool;
class Shader;
class Texture;
class UniformBuf;
+class StorageBuf;
class VertBuf;
class GPUBackend {
@@ -32,6 +35,7 @@ class GPUBackend {
virtual void samplers_update() = 0;
virtual void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) = 0;
+ virtual void compute_dispatch_indirect(StorageBuf *indirect_buf) = 0;
virtual Context *context_alloc(void *ghost_window) = 0;
@@ -43,7 +47,14 @@ class GPUBackend {
virtual Shader *shader_alloc(const char *name) = 0;
virtual Texture *texture_alloc(const char *name) = 0;
virtual UniformBuf *uniformbuf_alloc(int size, const char *name) = 0;
+ virtual StorageBuf *storagebuf_alloc(int size, GPUUsageType usage, const char *name) = 0;
virtual VertBuf *vertbuf_alloc() = 0;
+
+ /* Render Frame Coordination --
+ * Used for performing per-frame actions globally */
+ virtual void render_begin() = 0;
+ virtual void render_end() = 0;
+ virtual void render_step() = 0;
};
} // namespace gpu
diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc
index 66e3a71317a..b750dacaca6 100644
--- a/source/blender/gpu/intern/gpu_capabilities.cc
+++ b/source/blender/gpu/intern/gpu_capabilities.cc
@@ -157,6 +157,11 @@ bool GPU_shader_image_load_store_support()
return GCaps.shader_image_load_store_support;
}
+int GPU_max_shader_storage_buffer_bindings()
+{
+ return GCaps.max_shader_storage_buffer_bindings;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh
index 458047ea6ad..4a951eb8458 100644
--- a/source/blender/gpu/intern/gpu_capabilities_private.hh
+++ b/source/blender/gpu/intern/gpu_capabilities_private.hh
@@ -20,11 +20,13 @@ namespace blender::gpu {
*/
struct GPUCapabilities {
int max_texture_size = 0;
+ int max_texture_3d_size = 0;
int max_texture_layers = 0;
int max_textures = 0;
int max_textures_vert = 0;
int max_textures_geom = 0;
int max_textures_frag = 0;
+ int max_samplers = 0;
int max_work_group_count[3] = {0, 0, 0};
int max_work_group_size[3] = {0, 0, 0};
int max_uniforms_vert = 0;
@@ -33,6 +35,7 @@ struct GPUCapabilities {
int max_batch_vertices = 0;
int max_vertex_attribs = 0;
int max_varying_floats = 0;
+ int max_shader_storage_buffer_bindings = 0;
int extensions_len = 0;
const char *(*extension_get)(int);
@@ -40,6 +43,8 @@ struct GPUCapabilities {
bool compute_shader_support = false;
bool shader_storage_buffer_objects_support = false;
bool shader_image_load_store_support = false;
+ bool transform_feedback_support = false;
+
/* OpenGL related workarounds. */
bool mip_render_workaround = false;
bool depth_blitting_workaround = false;
@@ -47,6 +52,10 @@ struct GPUCapabilities {
bool broken_amd_driver = false;
bool use_hq_normals_workaround = false;
/* Vulkan related workarounds. */
+
+ /* Metal related workarounds. */
+ /* Minimum per-vertex stride in bytes (For a vertex buffer). */
+ int minimum_per_vertex_stride = 1;
};
extern GPUCapabilities GCaps;
diff --git a/source/blender/gpu/intern/gpu_compute.cc b/source/blender/gpu/intern/gpu_compute.cc
index e99455b756a..b45cf8211cb 100644
--- a/source/blender/gpu/intern/gpu_compute.cc
+++ b/source/blender/gpu/intern/gpu_compute.cc
@@ -7,10 +7,7 @@
#include "GPU_compute.h"
#include "gpu_backend.hh"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "gpu_storage_buffer_private.hh"
void GPU_compute_dispatch(GPUShader *shader,
uint groups_x_len,
@@ -22,6 +19,12 @@ void GPU_compute_dispatch(GPUShader *shader,
gpu_backend.compute_dispatch(groups_x_len, groups_y_len, groups_z_len);
}
-#ifdef __cplusplus
+void GPU_compute_dispatch_indirect(GPUShader *shader, GPUStorageBuf *indirect_buf_)
+{
+ blender::gpu::GPUBackend &gpu_backend = *blender::gpu::GPUBackend::get();
+ blender::gpu::StorageBuf *indirect_buf = reinterpret_cast<blender::gpu::StorageBuf *>(
+ indirect_buf_);
+
+ GPU_shader_bind(shader);
+ gpu_backend.compute_dispatch_indirect(indirect_buf);
}
-#endif
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index 60e95e09a99..c6eaf7defdc 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -13,7 +13,9 @@
*/
/* TODO: Create cmake option. */
-#define WITH_OPENGL_BACKEND 1
+#if WITH_OPENGL
+# define WITH_OPENGL_BACKEND 1
+#endif
#include "BLI_assert.h"
#include "BLI_utildefines.h"
@@ -32,6 +34,9 @@
# include "gl_backend.hh"
# include "gl_context.hh"
#endif
+#ifdef WITH_METAL_BACKEND
+# include "mtl_backend.hh"
+#endif
#include <mutex>
#include <vector>
@@ -141,21 +146,76 @@ void GPU_context_main_unlock()
/** \} */
/* -------------------------------------------------------------------- */
+/** \name GPU Begin/end work blocks
+ *
+ * Used to explicitly define a per-frame block within which GPU work will happen.
+ * Used for global autoreleasepool flushing in Metal
+ * \{ */
+
+void GPU_render_begin()
+{
+ GPUBackend *backend = GPUBackend::get();
+ BLI_assert(backend);
+ backend->render_begin();
+}
+void GPU_render_end()
+{
+ GPUBackend *backend = GPUBackend::get();
+ BLI_assert(backend);
+ backend->render_end();
+}
+void GPU_render_step()
+{
+ GPUBackend *backend = GPUBackend::get();
+ BLI_assert(backend);
+ backend->render_step();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Backend selection
* \{ */
static GPUBackend *g_backend;
+bool GPU_backend_supported(eGPUBackendType type)
+{
+ switch (type) {
+ case GPU_BACKEND_OPENGL:
+#ifdef WITH_OPENGL_BACKEND
+ return true;
+#else
+ return false;
+#endif
+ case GPU_BACKEND_METAL:
+#ifdef WITH_METAL_BACKEND
+ return MTLBackend::metal_is_supported();
+#else
+ return false;
+#endif
+ default:
+ BLI_assert(false && "No backend specified");
+ return false;
+ }
+}
+
void GPU_backend_init(eGPUBackendType backend_type)
{
BLI_assert(g_backend == nullptr);
+ BLI_assert(GPU_backend_supported(backend_type));
switch (backend_type) {
-#if WITH_OPENGL_BACKEND
+#ifdef WITH_OPENGL_BACKEND
case GPU_BACKEND_OPENGL:
g_backend = new GLBackend;
break;
#endif
+#ifdef WITH_METAL_BACKEND
+ case GPU_BACKEND_METAL:
+ g_backend = new MTLBackend;
+ break;
+#endif
default:
BLI_assert(0);
break;
@@ -172,9 +232,18 @@ void GPU_backend_exit()
eGPUBackendType GPU_backend_get_type()
{
+
+#ifdef WITH_OPENGL_BACKEND
if (g_backend && dynamic_cast<GLBackend *>(g_backend) != nullptr) {
return GPU_BACKEND_OPENGL;
}
+#endif
+
+#ifdef WITH_METAL_BACKEND
+ if (g_backend && dynamic_cast<MTLBackend *>(g_backend) != nullptr) {
+ return GPU_BACKEND_METAL;
+ }
+#endif
return GPU_BACKEND_NONE;
}
diff --git a/source/blender/gpu/intern/gpu_platform.cc b/source/blender/gpu/intern/gpu_platform.cc
index 969a3033c6f..d108dd468a0 100644
--- a/source/blender/gpu/intern/gpu_platform.cc
+++ b/source/blender/gpu/intern/gpu_platform.cc
@@ -65,6 +65,7 @@ void GPUPlatformGlobal::init(eGPUDeviceType gpu_device,
eGPUOSType os_type,
eGPUDriverType driver_type,
eGPUSupportLevel gpu_support_level,
+ eGPUBackendType backend,
const char *vendor_str,
const char *renderer_str,
const char *version_str)
@@ -83,6 +84,7 @@ void GPUPlatformGlobal::init(eGPUDeviceType gpu_device,
this->version = BLI_strdup(version_str);
this->support_key = create_key(gpu_support_level, vendor_str, renderer_str, version_str);
this->gpu_name = create_gpu_name(vendor_str, renderer_str, version_str);
+ this->backend = backend;
}
void GPUPlatformGlobal::clear()
@@ -143,8 +145,17 @@ const char *GPU_platform_gpu_name()
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
{
+ return GPU_type_matches_ex(device, os, driver, GPU_BACKEND_ANY);
+}
+
+bool GPU_type_matches_ex(eGPUDeviceType device,
+ eGPUOSType os,
+ eGPUDriverType driver,
+ eGPUBackendType backend)
+{
BLI_assert(GPG.initialized);
- return (GPG.device & device) && (GPG.os & os) && (GPG.driver & driver);
+ return (GPG.device & device) && (GPG.os & os) && (GPG.driver & driver) &&
+ (GPG.backend & backend);
}
/** \} */
diff --git a/source/blender/gpu/intern/gpu_platform_private.hh b/source/blender/gpu/intern/gpu_platform_private.hh
index a6c400ad319..6e6c24a8662 100644
--- a/source/blender/gpu/intern/gpu_platform_private.hh
+++ b/source/blender/gpu/intern/gpu_platform_private.hh
@@ -23,12 +23,14 @@ class GPUPlatformGlobal {
char *version = nullptr;
char *support_key = nullptr;
char *gpu_name = nullptr;
+ eGPUBackendType backend = GPU_BACKEND_NONE;
public:
void init(eGPUDeviceType gpu_device,
eGPUOSType os_type,
eGPUDriverType driver_type,
eGPUSupportLevel gpu_support_level,
+ eGPUBackendType backend,
const char *vendor_str,
const char *renderer_str,
const char *version_str);
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index ac8e98a4a21..b434cfbbb0e 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -88,6 +88,16 @@ static void standard_defines(Vector<const char *> &sources)
else if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
sources.append("#define OS_UNIX\n");
}
+ /* API Definition */
+ eGPUBackendType backend = GPU_backend_get_type();
+ switch (backend) {
+ case GPU_BACKEND_OPENGL:
+ sources.append("#define GPU_OPENGL\n");
+ break;
+ default:
+ BLI_assert(false && "Invalid GPU Backend Type");
+ break;
+ }
if (GPU_crappy_amd_driver()) {
sources.append("#define GPU_DEPRECATED_AMD_DRIVER\n");
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc
index ec4ff7bc399..aef1984687d 100644
--- a/source/blender/gpu/intern/gpu_shader_create_info.cc
+++ b/source/blender/gpu/intern/gpu_shader_create_info.cc
@@ -62,6 +62,10 @@ void ShaderCreateInfo::finalize()
pass_resources_.extend(info.pass_resources_);
typedef_sources_.extend_non_duplicates(info.typedef_sources_);
+ if (info.early_fragment_test_) {
+ early_fragment_test_ = true;
+ }
+
validate(info);
auto assert_no_overlap = [&](const bool test, const StringRefNull error) {
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh
index da63d372669..9984295457c 100644
--- a/source/blender/gpu/intern/gpu_shader_create_info.hh
+++ b/source/blender/gpu/intern/gpu_shader_create_info.hh
@@ -271,6 +271,8 @@ struct ShaderCreateInfo {
bool finalized_ = false;
/** If true, all resources will have an automatic location assigned. */
bool auto_resource_location_ = false;
+ /** If true, force depth and stencil tests to always happen before fragment shader invocation. */
+ bool early_fragment_test_ = false;
/**
* Maximum length of all the resource names including each null terminator.
* Only for names used by gpu::ShaderInterface.
@@ -522,6 +524,16 @@ struct ShaderCreateInfo {
}
/**
+ * Force fragment tests before fragment shader invocation.
+ * IMPORTANT: This is incompatible with using the gl_FragDepth output.
+ */
+ Self &early_fragment_test(bool enable)
+ {
+ early_fragment_test_ = enable;
+ return *(Self *)this;
+ }
+
+ /**
* Only needed if geometry shader is enabled.
* IMPORTANT: Input and output instance name will have respectively "_in" and "_out" suffix
* appended in the geometry shader IF AND ONLY IF the vertex_out interface instance name matches
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
index 5b7df035acd..2c6845334d3 100644
--- a/source/blender/gpu/intern/gpu_shader_dependency.cc
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -8,6 +8,7 @@
* shader files.
*/
+#include <iomanip>
#include <iostream>
#include "BLI_map.hh"
@@ -136,15 +137,14 @@ struct GPUSource {
int64_t line_end = input.find("\n", offset);
int64_t line_start = input.rfind("\n", offset) + 1;
int64_t char_number = offset - line_start + 1;
- char line_prefix[16] = "";
- SNPRINTF(line_prefix, "%5ld | ", line_number);
/* TODO Use clog. */
std::cout << fullpath << ":" << line_number << ":" << char_number;
std::cout << " error: " << message << "\n";
- std::cout << line_prefix << input.substr(line_start, line_end - line_start) << "\n";
+ std::cout << std::setw(5) << line_number << " | "
+ << input.substr(line_start, line_end - line_start) << "\n";
std::cout << " | ";
for (int64_t i = 0; i < char_number - 1; i++) {
std::cout << " ";
@@ -189,7 +189,7 @@ struct GPUSource {
{
const StringRefNull input = source;
std::string output;
- int64_t cursor = 0;
+ int64_t cursor = -1;
int64_t last_pos = 0;
const bool is_cpp = filename.endswith(".hh");
@@ -204,10 +204,14 @@ struct GPUSource {
}
while (true) {
- cursor = find_keyword(input, "enum ", cursor);
+ cursor = find_keyword(input, "enum ", cursor + 1);
if (cursor == -1) {
break;
}
+ /* Skip matches like `typedef enum myEnum myType;` */
+ if (cursor >= 8 && input.substr(cursor - 8, 8) == "typedef ") {
+ continue;
+ }
/* Output anything between 2 enums blocks. */
output += input.substr(last_pos, cursor - last_pos);
@@ -361,6 +365,7 @@ void gpu_shader_dependency_init()
errors += value->init_dependencies(*g_sources);
}
BLI_assert_msg(errors == 0, "Dependency errors detected: Aborting");
+ UNUSED_VARS_NDEBUG(errors);
}
void gpu_shader_dependency_exit()
diff --git a/source/blender/gpu/intern/gpu_shader_log.cc b/source/blender/gpu/intern/gpu_shader_log.cc
index d67dd56b45b..83fc34a3278 100644
--- a/source/blender/gpu/intern/gpu_shader_log.cc
+++ b/source/blender/gpu/intern/gpu_shader_log.cc
@@ -78,6 +78,9 @@ void Shader::print_log(Span<const char *> sources,
}
#endif
}
+ if (sources_end_line.size() == 0) {
+ sources_end_line.append(0);
+ }
char *log_line = log, *line_end;
diff --git a/source/blender/gpu/intern/gpu_storage_buffer.cc b/source/blender/gpu/intern/gpu_storage_buffer.cc
new file mode 100644
index 00000000000..806acad90fe
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_storage_buffer.cc
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "MEM_guardedalloc.h"
+#include <cstring>
+
+#include "BLI_blenlib.h"
+#include "BLI_math_base.h"
+
+#include "gpu_backend.hh"
+#include "gpu_node_graph.h"
+
+#include "GPU_material.h"
+#include "GPU_vertex_buffer.h" /* For GPUUsageType. */
+
+#include "GPU_storage_buffer.h"
+#include "gpu_storage_buffer_private.hh"
+
+/* -------------------------------------------------------------------- */
+/** \name Creation & Deletion
+ * \{ */
+
+namespace blender::gpu {
+
+StorageBuf::StorageBuf(size_t size, const char *name)
+{
+ /* Make sure that UBO is padded to size of vec4 */
+ BLI_assert((size % 16) == 0);
+
+ size_in_bytes_ = size;
+
+ BLI_strncpy(name_, name, sizeof(name_));
+}
+
+StorageBuf::~StorageBuf()
+{
+ MEM_SAFE_FREE(data_);
+}
+
+} // namespace blender::gpu
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name C-API
+ * \{ */
+
+using namespace blender::gpu;
+
+GPUStorageBuf *GPU_storagebuf_create_ex(size_t size,
+ const void *data,
+ GPUUsageType usage,
+ const char *name)
+{
+ StorageBuf *ssbo = GPUBackend::get()->storagebuf_alloc(size, usage, name);
+ /* Direct init. */
+ if (data != nullptr) {
+ ssbo->update(data);
+ }
+ return wrap(ssbo);
+}
+
+void GPU_storagebuf_free(GPUStorageBuf *ssbo)
+{
+ delete unwrap(ssbo);
+}
+
+void GPU_storagebuf_update(GPUStorageBuf *ssbo, const void *data)
+{
+ unwrap(ssbo)->update(data);
+}
+
+void GPU_storagebuf_bind(GPUStorageBuf *ssbo, int slot)
+{
+ unwrap(ssbo)->bind(slot);
+}
+
+void GPU_storagebuf_unbind(GPUStorageBuf *ssbo)
+{
+ unwrap(ssbo)->unbind();
+}
+
+void GPU_storagebuf_unbind_all()
+{
+ /* FIXME */
+}
+
+void GPU_storagebuf_clear(GPUStorageBuf *ssbo,
+ eGPUTextureFormat internal_format,
+ eGPUDataFormat data_format,
+ void *data)
+{
+ unwrap(ssbo)->clear(internal_format, data_format, data);
+}
+
+void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo)
+{
+ uint32_t data = 0u;
+ GPU_storagebuf_clear(ssbo, GPU_R32UI, GPU_DATA_UINT, &data);
+}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_storage_buffer_private.hh b/source/blender/gpu/intern/gpu_storage_buffer_private.hh
new file mode 100644
index 00000000000..06e7c2c0e9d
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_storage_buffer_private.hh
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#include "BLI_sys_types.h"
+
+struct GPUStorageBuf;
+
+namespace blender {
+namespace gpu {
+
+#ifdef DEBUG
+# define DEBUG_NAME_LEN 64
+#else
+# define DEBUG_NAME_LEN 8
+#endif
+
+/**
+ * Implementation of Storage Buffers.
+ * Base class which is then specialized for each implementation (GL, VK, ...).
+ */
+class StorageBuf {
+ protected:
+ /** Data size in bytes. */
+ size_t size_in_bytes_;
+ /** Continuous memory block to copy to GPU. This data is owned by the StorageBuf. */
+ void *data_ = NULL;
+ /** Debugging name */
+ char name_[DEBUG_NAME_LEN];
+
+ public:
+ StorageBuf(size_t size, const char *name);
+ virtual ~StorageBuf();
+
+ virtual void update(const void *data) = 0;
+ virtual void bind(int slot) = 0;
+ virtual void unbind() = 0;
+ virtual void clear(eGPUTextureFormat internal_format,
+ eGPUDataFormat data_format,
+ void *data) = 0;
+};
+
+/* Syntactic sugar. */
+static inline GPUStorageBuf *wrap(StorageBuf *vert)
+{
+ return reinterpret_cast<GPUStorageBuf *>(vert);
+}
+static inline StorageBuf *unwrap(GPUStorageBuf *vert)
+{
+ return reinterpret_cast<StorageBuf *>(vert);
+}
+static inline const StorageBuf *unwrap(const GPUStorageBuf *vert)
+{
+ return reinterpret_cast<const StorageBuf *>(vert);
+}
+
+#undef DEBUG_NAME_LEN
+
+} // namespace gpu
+} // namespace blender
diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc
index 9e6a6f75391..d78dc845074 100644
--- a/source/blender/gpu/intern/gpu_texture.cc
+++ b/source/blender/gpu/intern/gpu_texture.cc
@@ -136,13 +136,16 @@ bool Texture::init_view(const GPUTexture *src_,
int mip_start,
int mip_len,
int layer_start,
- int layer_len)
+ int layer_len,
+ bool cube_as_array)
{
const Texture *src = unwrap(src_);
w_ = src->w_;
h_ = src->h_;
d_ = src->d_;
- switch (type_) {
+ layer_start = min_ii(layer_start, src->layer_count() - 1);
+ layer_len = min_ii(layer_len, (src->layer_count() - layer_start));
+ switch (src->type_) {
case GPU_TEXTURE_1D_ARRAY:
h_ = layer_len;
break;
@@ -163,6 +166,10 @@ bool Texture::init_view(const GPUTexture *src_,
format_flag_ = to_format_flag(format);
/* For now always copy the target. Target aliasing could be exposed later. */
type_ = src->type_;
+ if (cube_as_array) {
+ BLI_assert(type_ & GPU_TEXTURE_CUBE);
+ type_ = (type_ & ~GPU_TEXTURE_CUBE) | GPU_TEXTURE_2D_ARRAY;
+ }
sampler_state = src->sampler_state;
return this->init_internal(src_, mip_start, layer_start);
}
@@ -385,12 +392,13 @@ GPUTexture *GPU_texture_create_view(const char *name,
int mip_start,
int mip_len,
int layer_start,
- int layer_len)
+ int layer_len,
+ bool cube_as_array)
{
BLI_assert(mip_len > 0);
BLI_assert(layer_len > 0);
Texture *view = GPUBackend::get()->texture_alloc(name);
- view->init_view(src, format, mip_start, mip_len, layer_start, layer_len);
+ view->init_view(src, format, mip_start, mip_len, layer_start, layer_len, cube_as_array);
return wrap(view);
}
@@ -548,6 +556,12 @@ void GPU_texture_swizzle_set(GPUTexture *tex, const char swizzle[4])
reinterpret_cast<Texture *>(tex)->swizzle_set(swizzle);
}
+void GPU_texture_stencil_texture_mode_set(GPUTexture *tex, bool use_stencil)
+{
+ BLI_assert(GPU_texture_stencil(tex) || !use_stencil);
+ reinterpret_cast<Texture *>(tex)->stencil_texture_mode_set(use_stencil);
+}
+
void GPU_texture_free(GPUTexture *tex_)
{
Texture *tex = reinterpret_cast<Texture *>(tex_);
@@ -573,13 +587,13 @@ int GPU_texture_dimensions(const GPUTexture *tex_)
if (type & GPU_TEXTURE_1D) {
return 1;
}
- else if (type & GPU_TEXTURE_2D) {
+ if (type & GPU_TEXTURE_2D) {
return 2;
}
- else if (type & GPU_TEXTURE_3D) {
+ if (type & GPU_TEXTURE_3D) {
return 3;
}
- else if (type & GPU_TEXTURE_CUBE) {
+ if (type & GPU_TEXTURE_CUBE) {
return 2;
}
/* GPU_TEXTURE_BUFFER */
@@ -596,6 +610,16 @@ int GPU_texture_height(const GPUTexture *tex)
return reinterpret_cast<const Texture *>(tex)->height_get();
}
+int GPU_texture_layer_count(const GPUTexture *tex)
+{
+ return reinterpret_cast<const Texture *>(tex)->layer_count();
+}
+
+int GPU_texture_mip_count(const GPUTexture *tex)
+{
+ return reinterpret_cast<const Texture *>(tex)->mip_count();
+}
+
int GPU_texture_orig_width(const GPUTexture *tex)
{
return reinterpret_cast<const Texture *>(tex)->src_w;
diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh
index ec11fab421c..109e60e19a6 100644
--- a/source/blender/gpu/intern/gpu_texture_private.hh
+++ b/source/blender/gpu/intern/gpu_texture_private.hh
@@ -111,12 +111,14 @@ class Texture {
int mip_start,
int mip_len,
int layer_start,
- int layer_len);
+ int layer_len,
+ bool cube_as_array);
virtual void generate_mipmap() = 0;
virtual void copy_to(Texture *tex) = 0;
virtual void clear(eGPUDataFormat format, const void *data) = 0;
virtual void swizzle_set(const char swizzle_mask[4]) = 0;
+ virtual void stencil_texture_mode_set(bool use_stencil) = 0;
virtual void mip_range_set(int min, int max) = 0;
virtual void *read(int mip, eGPUDataFormat format) = 0;
@@ -208,6 +210,11 @@ class Texture {
}
}
+ int mip_count() const
+ {
+ return mipmaps_;
+ }
+
eGPUTextureFormat format_get() const
{
return format_;
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index b5a572bccbe..7bffafd7f9d 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -505,7 +505,9 @@ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
bool display_colorspace,
bool do_overlay_merge)
{
- if (viewport->color_render_tx == NULL) {
+ const int view = 0;
+
+ if (viewport->color_render_tx[view] == NULL) {
return;
}
@@ -527,7 +529,7 @@ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport,
};
gpu_viewport_draw_colormanaged(
- viewport, 0, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge);
+ viewport, view, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge);
/* This one is from the offscreen. Don't free it with the viewport. */
viewport->depth_tx = NULL;
diff --git a/source/blender/gpu/metal/mtl_backend.hh b/source/blender/gpu/metal/mtl_backend.hh
new file mode 100644
index 00000000000..78f638d23f5
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_backend.hh
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#include "BLI_vector.hh"
+
+#include "gpu_backend.hh"
+#include "mtl_capabilities.hh"
+
+namespace blender {
+namespace gpu {
+
+class Batch;
+class DrawList;
+class FrameBuffer;
+class IndexBuf;
+class QueryPool;
+class Shader;
+class Texture;
+class UniformBuf;
+class VertBuf;
+class MTLContext;
+
+class MTLBackend : public GPUBackend {
+ friend class MTLContext;
+
+ public:
+ /* Capabilities. */
+ static MTLCapabilities capabilities;
+
+ inline ~MTLBackend()
+ {
+ MTLBackend::platform_exit();
+ }
+
+ static bool metal_is_supported();
+ inline static MTLBackend *get()
+ {
+ return static_cast<MTLBackend *>(GPUBackend::get());
+ }
+
+ void samplers_update() override;
+ inline void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) override
+ {
+ /* Placeholder */
+ }
+
+ /* MTL Allocators need to be implemented in separate .mm files, due to allocation of Objective-C
+ * objects. */
+ Context *context_alloc(void *ghost_window) override;
+ Batch *batch_alloc() override;
+ DrawList *drawlist_alloc(int list_length) override;
+ FrameBuffer *framebuffer_alloc(const char *name) override;
+ IndexBuf *indexbuf_alloc() override;
+ QueryPool *querypool_alloc() override;
+ Shader *shader_alloc(const char *name) override;
+ Texture *texture_alloc(const char *name) override;
+ UniformBuf *uniformbuf_alloc(int size, const char *name) override;
+ VertBuf *vertbuf_alloc() override;
+
+ /* Render Frame Coordination. */
+ void render_begin() override;
+ void render_end() override;
+ void render_step() override;
+ bool is_inside_render_boundary();
+
+ private:
+ static void platform_init(MTLContext *ctx);
+ static void platform_exit();
+
+ static void capabilities_init(MTLContext *ctx);
+};
+
+} // namespace gpu
+} // namespace blender
diff --git a/source/blender/gpu/metal/mtl_backend.mm b/source/blender/gpu/metal/mtl_backend.mm
new file mode 100644
index 00000000000..e1da371bd0b
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_backend.mm
@@ -0,0 +1,408 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "BKE_global.h"
+
+#include "gpu_backend.hh"
+#include "mtl_backend.hh"
+
+#include "gpu_capabilities_private.hh"
+#include "gpu_platform_private.hh"
+
+#include <Cocoa/Cocoa.h>
+#include <Metal/Metal.h>
+#include <QuartzCore/QuartzCore.h>
+
+namespace blender {
+namespace gpu {
+
+/* Global per-thread AutoReleasePool. */
+thread_local NSAutoreleasePool *g_autoreleasepool = nil;
+thread_local int g_autoreleasepool_depth = 0;
+
+/* -------------------------------------------------------------------- */
+/** \name Metal Backend
+ * \{ */
+
+void MTLBackend::samplers_update(){
+ /* Placeholder -- Handled in MTLContext. */
+};
+
+Context *MTLBackend::context_alloc(void *ghost_window)
+{
+ /* TODO(Metal): Implement MTLContext. */
+ return nullptr;
+};
+
+Batch *MTLBackend::batch_alloc()
+{
+ /* TODO(Metal): Implement MTLBatch. */
+ return nullptr;
+};
+
+DrawList *MTLBackend::drawlist_alloc(int list_length)
+{
+ /* TODO(Metal): Implement MTLDrawList. */
+ return nullptr;
+};
+
+FrameBuffer *MTLBackend::framebuffer_alloc(const char *name)
+{
+ /* TODO(Metal): Implement MTLFrameBuffer. */
+ return nullptr;
+};
+
+IndexBuf *MTLBackend::indexbuf_alloc()
+{
+ /* TODO(Metal): Implement MTLIndexBuf. */
+ return nullptr;
+};
+
+QueryPool *MTLBackend::querypool_alloc()
+{
+ /* TODO(Metal): Implement MTLQueryPool. */
+ return nullptr;
+};
+
+Shader *MTLBackend::shader_alloc(const char *name)
+{
+ /* TODO(Metal): Implement MTLShader. */
+ return nullptr;
+};
+
+Texture *MTLBackend::texture_alloc(const char *name)
+{
+ /* TODO(Metal): Implement MTLTexture. */
+ return nullptr;
+}
+
+UniformBuf *MTLBackend::uniformbuf_alloc(int size, const char *name)
+{
+ /* TODO(Metal): Implement MTLUniformBuf. */
+ return nullptr;
+};
+
+VertBuf *MTLBackend::vertbuf_alloc()
+{
+ /* TODO(Metal): Implement MTLVertBuf. */
+ return nullptr;
+}
+
+void MTLBackend::render_begin()
+{
+ /* All Rendering must occur within a render boundary */
+ /* Track a call-count for nested calls, used to ensure we are inside an
+ * autoreleasepool from all rendering path. */
+ BLI_assert(g_autoreleasepool_depth >= 0);
+
+ if (g_autoreleasepool == nil) {
+ g_autoreleasepool = [[NSAutoreleasePool alloc] init];
+ }
+ g_autoreleasepool_depth++;
+ BLI_assert(g_autoreleasepool_depth > 0);
+}
+
+void MTLBackend::render_end()
+{
+ /* If call-count reaches zero, drain auto release pool.
+ * Ensures temporary objects are freed within a frame's lifetime. */
+ BLI_assert(g_autoreleasepool != nil);
+ g_autoreleasepool_depth--;
+ BLI_assert(g_autoreleasepool_depth >= 0);
+
+ if (g_autoreleasepool_depth == 0) {
+ [g_autoreleasepool drain];
+ g_autoreleasepool = nil;
+ }
+}
+
+void MTLBackend::render_step()
+{
+ /* Placeholder */
+}
+
+bool MTLBackend::is_inside_render_boundary()
+{
+ return (g_autoreleasepool != nil);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Platform
+ * \{ */
+
+/* For Metal, platform_init needs to be called after MTLContext initialization. */
+void MTLBackend::platform_init(MTLContext *ctx)
+{
+ if (GPG.initialized) {
+ return;
+ }
+
+ eGPUDeviceType device = GPU_DEVICE_UNKNOWN;
+ eGPUOSType os = GPU_OS_ANY;
+ eGPUDriverType driver = GPU_DRIVER_ANY;
+ eGPUSupportLevel support_level = GPU_SUPPORT_LEVEL_SUPPORTED;
+
+ BLI_assert(ctx);
+ id<MTLDevice> mtl_device = nil; /*ctx->device; TODO(Metal): Implement MTLContext. */
+ BLI_assert(device);
+
+ NSString *gpu_name = [mtl_device name];
+ const char *vendor = [gpu_name UTF8String];
+ const char *renderer = "Metal API";
+ const char *version = "1.2";
+ printf("METAL API - DETECTED GPU: %s\n", vendor);
+
+ /* macOS is the only supported platform, but check to ensure we are not building with Metal
+ * enablement on another platform. */
+#ifdef _WIN32
+ os = GPU_OS_WIN;
+#elif defined(__APPLE__)
+ os = GPU_OS_MAC;
+#else
+ os = GPU_OS_UNIX;
+#endif
+
+ BLI_assert(os == GPU_OS_MAC && "Platform must be macOS");
+
+ /* Determine Vendor from name. */
+ if (strstr(vendor, "ATI") || strstr(vendor, "AMD")) {
+ device = GPU_DEVICE_ATI;
+ driver = GPU_DRIVER_OFFICIAL;
+ }
+ else if (strstr(vendor, "NVIDIA")) {
+ device = GPU_DEVICE_NVIDIA;
+ driver = GPU_DRIVER_OFFICIAL;
+ }
+ else if (strstr(vendor, "Intel")) {
+ device = GPU_DEVICE_INTEL;
+ driver = GPU_DRIVER_OFFICIAL;
+ }
+ else if (strstr(vendor, "Apple") || strstr(vendor, "APPLE")) {
+ /* Apple Silicon. */
+ device = GPU_DEVICE_APPLE;
+ driver = GPU_DRIVER_OFFICIAL;
+ }
+ else if (strstr(renderer, "Apple Software Renderer")) {
+ device = GPU_DEVICE_SOFTWARE;
+ driver = GPU_DRIVER_SOFTWARE;
+ }
+ else if (strstr(renderer, "llvmpipe") || strstr(renderer, "softpipe")) {
+ device = GPU_DEVICE_SOFTWARE;
+ driver = GPU_DRIVER_SOFTWARE;
+ }
+ else {
+ printf("Warning: Could not find a matching GPU name. Things may not behave as expected.\n");
+ printf("Detected configuration:\n");
+ printf("Vendor: %s\n", vendor);
+ printf("Renderer: %s\n", renderer);
+ }
+
+ GPG.init(device, os, driver, support_level, GPU_BACKEND_METAL, vendor, renderer, version);
+}
+
+void MTLBackend::platform_exit()
+{
+ BLI_assert(GPG.initialized);
+ GPG.clear();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Capabilities
+ * \{ */
+MTLCapabilities MTLBackend::capabilities = {};
+
+static const char *mtl_extensions_get_null(int i)
+{
+ return nullptr;
+}
+
+bool supports_barycentric_whitelist(id<MTLDevice> device)
+{
+ NSString *gpu_name = [device name];
+ BLI_assert([gpu_name length]);
+ const char *vendor = [gpu_name UTF8String];
+
+ /* Verify GPU support. */
+ bool supported_gpu = [device supportsFamily:MTLGPUFamilyMac2];
+ bool should_support_barycentrics = false;
+
+ /* Known good configs. */
+ if (strstr(vendor, "AMD") || strstr(vendor, "Apple") || strstr(vendor, "APPLE")) {
+ should_support_barycentrics = true;
+ }
+
+ /* Explicit support for Intel-based platforms. */
+ if ((strstr(vendor, "Intel") || strstr(vendor, "INTEL"))) {
+ should_support_barycentrics = true;
+ }
+ return supported_gpu && should_support_barycentrics;
+}
+
+bool MTLBackend::metal_is_supported()
+{
+ /* Device compatibility information using Metal Feature-set tables.
+ * See: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf */
+
+ NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
+
+ /* Metal Viewport requires macOS Version 10.15 onwards. */
+ bool supported_os_version = version.majorVersion >= 11 ||
+ (version.majorVersion == 10 ? version.minorVersion >= 15 : false);
+ if (!supported_os_version) {
+ printf(
+ "OS Version too low to run minimum required metal version. Required at least 10.15, got "
+ "%ld.%ld \n",
+ (long)version.majorVersion,
+ (long)version.minorVersion);
+ return false;
+ }
+
+ if (@available(macOS 10.15, *)) {
+ id<MTLDevice> device = MTLCreateSystemDefaultDevice();
+
+ /* Debug: Enable low power GPU with Environment Var: METAL_FORCE_INTEL. */
+ static const char *forceIntelStr = getenv("METAL_FORCE_INTEL");
+ bool forceIntel = forceIntelStr ? (atoi(forceIntelStr) != 0) : false;
+
+ if (forceIntel) {
+ NSArray<id<MTLDevice>> *allDevices = MTLCopyAllDevices();
+ for (id<MTLDevice> _device in allDevices) {
+ if (_device.lowPower) {
+ device = _device;
+ }
+ }
+ }
+
+ /* Metal Viewport requires argument buffer tier-2 support and Barycentric Coordinates.
+ * These are available on most hardware configurations supporting Metal 2.2. */
+ bool supports_argument_buffers_tier2 = ([device argumentBuffersSupport] ==
+ MTLArgumentBuffersTier2);
+ bool supports_barycentrics = [device supportsShaderBarycentricCoordinates] ||
+ supports_barycentric_whitelist(device);
+ bool supported_metal_version = [device supportsFamily:MTLGPUFamilyMac2];
+
+ bool result = supports_argument_buffers_tier2 && supports_barycentrics &&
+ supported_os_version && supported_metal_version;
+
+ if (!supports_argument_buffers_tier2) {
+ printf("[Metal] Device does not support argument buffers tier 2\n");
+ }
+ if (!supports_barycentrics) {
+ printf("[Metal] Device does not support barycentrics coordinates\n");
+ }
+ if (!supported_metal_version) {
+ printf("[Metal] Device does not support metal 2.2 or higher\n");
+ }
+
+ if (result) {
+ printf("Device with name %s supports metal minimum requirements\n",
+ [[device name] UTF8String]);
+ }
+
+ return result;
+ }
+ return false;
+}
+
+void MTLBackend::capabilities_init(MTLContext *ctx)
+{
+ BLI_assert(ctx);
+ id<MTLDevice> device = nil; /*ctx->device TODO(Metal): Implement MTLContext. */
+ BLI_assert(device);
+
+ /* Initialize Capabilities. */
+ MTLBackend::capabilities.supports_argument_buffers_tier2 = ([device argumentBuffersSupport] ==
+ MTLArgumentBuffersTier2);
+ MTLBackend::capabilities.supports_family_mac1 = [device supportsFamily:MTLGPUFamilyMac1];
+ MTLBackend::capabilities.supports_family_mac2 = [device supportsFamily:MTLGPUFamilyMac2];
+ MTLBackend::capabilities.supports_family_mac_catalyst1 = [device
+ supportsFamily:MTLGPUFamilyMacCatalyst1];
+ MTLBackend::capabilities.supports_family_mac_catalyst2 = [device
+ supportsFamily:MTLGPUFamilyMacCatalyst2];
+
+ /* Common Global Capabilities. */
+ GCaps.max_texture_size = ([device supportsFamily:MTLGPUFamilyApple3] ||
+ MTLBackend::capabilities.supports_family_mac1) ?
+ 16384 :
+ 8192;
+ GCaps.max_texture_3d_size = 2048;
+ GCaps.max_texture_layers = 2048;
+ GCaps.max_textures = (MTLBackend::capabilities.supports_family_mac1) ?
+ 128 :
+ (([device supportsFamily:MTLGPUFamilyApple4]) ? 96 : 31);
+ if (GCaps.max_textures <= 32) {
+ BLI_assert(false);
+ }
+ GCaps.max_samplers = (MTLBackend::capabilities.supports_argument_buffers_tier2) ? 1024 : 16;
+
+ GCaps.max_textures_vert = GCaps.max_textures;
+ GCaps.max_textures_geom = 0; /* N/A geometry shaders not supported. */
+ GCaps.max_textures_frag = GCaps.max_textures;
+
+ /* Conservative uniform data limit is 4KB per-stage -- This is the limit of setBytes.
+ * MTLBuffer path is also supported but not as efficient. */
+ GCaps.max_uniforms_vert = 1024;
+ GCaps.max_uniforms_frag = 1024;
+
+ GCaps.max_batch_indices = 1 << 31;
+ GCaps.max_batch_vertices = 1 << 31;
+ GCaps.max_vertex_attribs = 31;
+ GCaps.max_varying_floats = 60;
+
+ /* Feature support */
+ GCaps.mem_stats_support = false;
+ GCaps.shader_image_load_store_support = ([device supportsFamily:MTLGPUFamilyApple3] ||
+ MTLBackend::capabilities.supports_family_mac1 ||
+ MTLBackend::capabilities.supports_family_mac2);
+ GCaps.compute_shader_support = false; /* TODO(Metal): Add compute support. */
+ GCaps.shader_storage_buffer_objects_support =
+ false; /* TODO(Metal): implement Storage Buffer support.*/
+
+ /* Maximum buffer bindings: 31. Consider required slot for uniforms/UBOs/Vertex attributes.
+ * Can use argument buffers if a higher limit is required. */
+ GCaps.max_shader_storage_buffer_bindings = 24;
+
+ if (GCaps.compute_shader_support) {
+ GCaps.max_work_group_count[0] = 65535;
+ GCaps.max_work_group_count[1] = 65535;
+ GCaps.max_work_group_count[2] = 65535;
+
+ /* In Metal, total_thread_count is 512 or 1024, such that
+ * threadgroup `width*height*depth <= total_thread_count` */
+ unsigned int max_threads_per_threadgroup_per_dim =
+ ([device supportsFamily:MTLGPUFamilyApple4] ||
+ MTLBackend::capabilities.supports_family_mac1) ?
+ 1024 :
+ 512;
+ GCaps.max_work_group_size[0] = max_threads_per_threadgroup_per_dim;
+ GCaps.max_work_group_size[1] = max_threads_per_threadgroup_per_dim;
+ GCaps.max_work_group_size[2] = max_threads_per_threadgroup_per_dim;
+ }
+
+ GCaps.transform_feedback_support = true;
+
+ /* OPENGL Related workarounds -- none needed for Metal. */
+ GCaps.extensions_len = 0;
+ GCaps.extension_get = mtl_extensions_get_null;
+ GCaps.mip_render_workaround = false;
+ GCaps.depth_blitting_workaround = false;
+ GCaps.use_main_context_workaround = false;
+ GCaps.broken_amd_driver = false;
+
+ /* Metal related workarounds. */
+ /* Minimum per-vertex stride is 4 bytes in Metal.
+ * A bound vertex buffer must contribute at least 4 bytes per vertex. */
+ GCaps.minimum_per_vertex_stride = 4;
+}
+
+/** \} */
+
+} // gpu
+} // blender
diff --git a/source/blender/gpu/metal/mtl_capabilities.hh b/source/blender/gpu/metal/mtl_capabilities.hh
new file mode 100644
index 00000000000..5563008e87d
--- /dev/null
+++ b/source/blender/gpu/metal/mtl_capabilities.hh
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+namespace blender {
+namespace gpu {
+
+/*** Derived from: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf ***/
+/** Upper Bound/Fixed Limits **/
+
+#define METAL_MAX_TEXTURE_SLOTS 128
+#define METAL_MAX_SAMPLER_SLOTS METAL_MAX_TEXTURE_SLOTS
+#define METAL_MAX_UNIFORM_BUFFER_BINDINGS 31
+#define METAL_MAX_VERTEX_INPUT_ATTRIBUTES 31
+#define METAL_MAX_UNIFORMS_PER_BLOCK 64
+
+/* Context-specific limits -- populated in 'MTLBackend::platform_init' */
+typedef struct MTLCapabilities {
+
+ /* Variable Limits & feature sets. */
+ int max_color_render_targets = 4; /* Minimum = 4 */
+ int buffer_alignment_for_textures = 256; /* Upper bound = 256 bytes */
+ int minimum_buffer_offset_alignment = 256; /* Upper bound = 256 bytes */
+
+ /* Capabilities */
+ bool supports_vertex_amplification = false;
+ bool supports_texture_swizzle = true;
+ bool supports_cubemaps = true;
+ bool supports_layered_rendering = true;
+ bool supports_memory_barriers = false;
+ bool supports_sampler_border_color = false;
+ bool supports_argument_buffers_tier2 = false;
+
+ /* GPU Family */
+ bool supports_family_mac1 = false;
+ bool supports_family_mac2 = false;
+ bool supports_family_mac_catalyst1 = false;
+ bool supports_family_mac_catalyst2 = false;
+
+} MTLCapabilities;
+
+} // namespace gpu
+} // namespace blender
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index f0d7a23ef82..2c9cbdb99d8 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -140,7 +140,7 @@ void GLBackend::platform_init()
}
}
- GPG.init(device, os, driver, support_level, vendor, renderer, version);
+ GPG.init(device, os, driver, support_level, GPU_BACKEND_OPENGL, vendor, renderer, version);
}
void GLBackend::platform_exit()
@@ -418,6 +418,12 @@ static void detect_workarounds()
(strstr(renderer, "HD Graphics 4400") || strstr(renderer, "HD Graphics 4600"))) {
GCaps.shader_storage_buffer_objects_support = false;
}
+
+ /* Metal-related Workarounds. */
+
+ /* Minimum Per-Vertex stride is 1 byte for OpenGL. */
+ GCaps.minimum_per_vertex_stride = 1;
+
} // namespace blender::gpu
/** Internal capabilities. */
@@ -426,6 +432,8 @@ 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;
+GLint GLContext::max_ssbo_binds = 0;
+GLint GLContext::max_ssbo_size = 0;
/** Extensions. */
@@ -442,6 +450,7 @@ bool GLContext::native_barycentric_support = false;
bool GLContext::multi_bind_support = false;
bool GLContext::multi_draw_indirect_support = false;
bool GLContext::shader_draw_parameters_support = false;
+bool GLContext::stencil_texturing_support = false;
bool GLContext::texture_cube_map_array_support = false;
bool GLContext::texture_filter_anisotropic_support = false;
bool GLContext::texture_gather_support = false;
@@ -485,13 +494,17 @@ void GLBackend::capabilities_init()
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &GCaps.max_work_group_size[0]);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &GCaps.max_work_group_size[1]);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &GCaps.max_work_group_size[2]);
+ glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS,
+ &GCaps.max_shader_storage_buffer_bindings);
}
GCaps.shader_storage_buffer_objects_support = GLEW_ARB_shader_storage_buffer_object;
/* GL specific capabilities. */
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &GLContext::max_texture_3d_size);
glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GLContext::max_cubemap_size);
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &GLContext::max_ubo_binds);
+ glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &GLContext::max_ssbo_binds);
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &GLContext::max_ubo_size);
+ glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &GLContext::max_ssbo_size);
GLContext::base_instance_support = GLEW_ARB_base_instance;
GLContext::clear_texture_support = GLEW_ARB_clear_texture;
GLContext::copy_image_support = GLEW_ARB_copy_image;
@@ -505,6 +518,7 @@ void GLBackend::capabilities_init()
GLContext::multi_bind_support = GLEW_ARB_multi_bind;
GLContext::multi_draw_indirect_support = GLEW_ARB_multi_draw_indirect;
GLContext::shader_draw_parameters_support = GLEW_ARB_shader_draw_parameters;
+ GLContext::stencil_texturing_support = GLEW_VERSION_4_3;
GLContext::texture_cube_map_array_support = GLEW_ARB_texture_cube_map_array;
GLContext::texture_filter_anisotropic_support = GLEW_EXT_texture_filter_anisotropic;
GLContext::texture_gather_support = GLEW_ARB_texture_gather;
diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh
index 9d637d7b6af..29249111294 100644
--- a/source/blender/gpu/opengl/gl_backend.hh
+++ b/source/blender/gpu/opengl/gl_backend.hh
@@ -19,6 +19,7 @@
#include "gl_index_buffer.hh"
#include "gl_query.hh"
#include "gl_shader.hh"
+#include "gl_storage_buffer.hh"
#include "gl_texture.hh"
#include "gl_uniform_buffer.hh"
#include "gl_vertex_buffer.hh"
@@ -101,6 +102,11 @@ class GLBackend : public GPUBackend {
return new GLUniformBuf(size, name);
};
+ StorageBuf *storagebuf_alloc(int size, GPUUsageType usage, const char *name) override
+ {
+ return new GLStorageBuf(size, usage, name);
+ };
+
VertBuf *vertbuf_alloc() override
{
return new GLVertBuf();
@@ -117,6 +123,24 @@ class GLBackend : public GPUBackend {
GLCompute::dispatch(groups_x_len, groups_y_len, groups_z_len);
}
+ void compute_dispatch_indirect(StorageBuf *indirect_buf) override
+ {
+ GLContext::get()->state_manager_active_get()->apply_state();
+
+ dynamic_cast<GLStorageBuf *>(indirect_buf)->bind_as(GL_DISPATCH_INDIRECT_BUFFER);
+ /* This barrier needs to be here as it only work on the currently bound indirect buffer. */
+ glMemoryBarrier(GL_DRAW_INDIRECT_BUFFER);
+
+ glDispatchComputeIndirect((GLintptr)0);
+ /* Unbind. */
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
+ }
+
+ /* Render Frame Coordination */
+ void render_begin(void) override{};
+ void render_end(void) override{};
+ void render_step(void) override{};
+
private:
static void platform_init();
static void platform_exit();
diff --git a/source/blender/gpu/opengl/gl_compute.cc b/source/blender/gpu/opengl/gl_compute.cc
index 1913174eaef..2fbf23c227d 100644
--- a/source/blender/gpu/opengl/gl_compute.cc
+++ b/source/blender/gpu/opengl/gl_compute.cc
@@ -16,8 +16,6 @@ void GLCompute::dispatch(int group_x_len, int group_y_len, int group_z_len)
{
GL_CHECK_RESOURCES("Compute");
- GLContext::get()->state_manager->apply_state();
-
glDispatchCompute(group_x_len, group_y_len, group_z_len);
}
diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh
index 369b667cbcc..c333c8a4afd 100644
--- a/source/blender/gpu/opengl/gl_context.hh
+++ b/source/blender/gpu/opengl/gl_context.hh
@@ -45,6 +45,8 @@ class GLContext : public Context {
static GLint max_texture_3d_size;
static GLint max_ubo_size;
static GLint max_ubo_binds;
+ static GLint max_ssbo_size;
+ static GLint max_ssbo_binds;
/** Extensions. */
@@ -61,6 +63,7 @@ class GLContext : public Context {
static bool multi_bind_support;
static bool multi_draw_indirect_support;
static bool shader_draw_parameters_support;
+ static bool stencil_texturing_support;
static bool texture_cube_map_array_support;
static bool texture_filter_anisotropic_support;
static bool texture_gather_support;
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index 256702b60c5..5a55a2e8020 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -24,6 +24,8 @@ using namespace blender;
using namespace blender::gpu;
using namespace blender::gpu::shader;
+extern "C" char datatoc_glsl_shader_defines_glsl[];
+
/* -------------------------------------------------------------------- */
/** \name Creation / Destruction
* \{ */
@@ -174,6 +176,10 @@ static const char *to_string(const eGPUTextureFormat &type)
return "r16f";
case GPU_R16:
return "r16";
+ case GPU_R11F_G11F_B10F:
+ return "r11f_g11f_b10f";
+ case GPU_RGB10_A2:
+ return "rgb10_a2";
default:
return "unknown";
}
@@ -576,6 +582,9 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c
pre_main += " gpu_BaryCoordNoPersp = stable_bary_(gl_BaryCoordNoPerspAMD);\n";
}
}
+ if (info.early_fragment_test_) {
+ ss << "layout(early_fragment_tests) in;\n";
+ }
ss << "\n/* Outputs. */\n";
for (const ShaderCreateInfo::FragOut &output : info.fragment_outputs_) {
ss << "layout(location = " << output.index;
@@ -667,7 +676,7 @@ std::string GLShader::compute_layout_declare(const ShaderCreateInfo &info) const
ss << ", local_size_y = " << info.compute_layout_.local_size_y;
}
if (info.compute_layout_.local_size_z != -1) {
- ss << ", local_size_y = " << info.compute_layout_.local_size_z;
+ ss << ", local_size_z = " << info.compute_layout_.local_size_z;
}
ss << ") in;\n";
ss << "\n";
@@ -753,7 +762,7 @@ bool GLShader::do_geometry_shader_injection(const shader::ShaderCreateInfo *info
static char *glsl_patch_default_get()
{
/** Used for shader patching. Init once. */
- static char patch[1024] = "\0";
+ static char patch[2048] = "\0";
if (patch[0] != '\0') {
return patch;
}
@@ -820,6 +829,9 @@ static char *glsl_patch_default_get()
STR_CONCATF(patch, slen, "#define DFDX_SIGN %1.1f\n", GLContext::derivative_signs[0]);
STR_CONCATF(patch, slen, "#define DFDY_SIGN %1.1f\n", GLContext::derivative_signs[1]);
+ /* GLSL Backend Lib. */
+ STR_CONCAT(patch, slen, datatoc_glsl_shader_defines_glsl);
+
BLI_assert(slen < sizeof(patch));
return patch;
}
@@ -836,6 +848,10 @@ static char *glsl_patch_compute_get()
/* Version need to go first. */
STR_CONCAT(patch, slen, "#version 430\n");
STR_CONCAT(patch, slen, "#extension GL_ARB_compute_shader :enable\n");
+
+ /* Array compat. */
+ STR_CONCAT(patch, slen, "#define array(_type) _type[]\n");
+
BLI_assert(slen < sizeof(patch));
return patch;
}
diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh
index 86281d231a8..9c21d0c6230 100644
--- a/source/blender/gpu/opengl/gl_shader.hh
+++ b/source/blender/gpu/opengl/gl_shader.hh
@@ -72,6 +72,11 @@ class GLShader : public Shader {
/** DEPRECATED: Kept only because of BGL API. */
int program_handle_get() const override;
+ bool is_compute() const
+ {
+ return compute_shader_ != 0;
+ }
+
private:
char *glsl_patch_get(GLenum gl_stage);
diff --git a/source/blender/gpu/opengl/gl_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc
new file mode 100644
index 00000000000..109bb65fcb7
--- /dev/null
+++ b/source/blender/gpu/opengl/gl_storage_buffer.cc
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "BKE_global.h"
+
+#include "BLI_string.h"
+
+#include "gpu_backend.hh"
+#include "gpu_context_private.hh"
+
+#include "gl_backend.hh"
+#include "gl_debug.hh"
+#include "gl_storage_buffer.hh"
+#include "gl_vertex_buffer.hh"
+
+namespace blender::gpu {
+
+/* -------------------------------------------------------------------- */
+/** \name Creation & Deletion
+ * \{ */
+
+GLStorageBuf::GLStorageBuf(size_t size, GPUUsageType usage, const char *name)
+ : StorageBuf(size, name)
+{
+ usage_ = usage;
+ /* Do not create UBO GL buffer here to allow allocation from any thread. */
+ BLI_assert(size <= GLContext::max_ssbo_size);
+}
+
+GLStorageBuf::~GLStorageBuf()
+{
+ GLContext::buf_free(ssbo_id_);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Data upload / update
+ * \{ */
+
+void GLStorageBuf::init()
+{
+ BLI_assert(GLContext::get());
+
+ glGenBuffers(1, &ssbo_id_);
+ glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_);
+ glBufferData(GL_SHADER_STORAGE_BUFFER, size_in_bytes_, nullptr, to_gl(this->usage_));
+
+ debug::object_label(GL_SHADER_STORAGE_BUFFER, ssbo_id_, name_);
+}
+
+void GLStorageBuf::update(const void *data)
+{
+ if (ssbo_id_ == 0) {
+ this->init();
+ }
+ glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_);
+ glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, size_in_bytes_, data);
+ glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Usage
+ * \{ */
+
+void GLStorageBuf::bind(int slot)
+{
+ if (slot >= GLContext::max_ssbo_binds) {
+ fprintf(
+ stderr,
+ "Error: Trying to bind \"%s\" ssbo to slot %d which is above the reported limit of %d.",
+ name_,
+ slot,
+ GLContext::max_ssbo_binds);
+ return;
+ }
+
+ if (ssbo_id_ == 0) {
+ this->init();
+ }
+
+ if (data_ != nullptr) {
+ this->update(data_);
+ MEM_SAFE_FREE(data_);
+ }
+
+ slot_ = slot;
+ glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot_, ssbo_id_);
+
+#ifdef DEBUG
+ BLI_assert(slot < 16);
+ /* TODO */
+ // GLContext::get()->bound_ssbo_slots |= 1 << slot;
+#endif
+}
+
+void GLStorageBuf::bind_as(GLenum target)
+{
+ BLI_assert_msg(ssbo_id_ != 0,
+ "Trying to use storage buf as indirect buffer but buffer was never filled.");
+ glBindBuffer(target, ssbo_id_);
+}
+
+void GLStorageBuf::unbind()
+{
+#ifdef DEBUG
+ /* NOTE: This only unbinds the last bound slot. */
+ glBindBufferBase(GL_SHADER_STORAGE_BUFFER, slot_, 0);
+ /* Hope that the context did not change. */
+ /* TODO */
+ // GLContext::get()->bound_ssbo_slots &= ~(1 << slot_);
+#endif
+ slot_ = 0;
+}
+
+void GLStorageBuf::clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data)
+{
+ if (ssbo_id_ == 0) {
+ this->init();
+ }
+
+ if (GLContext::direct_state_access_support) {
+ glClearNamedBufferData(ssbo_id_,
+ to_gl_internal_format(internal_format),
+ to_gl_data_format(internal_format),
+ to_gl(data_format),
+ data);
+ }
+ else {
+ /* WATCH(@fclem): This should be ok since we only use clear outside of drawing functions. */
+ glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_);
+ glClearBufferData(GL_SHADER_STORAGE_BUFFER,
+ to_gl_internal_format(internal_format),
+ to_gl_data_format(internal_format),
+ to_gl(data_format),
+ data);
+ glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
+ }
+}
+
+/** \} */
+
+} // namespace blender::gpu
diff --git a/source/blender/gpu/opengl/gl_storage_buffer.hh b/source/blender/gpu/opengl/gl_storage_buffer.hh
new file mode 100644
index 00000000000..c808a0bdda1
--- /dev/null
+++ b/source/blender/gpu/opengl/gl_storage_buffer.hh
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#include "MEM_guardedalloc.h"
+
+#include "gpu_storage_buffer_private.hh"
+
+#include "glew-mx.h"
+
+namespace blender {
+namespace gpu {
+
+/**
+ * Implementation of Storage Buffers using OpenGL.
+ */
+class GLStorageBuf : public StorageBuf {
+ private:
+ /** Slot to which this UBO is currently bound. -1 if not bound. */
+ int slot_ = -1;
+ /** OpenGL Object handle. */
+ GLuint ssbo_id_ = 0;
+ /** Usage type. */
+ GPUUsageType usage_;
+
+ public:
+ GLStorageBuf(size_t size, GPUUsageType usage, const char *name);
+ ~GLStorageBuf();
+
+ void update(const void *data) override;
+ void bind(int slot) override;
+ void unbind() override;
+ void clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data) override;
+
+ /* Special internal function to bind SSBOs to indirect argument targets. */
+ void bind_as(GLenum target);
+
+ private:
+ void init();
+
+ MEM_CXX_CLASS_ALLOC_FUNCS("GLStorageBuf");
+};
+
+} // namespace gpu
+} // namespace blender
diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc
index 0a5c7f8e79e..b78e30e8b4c 100644
--- a/source/blender/gpu/opengl/gl_texture.cc
+++ b/source/blender/gpu/opengl/gl_texture.cc
@@ -453,6 +453,19 @@ void GLTexture::swizzle_set(const char swizzle[4])
}
}
+void GLTexture::stencil_texture_mode_set(bool use_stencil)
+{
+ BLI_assert(GLContext::stencil_texturing_support);
+ GLint value = use_stencil ? GL_STENCIL_INDEX : GL_DEPTH_COMPONENT;
+ if (GLContext::direct_state_access_support) {
+ glTextureParameteri(tex_id_, GL_DEPTH_STENCIL_TEXTURE_MODE, value);
+ }
+ else {
+ GLContext::state_manager_active_get()->texture_bind_temp(this);
+ glTexParameteri(target_, GL_DEPTH_STENCIL_TEXTURE_MODE, value);
+ }
+}
+
void GLTexture::mip_range_set(int min, int max)
{
BLI_assert(min <= max && min >= 0 && max <= mipmaps_);
@@ -556,7 +569,7 @@ void GLTexture::samplers_update()
float max_anisotropy = 1.0f;
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy);
- float aniso_filter = max_ff(max_anisotropy, U.anisotropic_filter);
+ float aniso_filter = min_ff(max_anisotropy, U.anisotropic_filter);
for (int i = 0; i <= GPU_SAMPLER_ICON - 1; i++) {
eGPUSamplerState state = static_cast<eGPUSamplerState>(i);
@@ -688,6 +701,11 @@ void GLTexture::check_feedback_loop()
if (GPU_mip_render_workaround()) {
return;
}
+ /* Do not check if using compute shader. */
+ GLShader *sh = dynamic_cast<GLShader *>(Context::get()->shader);
+ if (sh && sh->is_compute()) {
+ return;
+ }
GLFrameBuffer *fb = static_cast<GLFrameBuffer *>(GLContext::get()->active_fb);
for (int i = 0; i < ARRAY_SIZE(fb_); i++) {
if (fb_[i] == fb) {
diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh
index d4d024f5e3e..2dde8d6c86b 100644
--- a/source/blender/gpu/opengl/gl_texture.hh
+++ b/source/blender/gpu/opengl/gl_texture.hh
@@ -57,6 +57,7 @@ class GLTexture : public Texture {
void copy_to(Texture *dst) override;
void clear(eGPUDataFormat format, const void *data) override;
void swizzle_set(const char swizzle_mask[4]) override;
+ void stencil_texture_mode_set(bool use_stencil) override;
void mip_range_set(int min, int max) override;
void *read(int mip, eGPUDataFormat type) override;
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
index 9851e08fe2e..353bf1481da 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
@@ -23,15 +23,15 @@ void main()
/* Use pos to select the right swizzle (instead of gl_VertexID)
* in order to workaround an OSX driver bug. */
- if (pos == vec2(0.0, 0.0)) {
+ if (all(equal(pos, vec2(0.0, 0.0)))) {
rect.xy = rect.xz;
tex.xy = tex.xz;
}
- else if (pos == vec2(0.0, 1.0)) {
+ else if (all(equal(pos, vec2(0.0, 1.0)))) {
rect.xy = rect.xw;
tex.xy = tex.xw;
}
- else if (pos == vec2(1.0, 1.0)) {
+ else if (all(equal(pos, vec2(1.0, 1.0)))) {
rect.xy = rect.yw;
tex.xy = tex.yw;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl
index d9a5aeeef46..903c602c5d6 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_rect_vert.glsl
@@ -15,6 +15,32 @@ void main()
{
vec2 uv;
vec2 co;
+
+#ifdef GPU_METAL
+/* Metal API does not support Triangle fan primitive topology.
+ * When this shader is called using Triangle-Strip, vertex ID's
+ * are in a different order. */
+# define GPU_PRIM_TRI_STRIP
+#endif
+
+#ifdef GPU_PRIM_TRI_STRIP
+ if (gl_VertexID == 0) {
+ co = rect_geom.xw;
+ uv = rect_icon.xw;
+ }
+ else if (gl_VertexID == 1) {
+ co = rect_geom.xy;
+ uv = rect_icon.xy;
+ }
+ else if (gl_VertexID == 2) {
+ co = rect_geom.zw;
+ uv = rect_icon.zw;
+ }
+ else {
+ co = rect_geom.zy;
+ uv = rect_icon.zy;
+ }
+#else
if (gl_VertexID == 0) {
co = rect_geom.xy;
uv = rect_icon.xy;
@@ -31,6 +57,7 @@ void main()
co = rect_geom.zy;
uv = rect_icon.zy;
}
+#endif
gl_Position = ModelViewProjectionMatrix * vec4(co, 0.0f, 1.0f);
texCoord_interp = uv;
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
index 80b93baf20a..3a39cd8b847 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl
@@ -53,7 +53,7 @@ flat out float lineWidth;
noperspective out float butCo;
flat out float discardFac;
-# ifdef OS_MAC
+# if defined(OS_MAC) && defined(GPU_OPENGL)
in float dummy;
# endif
#endif
diff --git a/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl b/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl
index 1b9fd48c77a..59efdd8d538 100644
--- a/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_depth_only_frag.glsl
@@ -1,6 +1,6 @@
void main()
{
- // no color output, only depth (line below is implicit)
+ /* No color output, only depth (line below is implicit). */
// gl_FragDepth = gl_FragCoord.z;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl
index 2314dbbc5d5..d77f073b7de 100644
--- a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl
@@ -32,8 +32,8 @@ void linearrgb_to_srgb(vec4 col_from, out vec4 col_to)
void main()
{
- fragColor = texture(image_texture, texCoord_interp.st);
- vec4 overlay_col = texture(overlays_texture, texCoord_interp.st);
+ fragColor = texture(image_texture, texCoord_interp.xy);
+ vec4 overlay_col = texture(overlays_texture, texCoord_interp.xy);
if (overlay) {
fragColor = clamp(fragColor, 0.0, 1.0);
diff --git a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl
index 4ef3ff1a8d0..617c02ac079 100644
--- a/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_keyframe_shape_vert.glsl
@@ -43,7 +43,7 @@ bool test(int bit)
vec2 line_thresholds(float width)
{
- return vec2(max(0, width - line_falloff), width);
+ return vec2(max(0.0, width - line_falloff), width);
}
void main()
diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
index c339d3cbabb..f958a81b1eb 100644
--- a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
@@ -52,7 +52,7 @@ bool is_inside_box(ivec2 v)
float texture_1D_custom_bilinear_filter(vec2 uv)
{
- vec2 texel_2d = uv * glyph_dim + 0.5;
+ vec2 texel_2d = uv * vec2(glyph_dim) + vec2(0.5);
ivec2 texel_2d_near = ivec2(texel_2d) - 1;
int frag_offset = glyph_offset + texel_2d_near.y * glyph_dim.x + texel_2d_near.x;
@@ -100,7 +100,7 @@ void main()
fragColor.a = texture_1D_custom_bilinear_filter(texCoord_interp);
}
else {
- vec2 texel = 1.0 / glyph_dim;
+ vec2 texel = 1.0 / vec2(glyph_dim);
fragColor.a = 0.0;
if (interp_size == 1) {
diff --git a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
index 5b01fea5266..63d73733c2f 100644
--- a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl
@@ -28,8 +28,9 @@ void main()
vec2 interp_offset = float(interp_size) / abs(pos.zw - pos.xy);
texCoord_interp = mix(-interp_offset, 1.0 + interp_offset, quad);
- vec2 final_pos = mix(
- pos.xy + ivec2(-interp_size, interp_size), pos.zw + ivec2(interp_size, -interp_size), quad);
+ vec2 final_pos = mix(vec2(ivec2(pos.xy) + ivec2(-interp_size, interp_size)),
+ vec2(ivec2(pos.zw) + ivec2(interp_size, -interp_size)),
+ quad);
gl_Position = ModelViewProjectionMatrix * vec4(final_pos, 0.0, 1.0);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl
index f3eae653f95..92762db5ff4 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl
@@ -1,7 +1,10 @@
-void node_light_falloff(
- float strength, float tsmooth, out float quadratic, out float linear, out float constant)
+void node_light_falloff(float strength,
+ float tsmooth,
+ out float quadratic,
+ out float linear,
+ out float falloff_constant)
{
quadratic = strength;
linear = strength;
- constant = strength;
+ falloff_constant = strength;
}
diff --git a/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl b/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl
new file mode 100644
index 00000000000..a5fce2e71c3
--- /dev/null
+++ b/source/blender/gpu/shaders/opengl/glsl_shader_defines.glsl
@@ -0,0 +1,17 @@
+/* Backend Functions. */
+#define select(A, B, mask) mix(A, B, mask)
+
+bool is_zero(vec2 A)
+{
+ return all(equal(A, vec2(0.0)));
+}
+
+bool is_zero(vec3 A)
+{
+ return all(equal(A, vec3(0.0)));
+}
+
+bool is_zero(vec4 A)
+{
+ return all(equal(A, vec4(0.0)));
+}
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index 470dfb01bdd..b9f7dd98073 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -1512,17 +1512,17 @@ static IK_Scene *convert_tree(
iktarget->bldepsgraph = depsgraph;
condata = (bKinematicConstraint *)iktarget->blenderConstraint->data;
pchan = tree->pchan[iktarget->channel];
- unsigned int controltype, bonecnt;
- double bonelen;
+ unsigned int controltype, bone_count;
+ double bone_length;
float mat[4][4];
/* add the end effector
* estimate the average bone length, used to clamp feedback error */
- for (bonecnt = 0, bonelen = 0.0f, a = iktarget->channel; a >= 0;
- a = tree->parent[a], bonecnt++) {
- bonelen += ikscene->blScale * tree->pchan[a]->bone->length;
+ for (bone_count = 0, bone_length = 0.0f, a = iktarget->channel; a >= 0;
+ a = tree->parent[a], bone_count++) {
+ bone_length += ikscene->blScale * tree->pchan[a]->bone->length;
}
- bonelen /= bonecnt;
+ bone_length /= bone_count;
/* store the rest pose of the end effector to compute enforce target */
copy_m4_m4(mat, pchan->bone->arm_mat);
@@ -1567,7 +1567,7 @@ static IK_Scene *convert_tree(
}
}
if (controltype) {
- iktarget->constraint = new iTaSC::CopyPose(controltype, controltype, bonelen);
+ iktarget->constraint = new iTaSC::CopyPose(controltype, controltype, bone_length);
/* set the gain */
if (controltype & iTaSC::CopyPose::CTL_POSITION) {
iktarget->constraint->setControlParameter(
@@ -1599,7 +1599,7 @@ static IK_Scene *convert_tree(
}
break;
case CONSTRAINT_IK_DISTANCE:
- iktarget->constraint = new iTaSC::Distance(bonelen);
+ iktarget->constraint = new iTaSC::Distance(bone_length);
iktarget->constraint->setControlParameter(
iTaSC::Distance::ID_DISTANCE, iTaSC::ACT_VALUE, condata->dist);
iktarget->constraint->registerCallback(distance_callback, iktarget);
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index 294aa8bbb9c..e46326467cc 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -57,6 +57,7 @@ set(SRC
IMB_imbuf_types.h
IMB_metadata.h
IMB_moviecache.h
+ IMB_openexr.h
IMB_thumbs.h
intern/IMB_allocimbuf.h
intern/IMB_anim.h
@@ -173,6 +174,19 @@ if(WITH_IMAGE_HDR)
add_definitions(-DWITH_HDR)
endif()
+if(WITH_IMAGE_WEBP)
+ list(APPEND SRC
+ intern/webp.c
+ )
+ list(APPEND INC_SYS
+ ${WEBP_INCLUDE_DIRS}
+ )
+ list(APPEND LIB
+ ${WEBP_LIBRARIES}
+ )
+ add_definitions(-DWITH_WEBP)
+endif()
+
list(APPEND INC
../../../intern/opencolorio
)
diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h
index 785fa2b198a..7cf2c02e657 100644
--- a/source/blender/imbuf/IMB_colormanagement.h
+++ b/source/blender/imbuf/IMB_colormanagement.h
@@ -19,6 +19,7 @@ extern "C" {
struct ColorManagedColorspaceSettings;
struct ColorManagedDisplaySettings;
struct ColorManagedViewSettings;
+struct ColorManagedOutputSettings;
struct ColormanageProcessor;
struct EnumPropertyItem;
struct ImBuf;
@@ -52,6 +53,7 @@ bool IMB_colormanagement_space_is_data(struct ColorSpace *colorspace);
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);
+bool IMB_colormanagement_space_name_is_scene_linear(const char *name);
/**
* Convert a float RGB triplet to the correct luminance weighted average.
@@ -238,23 +240,10 @@ void IMB_colormanagement_imbuf_make_display_space(
* 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,
- bool allocate_result,
- const struct ColorManagedViewSettings *view_settings,
- const struct ColorManagedDisplaySettings *display_settings,
- struct ImageFormatData *image_format_data);
-
-void IMB_colormanagement_buffer_make_display_space(
- float *buffer,
- unsigned char *display_buffer,
- int width,
- int height,
- int channels,
- float dither,
- const struct ColorManagedViewSettings *view_settings,
- const struct ColorManagedDisplaySettings *display_settings);
+struct ImBuf *IMB_colormanagement_imbuf_for_write(struct ImBuf *ibuf,
+ bool save_as_render,
+ bool allocate_result,
+ const struct ImageFormatData *image_format);
/** \} */
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 8929a467670..0390df06052 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -965,13 +965,13 @@ void IMB_stereo3d_write_dimensions(
char mode, bool is_squeezed, size_t width, size_t height, size_t *r_width, size_t *r_height);
void IMB_stereo3d_read_dimensions(
char mode, bool is_squeezed, size_t width, size_t height, size_t *r_width, size_t *r_height);
-int *IMB_stereo3d_from_rect(struct ImageFormatData *im_format,
+int *IMB_stereo3d_from_rect(const struct ImageFormatData *im_format,
size_t x,
size_t y,
size_t channels,
int *rect_left,
int *rect_right);
-float *IMB_stereo3d_from_rectf(struct ImageFormatData *im_format,
+float *IMB_stereo3d_from_rectf(const struct ImageFormatData *im_format,
size_t x,
size_t y,
size_t channels,
@@ -980,13 +980,13 @@ float *IMB_stereo3d_from_rectf(struct ImageFormatData *im_format,
/**
* Left/right are always float.
*/
-struct ImBuf *IMB_stereo3d_ImBuf(struct ImageFormatData *im_format,
+struct ImBuf *IMB_stereo3d_ImBuf(const 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,
+void IMB_ImBufFromStereo3d(const struct Stereo3dFormat *s3d,
struct ImBuf *ibuf_stereo,
struct ImBuf **r_ibuf_left,
struct ImBuf **r_ibuf_right);
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 98b7cc6e87f..934163846e4 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -80,6 +80,9 @@ enum eImbFileType {
#ifdef WITH_DDS
IMB_FTYPE_DDS = 13,
#endif
+#ifdef WITH_WEBP
+ IMB_FTYPE_WEBP = 14,
+#endif
};
/* Only for readability. */
diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/IMB_openexr.h
index f5a2f983b18..32f393fc017 100644
--- a/source/blender/imbuf/intern/openexr/openexr_multi.h
+++ b/source/blender/imbuf/IMB_openexr.h
@@ -2,12 +2,12 @@
* Copyright 2006 Blender Foundation. All rights reserved. */
/** \file
- * \ingroup openexr
+ * \ingroup imbuf
*/
#pragma once
-/* Experiment with more advanced EXR API. */
+/* API for reading and writing multilayer EXR files. */
/* XXX layer+pass name max 64? */
/* This api also supports max 8 channels per pass now. easy to fix! */
@@ -44,12 +44,12 @@ void IMB_exr_add_channel(void *handle,
* Read from file.
*/
bool IMB_exr_begin_read(
- void *handle, const char *filename, int *width, int *height, bool parse_channels);
+ void *handle, const char *filepath, int *width, int *height, 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,
+ const char *filepath,
int width,
int height,
int compress,
@@ -59,7 +59,7 @@ bool IMB_exr_begin_write(void *handle,
* (FSA and Save Buffers).
*/
void IMB_exrtile_begin_write(
- void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley);
+ void *handle, const char *filepath, int mipmap, int width, int height, int tilex, int tiley);
/**
* Still clumsy name handling, layers/channels can be ordered as list in list later.
diff --git a/source/blender/imbuf/intern/IMB_colormanagement_intern.h b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
index 42941ace40b..c89b15480a2 100644
--- a/source/blender/imbuf/intern/IMB_colormanagement_intern.h
+++ b/source/blender/imbuf/intern/IMB_colormanagement_intern.h
@@ -33,6 +33,9 @@ typedef struct ColorSpace {
struct OCIO_ConstCPUProcessorRcPtr *to_scene_linear;
struct OCIO_ConstCPUProcessorRcPtr *from_scene_linear;
+ char (*aliases)[MAX_COLORSPACE_NAME];
+ int num_aliases;
+
bool is_invertible;
bool is_data;
diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h
index 035c5b10c60..31f8b3a9505 100644
--- a/source/blender/imbuf/intern/IMB_filetype.h
+++ b/source/blender/imbuf/intern/IMB_filetype.h
@@ -238,3 +238,16 @@ void imb_loadtiletiff(
bool imb_savetiff(struct ImBuf *ibuf, const char *filepath, int flags);
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Format: TIFF (#IMB_FTYPE_WEBP)
+ * \{ */
+
+bool imb_is_a_webp(const unsigned char *buf, size_t size);
+struct ImBuf *imb_loadwebp(const unsigned char *mem,
+ size_t size,
+ int flags,
+ char colorspace[IM_MAX_SPACE]);
+bool imb_savewebp(struct ImBuf *ibuf, const char *name, int flags);
+
+/** \} */
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 15046ea54e1..193fda01816 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -37,6 +37,7 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_main.h"
#include "RNA_define.h"
@@ -503,7 +504,18 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config)
is_invertible = OCIO_colorSpaceIsInvertible(ocio_colorspace);
is_data = OCIO_colorSpaceIsData(ocio_colorspace);
- colormanage_colorspace_add(name, description, is_invertible, is_data);
+ ColorSpace *colorspace = colormanage_colorspace_add(name, description, is_invertible, is_data);
+
+ colorspace->num_aliases = OCIO_colorSpaceGetNumAliases(ocio_colorspace);
+ if (colorspace->num_aliases > 0) {
+ colorspace->aliases = MEM_callocN(sizeof(*colorspace->aliases) * colorspace->num_aliases,
+ "ColorSpace aliases");
+ for (int i = 0; i < colorspace->num_aliases; i++) {
+ BLI_strncpy(colorspace->aliases[i],
+ OCIO_colorSpaceGetAlias(ocio_colorspace, i),
+ MAX_COLORSPACE_NAME);
+ }
+ }
OCIO_colorSpaceRelease(ocio_colorspace);
}
@@ -586,6 +598,7 @@ static void colormanage_free_config(void)
}
/* free color space itself */
+ MEM_SAFE_FREE(colorspace->aliases);
MEM_freeN(colorspace);
colorspace = colorspace_next;
@@ -1393,6 +1406,12 @@ bool IMB_colormanagement_space_name_is_data(const char *name)
return (colorspace && colorspace->is_data);
}
+bool IMB_colormanagement_space_name_is_scene_linear(const char *name)
+{
+ ColorSpace *colorspace = colormanage_colorspace_get_named(name);
+ return (colorspace && IMB_colormanagement_space_is_scene_linear(colorspace));
+}
+
const float *IMB_colormanagement_get_xyz_to_rgb()
{
return &imbuf_xyz_to_rgb[0][0];
@@ -2430,15 +2449,12 @@ void IMB_colormanagement_imbuf_make_display_space(
ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
bool save_as_render,
bool allocate_result,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
- ImageFormatData *image_format_data)
+ const ImageFormatData *image_format)
{
ImBuf *colormanaged_ibuf = ibuf;
- bool do_colormanagement;
- bool is_movie = BKE_imtype_is_movie(image_format_data->imtype);
- bool requires_linear_float = BKE_imtype_requires_linear_float(image_format_data->imtype);
- bool do_alpha_under = image_format_data->planes != R_IMF_PLANES_RGBA;
+ const bool is_movie = BKE_imtype_is_movie(image_format->imtype);
+ const bool requires_linear_float = BKE_imtype_requires_linear_float(image_format->imtype);
+ const bool do_alpha_under = image_format->planes != R_IMF_PLANES_RGBA;
if (ibuf->rect_float && ibuf->rect &&
(ibuf->userflags & (IB_DISPLAY_BUFFER_INVALID | IB_RECT_INVALID)) != 0) {
@@ -2446,9 +2462,13 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
ibuf->userflags &= ~(IB_RECT_INVALID | IB_DISPLAY_BUFFER_INVALID);
}
- do_colormanagement = save_as_render && (is_movie || !requires_linear_float);
+ const bool do_colormanagement_display = save_as_render && (is_movie || !requires_linear_float);
+ const bool do_colormanagement_linear = save_as_render && requires_linear_float &&
+ image_format->linear_colorspace_settings.name[0] &&
+ !IMB_colormanagement_space_name_is_scene_linear(
+ image_format->linear_colorspace_settings.name);
- if (do_colormanagement || do_alpha_under) {
+ if (do_colormanagement_display || do_colormanagement_linear || do_alpha_under) {
if (allocate_result) {
colormanaged_ibuf = IMB_dupImBuf(ibuf);
}
@@ -2501,15 +2521,16 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
}
}
- if (do_colormanagement) {
+ if (do_colormanagement_display) {
+ /* Color management with display and view transform. */
bool make_byte = false;
/* for proper check whether byte buffer is required by a format or not
* should be pretty safe since this image buffer is supposed to be used for
* saving only and ftype would be overwritten a bit later by BKE_imbuf_write
*/
- colormanaged_ibuf->ftype = BKE_image_imtype_to_ftype(image_format_data->imtype,
- &colormanaged_ibuf->foptions);
+ colormanaged_ibuf->ftype = BKE_imtype_to_ftype(image_format->imtype,
+ &colormanaged_ibuf->foptions);
/* if file format isn't able to handle float buffer itself,
* we need to allocate byte buffer and store color managed
@@ -2523,16 +2544,39 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
}
/* perform color space conversions */
- colormanagement_imbuf_make_display_space(
- colormanaged_ibuf, view_settings, display_settings, make_byte);
+ colormanagement_imbuf_make_display_space(colormanaged_ibuf,
+ &image_format->view_settings,
+ &image_format->display_settings,
+ make_byte);
if (colormanaged_ibuf->rect_float) {
/* float buffer isn't linear anymore,
* image format write callback should check for this flag and assume
* no space conversion should happen if ibuf->float_colorspace != NULL
*/
- colormanaged_ibuf->float_colorspace = display_transform_get_colorspace(view_settings,
- display_settings);
+ colormanaged_ibuf->float_colorspace = display_transform_get_colorspace(
+ &image_format->view_settings, &image_format->display_settings);
+ }
+ }
+ else if (do_colormanagement_linear) {
+ /* Color management transform to another linear color space. */
+ if (!colormanaged_ibuf->rect_float) {
+ IMB_float_from_rect(colormanaged_ibuf);
+ imb_freerectImBuf(colormanaged_ibuf);
+ }
+
+ if (colormanaged_ibuf->rect_float) {
+ const char *from_colorspace = (ibuf->float_colorspace) ? ibuf->float_colorspace->name :
+ global_role_scene_linear;
+ const char *to_colorspace = image_format->linear_colorspace_settings.name;
+
+ IMB_colormanagement_transform(colormanaged_ibuf->rect_float,
+ colormanaged_ibuf->x,
+ colormanaged_ibuf->y,
+ colormanaged_ibuf->channels,
+ from_colorspace,
+ to_colorspace,
+ false);
}
}
@@ -2543,45 +2587,6 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf,
return colormanaged_ibuf;
}
-void IMB_colormanagement_buffer_make_display_space(
- float *buffer,
- unsigned char *display_buffer,
- int width,
- int height,
- int channels,
- float dither,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings)
-{
- ColormanageProcessor *cm_processor;
- size_t float_buffer_size = ((size_t)width) * height * channels * sizeof(float);
- float *display_buffer_float = MEM_mallocN(float_buffer_size, "byte_buffer_make_display_space");
-
- /* TODO(sergey): Convert float directly to byte buffer. */
-
- memcpy(display_buffer_float, buffer, float_buffer_size);
-
- cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings);
-
- processor_transform_apply_threaded(
- NULL, display_buffer_float, width, height, channels, cm_processor, true, false);
-
- IMB_buffer_byte_from_float(display_buffer,
- display_buffer_float,
- channels,
- dither,
- IB_PROFILE_SRGB,
- IB_PROFILE_SRGB,
- true,
- width,
- height,
- width,
- width);
-
- MEM_freeN(display_buffer_float);
- IMB_colormanagement_processor_free(cm_processor);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -3063,6 +3068,12 @@ ColorSpace *colormanage_colorspace_get_named(const char *name)
if (STREQ(colorspace->name, name)) {
return colorspace;
}
+
+ for (int i = 0; i < colorspace->num_aliases; i++) {
+ if (STREQ(colorspace->aliases[i], name)) {
+ return colorspace;
+ }
+ }
}
return NULL;
diff --git a/source/blender/imbuf/intern/dds/Stream.cpp b/source/blender/imbuf/intern/dds/Stream.cpp
index bc7239dbd1b..34f3654aa3f 100644
--- a/source/blender/imbuf/intern/dds/Stream.cpp
+++ b/source/blender/imbuf/intern/dds/Stream.cpp
@@ -12,14 +12,14 @@
static const char *msg_error_seek = "DDS: trying to seek beyond end of stream (corrupt file?)";
static const char *msg_error_read = "DDS: trying to read beyond end of stream (corrupt file?)";
-inline bool is_read_within_bounds(const Stream &mem, unsigned int cnt)
+inline bool is_read_within_bounds(const Stream &mem, unsigned int count)
{
if (mem.pos >= mem.size) {
/* No more data remained in the memory buffer. */
return false;
}
- if (cnt > mem.size - mem.pos) {
+ if (count > mem.size - mem.pos) {
/* Reading past the memory bounds. */
return false;
}
@@ -83,15 +83,15 @@ unsigned int mem_read(Stream &mem, unsigned char &i)
return 1;
}
-unsigned int mem_read(Stream &mem, unsigned char *i, unsigned int cnt)
+unsigned int mem_read(Stream &mem, unsigned char *i, unsigned int count)
{
- if (!is_read_within_bounds(mem, cnt)) {
+ if (!is_read_within_bounds(mem, count)) {
mem.set_failed(msg_error_read);
return 0;
}
- memcpy(i, mem.mem + mem.pos, cnt);
- mem.pos += cnt;
- return cnt;
+ memcpy(i, mem.mem + mem.pos, count);
+ mem.pos += count;
+ return count;
}
void Stream::set_failed(const char *msg)
diff --git a/source/blender/imbuf/intern/dds/Stream.h b/source/blender/imbuf/intern/dds/Stream.h
index 3e17b143629..d90440f47cd 100644
--- a/source/blender/imbuf/intern/dds/Stream.h
+++ b/source/blender/imbuf/intern/dds/Stream.h
@@ -24,4 +24,4 @@ unsigned int mem_read(Stream &mem, unsigned long long &i);
unsigned int mem_read(Stream &mem, unsigned int &i);
unsigned int mem_read(Stream &mem, unsigned short &i);
unsigned int mem_read(Stream &mem, unsigned char &i);
-unsigned int mem_read(Stream &mem, unsigned char *i, unsigned int cnt);
+unsigned int mem_read(Stream &mem, unsigned char *i, unsigned int count);
diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c
index 60442f97885..548bc9e120c 100644
--- a/source/blender/imbuf/intern/filetype.c
+++ b/source/blender/imbuf/intern/filetype.c
@@ -197,6 +197,20 @@ const ImFileType IMB_FILE_TYPES[] = {
.default_save_role = COLOR_ROLE_DEFAULT_FLOAT,
},
#endif
+#ifdef WITH_WEBP
+ {
+ .init = NULL,
+ .exit = NULL,
+ .is_a = imb_is_a_webp,
+ .load = imb_loadwebp,
+ .load_filepath = NULL,
+ .save = imb_savewebp,
+ .load_tile = NULL,
+ .flag = 0,
+ .filetype = IMB_FTYPE_WEBP,
+ .default_save_role = COLOR_ROLE_DEFAULT_BYTE,
+ },
+#endif
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0},
};
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index c1e00642a6d..84bed479577 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -1314,14 +1314,14 @@ static void index_rebuild_fallback(FallbackIndexBuilderContext *context,
short *do_update,
float *progress)
{
- int cnt = IMB_anim_get_duration(context->anim, IMB_TC_NONE);
+ int count = IMB_anim_get_duration(context->anim, IMB_TC_NONE);
int i, pos;
struct anim *anim = context->anim;
- for (pos = 0; pos < cnt; pos++) {
+ for (pos = 0; pos < count; pos++) {
struct ImBuf *ibuf = IMB_anim_absolute(anim, pos, IMB_TC_NONE, IMB_PROXY_NONE);
struct ImBuf *tmp_ibuf = IMB_dupImBuf(ibuf);
- float next_progress = (float)pos / (float)cnt;
+ float next_progress = (float)pos / (float)count;
if (*progress != next_progress) {
*progress = next_progress;
diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c
index 86321d6432c..eb0a2c4a47f 100644
--- a/source/blender/imbuf/intern/iris.c
+++ b/source/blender/imbuf/intern/iris.c
@@ -105,7 +105,7 @@ static int expandrow2(
float *optr, const float *optr_end, const uchar *iptr, const uchar *iptr_end, int z);
static void interleaverow(uchar *lptr, const uchar *cptr, int z, int n);
static void interleaverow2(float *lptr, const uchar *cptr, int z, int n);
-static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int cnt);
+static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int row_len);
static void lumrow(const uchar *rgbptr, uchar *lumptr, int n);
/*
@@ -892,7 +892,7 @@ static void lumrow(const uchar *rgbptr, uchar *lumptr, int n)
}
}
-static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int cnt)
+static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int row_len)
{
uchar *iptr, *ibufend, *sptr, *optr;
short todo, cc;
@@ -900,7 +900,7 @@ static int compressrow(uchar *lbuf, uchar *rlebuf, int z, int cnt)
lbuf += z;
iptr = lbuf;
- ibufend = iptr + cnt * 4;
+ ibufend = iptr + row_len * 4;
optr = rlebuf;
while (iptr < ibufend) {
diff --git a/source/blender/imbuf/intern/openexr/CMakeLists.txt b/source/blender/imbuf/intern/openexr/CMakeLists.txt
index 08b17764d12..c34a97f6837 100644
--- a/source/blender/imbuf/intern/openexr/CMakeLists.txt
+++ b/source/blender/imbuf/intern/openexr/CMakeLists.txt
@@ -17,10 +17,8 @@ set(INC_SYS
)
set(SRC
- openexr_api.h
- openexr_multi.h
-
openexr_api.cpp
+ openexr_api.h
)
set(LIB
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 418a4724c00..9948aaac5da 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -78,6 +78,7 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
}
#include "BLI_blenlib.h"
#include "BLI_math_color.h"
+#include "BLI_string_utils.h"
#include "BLI_threads.h"
#include "BKE_idprop.h"
@@ -89,8 +90,7 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_metadata.h"
-
-#include "openexr_multi.h"
+#include "IMB_openexr.h"
using namespace Imf;
using namespace Imath;
@@ -155,15 +155,15 @@ class IMemStream : public Imf::IStream {
class IFileStream : public Imf::IStream {
public:
- IFileStream(const char *filename) : IStream(filename)
+ IFileStream(const char *filepath) : IStream(filepath)
{
/* utf-8 file path support on windows */
#if defined(WIN32)
- wchar_t *wfilename = alloc_utf16_from_8(filename, 0);
- ifs.open(wfilename, std::ios_base::binary);
- free(wfilename);
+ wchar_t *wfilepath = alloc_utf16_from_8(filepath, 0);
+ ifs.open(wfilepath, std::ios_base::binary);
+ free(wfilepath);
#else
- ifs.open(filename, std::ios_base::binary);
+ ifs.open(filepath, std::ios_base::binary);
#endif
if (!ifs) {
@@ -261,15 +261,15 @@ class OMemStream : public OStream {
class OFileStream : public OStream {
public:
- OFileStream(const char *filename) : OStream(filename)
+ OFileStream(const char *filepath) : OStream(filepath)
{
/* utf-8 file path support on windows */
#if defined(WIN32)
- wchar_t *wfilename = alloc_utf16_from_8(filename, 0);
- ofs.open(wfilename, std::ios_base::binary);
- free(wfilename);
+ wchar_t *wfilepath = alloc_utf16_from_8(filepath, 0);
+ ofs.open(wfilepath, std::ios_base::binary);
+ free(wfilepath);
#else
- ofs.open(filename, std::ios_base::binary);
+ ofs.open(filepath, std::ios_base::binary);
#endif
if (!ofs) {
@@ -834,7 +834,7 @@ void IMB_exr_add_channel(void *handle,
}
bool IMB_exr_begin_write(void *handle,
- const char *filename,
+ const char *filepath,
int width,
int height,
int compress,
@@ -872,7 +872,7 @@ bool IMB_exr_begin_write(void *handle,
/* avoid crash/abort when we don't have permission to write here */
/* manually create ofstream, so we can handle utf-8 filepaths on windows */
try {
- data->ofile_stream = new OFileStream(filename);
+ data->ofile_stream = new OFileStream(filepath);
data->ofile = new OutputFile(*(data->ofile_stream), header);
}
catch (const std::exception &exc) {
@@ -889,7 +889,7 @@ bool IMB_exr_begin_write(void *handle,
}
void IMB_exrtile_begin_write(
- void *handle, const char *filename, int mipmap, int width, int height, int tilex, int tiley)
+ void *handle, const char *filepath, int mipmap, int width, int height, int tilex, int tiley)
{
ExrHandle *data = (ExrHandle *)handle;
Header header(width, height);
@@ -941,7 +941,7 @@ void IMB_exrtile_begin_write(
/* avoid crash/abort when we don't have permission to write here */
/* manually create ofstream, so we can handle utf-8 filepaths on windows */
try {
- data->ofile_stream = new OFileStream(filename);
+ data->ofile_stream = new OFileStream(filepath);
data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), &headers[0], headers.size());
}
catch (const std::exception &) {
@@ -954,19 +954,19 @@ void IMB_exrtile_begin_write(
}
bool IMB_exr_begin_read(
- void *handle, const char *filename, int *width, int *height, const bool parse_channels)
+ void *handle, const char *filepath, int *width, int *height, const bool parse_channels)
{
ExrHandle *data = (ExrHandle *)handle;
ExrChannel *echan;
/* 32 is arbitrary, but zero length files crashes exr. */
- if (!(BLI_exists(filename) && BLI_file_size(filename) > 32)) {
+ if (!(BLI_exists(filepath) && BLI_file_size(filepath) > 32)) {
return false;
}
/* avoid crash/abort when we don't have permission to write here */
try {
- data->ifile_stream = new IFileStream(filename);
+ data->ifile_stream = new IFileStream(filepath);
data->ifile = new MultiPartInputFile(*(data->ifile_stream));
}
catch (const std::exception &) {
diff --git a/source/blender/imbuf/intern/openexr/openexr_stub.cpp b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
index 4ca4a8313b1..f8f204af70c 100644
--- a/source/blender/imbuf/intern/openexr/openexr_stub.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_stub.cpp
@@ -6,7 +6,8 @@
*/
#include "openexr_api.h"
-#include "openexr_multi.h"
+
+#include "IMB_openexr.h"
void *IMB_exr_get_handle(void)
{
@@ -28,7 +29,7 @@ void IMB_exr_add_channel(void * /*handle*/,
}
bool IMB_exr_begin_read(void * /*handle*/,
- const char * /*filename*/,
+ const char * /*filepath*/,
int * /*width*/,
int * /*height*/,
const bool /*add_channels*/)
@@ -36,7 +37,7 @@ bool IMB_exr_begin_read(void * /*handle*/,
return false;
}
bool IMB_exr_begin_write(void * /*handle*/,
- const char * /*filename*/,
+ const char * /*filepath*/,
int /*width*/,
int /*height*/,
int /*compress*/,
@@ -45,7 +46,7 @@ bool IMB_exr_begin_write(void * /*handle*/,
return false;
}
void IMB_exrtile_begin_write(void * /*handle*/,
- const char * /*filename*/,
+ const char * /*filepath*/,
int /*mipmap*/,
int /*width*/,
int /*height*/,
diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c
index 3786f1c5754..aa07edf5c3a 100644
--- a/source/blender/imbuf/intern/radiance_hdr.c
+++ b/source/blender/imbuf/intern/radiance_hdr.c
@@ -308,7 +308,7 @@ struct ImBuf *imb_loadhdr(const unsigned char *mem,
static int fwritecolrs(
FILE *file, int width, int channels, const unsigned char *ibufscan, const float *fpscan)
{
- int beg, c2, cnt = 0;
+ int beg, c2, count = 0;
fCOLOR fcol;
RGBE rgbe, *rgbe_scan;
@@ -347,14 +347,14 @@ static int fwritecolrs(
putc((unsigned char)(width & 255), file);
/* put components separately */
for (size_t i = 0; i < 4; i++) {
- for (size_t j = 0; j < width; j += cnt) { /* find next run */
- for (beg = j; beg < width; beg += cnt) {
- for (cnt = 1; (cnt < 127) && ((beg + cnt) < width) &&
- (rgbe_scan[beg + cnt][i] == rgbe_scan[beg][i]);
- cnt++) {
+ for (size_t j = 0; j < width; j += count) { /* find next run */
+ for (beg = j; beg < width; beg += count) {
+ for (count = 1; (count < 127) && ((beg + count) < width) &&
+ (rgbe_scan[beg + count][i] == rgbe_scan[beg][i]);
+ count++) {
/* pass */
}
- if (cnt >= MINRUN) {
+ if (count >= MINRUN) {
break; /* long enough */
}
}
@@ -378,12 +378,12 @@ static int fwritecolrs(
putc(rgbe_scan[j++][i], file);
}
}
- if (cnt >= MINRUN) { /* write out run */
- putc((unsigned char)(128 + cnt), file);
+ if (count >= MINRUN) { /* write out run */
+ putc((unsigned char)(128 + count), file);
putc(rgbe_scan[beg][i], file);
}
else {
- cnt = 0;
+ count = 0;
}
}
}
diff --git a/source/blender/imbuf/intern/stereoimbuf.c b/source/blender/imbuf/intern/stereoimbuf.c
index c081ffb981a..52756891f21 100644
--- a/source/blender/imbuf/intern/stereoimbuf.c
+++ b/source/blender/imbuf/intern/stereoimbuf.c
@@ -28,8 +28,10 @@
/* prototypes */
struct Stereo3DData;
-static void imb_stereo3d_write_doit(struct Stereo3DData *s3d_data, struct Stereo3dFormat *s3d);
-static void imb_stereo3d_read_doit(struct Stereo3DData *s3d_data, struct Stereo3dFormat *s3d);
+static void imb_stereo3d_write_doit(struct Stereo3DData *s3d_data,
+ const struct Stereo3dFormat *s3d);
+static void imb_stereo3d_read_doit(struct Stereo3DData *s3d_data,
+ const struct Stereo3dFormat *s3d);
typedef struct Stereo3DData {
struct {
@@ -46,7 +48,7 @@ typedef struct Stereo3DData {
/** \name Local Functions
* \{ */
-static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyphType mode)
+static void imb_stereo3d_write_anaglyph(const Stereo3DData *s3d, enum eStereo3dAnaglyphType mode)
{
int x, y;
size_t width = s3d->x;
@@ -144,7 +146,7 @@ static void imb_stereo3d_write_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyp
}
}
-static void imb_stereo3d_write_interlace(Stereo3DData *s3d,
+static void imb_stereo3d_write_interlace(const Stereo3DData *s3d,
enum eStereo3dInterlaceType mode,
const bool swap)
{
@@ -402,7 +404,7 @@ static void imb_stereo3d_write_interlace(Stereo3DData *s3d,
}
/* stereo3d output (s3d->rectf.stereo) is always unsqueezed */
-static void imb_stereo3d_write_sidebyside(Stereo3DData *s3d, const bool crosseyed)
+static void imb_stereo3d_write_sidebyside(const Stereo3DData *s3d, const bool crosseyed)
{
int y;
size_t width = s3d->x;
@@ -450,7 +452,7 @@ static void imb_stereo3d_write_sidebyside(Stereo3DData *s3d, const bool crosseye
}
/* stereo3d output (s3d->rectf.stereo) is always unsqueezed */
-static void imb_stereo3d_write_topbottom(Stereo3DData *s3d)
+static void imb_stereo3d_write_topbottom(const Stereo3DData *s3d)
{
int y;
size_t width = s3d->x;
@@ -565,7 +567,7 @@ void IMB_stereo3d_read_dimensions(const char mode,
* \{ */
static void imb_stereo3d_squeeze_ImBuf(ImBuf *ibuf,
- Stereo3dFormat *s3d,
+ const Stereo3dFormat *s3d,
const size_t x,
const size_t y)
{
@@ -581,7 +583,7 @@ static void imb_stereo3d_squeeze_ImBuf(ImBuf *ibuf,
}
static void imb_stereo3d_unsqueeze_ImBuf(ImBuf *ibuf,
- Stereo3dFormat *s3d,
+ const Stereo3dFormat *s3d,
const size_t x,
const size_t y)
{
@@ -597,7 +599,7 @@ static void imb_stereo3d_unsqueeze_ImBuf(ImBuf *ibuf,
}
static void imb_stereo3d_squeeze_rectf(
- float *rectf, Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels)
+ float *rectf, const Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels)
{
ImBuf *ibuf;
size_t width, height;
@@ -631,7 +633,7 @@ static void imb_stereo3d_squeeze_rectf(
}
static void imb_stereo3d_squeeze_rect(
- int *rect, Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels)
+ int *rect, const Stereo3dFormat *s3d, const size_t x, const size_t y, const size_t channels)
{
ImBuf *ibuf;
size_t width, height;
@@ -693,7 +695,7 @@ static void imb_stereo3d_data_init(Stereo3DData *s3d_data,
s3d_data->rectf.stereo = rectf_stereo;
}
-int *IMB_stereo3d_from_rect(ImageFormatData *im_format,
+int *IMB_stereo3d_from_rect(const ImageFormatData *im_format,
const size_t x,
const size_t y,
const size_t channels,
@@ -717,7 +719,7 @@ int *IMB_stereo3d_from_rect(ImageFormatData *im_format,
return r_rect;
}
-float *IMB_stereo3d_from_rectf(ImageFormatData *im_format,
+float *IMB_stereo3d_from_rectf(const ImageFormatData *im_format,
const size_t x,
const size_t y,
const size_t channels,
@@ -741,7 +743,7 @@ float *IMB_stereo3d_from_rectf(ImageFormatData *im_format,
return r_rectf;
}
-ImBuf *IMB_stereo3d_ImBuf(ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
+ImBuf *IMB_stereo3d_ImBuf(const ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *ibuf_right)
{
ImBuf *ibuf_stereo = NULL;
Stereo3DData s3d_data = {{NULL}};
@@ -776,7 +778,7 @@ ImBuf *IMB_stereo3d_ImBuf(ImageFormatData *im_format, ImBuf *ibuf_left, ImBuf *i
return ibuf_stereo;
}
-static void imb_stereo3d_write_doit(Stereo3DData *s3d_data, Stereo3dFormat *s3d)
+static void imb_stereo3d_write_doit(Stereo3DData *s3d_data, const Stereo3dFormat *s3d)
{
switch (s3d->display_mode) {
case S3D_DISPLAY_ANAGLYPH:
@@ -803,7 +805,7 @@ static void imb_stereo3d_write_doit(Stereo3DData *s3d_data, Stereo3dFormat *s3d)
/** \name Reading Stereo ImBuf's
* \{ */
-static void imb_stereo3d_read_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyphType mode)
+static void imb_stereo3d_read_anaglyph(const Stereo3DData *s3d, enum eStereo3dAnaglyphType mode)
{
int x, y;
size_t width = s3d->x;
@@ -901,7 +903,7 @@ static void imb_stereo3d_read_anaglyph(Stereo3DData *s3d, enum eStereo3dAnaglyph
}
}
-static void imb_stereo3d_read_interlace(Stereo3DData *s3d,
+static void imb_stereo3d_read_interlace(const Stereo3DData *s3d,
enum eStereo3dInterlaceType mode,
const bool swap)
{
@@ -1159,7 +1161,7 @@ static void imb_stereo3d_read_interlace(Stereo3DData *s3d,
}
/* stereo input (s3d->rectf.stereo) is always unsqueezed */
-static void imb_stereo3d_read_sidebyside(Stereo3DData *s3d, const bool crosseyed)
+static void imb_stereo3d_read_sidebyside(const Stereo3DData *s3d, const bool crosseyed)
{
int y;
size_t width = s3d->x;
@@ -1208,7 +1210,7 @@ static void imb_stereo3d_read_sidebyside(Stereo3DData *s3d, const bool crosseyed
}
/* stereo input (s3d->rectf.stereo) is always unsqueezed */
-static void imb_stereo3d_read_topbottom(Stereo3DData *s3d)
+static void imb_stereo3d_read_topbottom(const Stereo3DData *s3d)
{
int y;
size_t width = s3d->x;
@@ -1258,7 +1260,7 @@ static void imb_stereo3d_read_topbottom(Stereo3DData *s3d)
/** \name Preparing To Call The Read Functions
* \{ */
-void IMB_ImBufFromStereo3d(Stereo3dFormat *s3d,
+void IMB_ImBufFromStereo3d(const Stereo3dFormat *s3d,
ImBuf *ibuf_stereo3d,
ImBuf **r_ibuf_left,
ImBuf **r_ibuf_right)
@@ -1337,7 +1339,7 @@ void IMB_ImBufFromStereo3d(Stereo3dFormat *s3d,
*r_ibuf_right = ibuf_right;
}
-static void imb_stereo3d_read_doit(Stereo3DData *s3d_data, Stereo3dFormat *s3d)
+static void imb_stereo3d_read_doit(Stereo3DData *s3d_data, const Stereo3dFormat *s3d)
{
switch (s3d->display_mode) {
case S3D_DISPLAY_ANAGLYPH:
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index 241f1a736f4..45b50c866fe 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -41,12 +41,12 @@
#define UTIL_DEBUG 0
const char *imb_ext_image[] = {
- ".png", ".tga", ".bmp", ".jpg", ".jpeg", ".sgi", ".rgb", ".rgba",
+ ".png", ".tga", ".bmp", ".jpg", ".jpeg", ".sgi", ".rgb", ".rgba",
#ifdef WITH_TIFF
- ".tif", ".tiff", ".tx",
+ ".tif", ".tiff", ".tx",
#endif
#ifdef WITH_OPENJPEG
- ".jp2", ".j2c",
+ ".jp2", ".j2c",
#endif
#ifdef WITH_HDR
".hdr",
@@ -55,13 +55,16 @@ const char *imb_ext_image[] = {
".dds",
#endif
#ifdef WITH_CINEON
- ".dpx", ".cin",
+ ".dpx", ".cin",
#endif
#ifdef WITH_OPENEXR
".exr",
#endif
#ifdef WITH_OPENIMAGEIO
- ".psd", ".pdd", ".psb",
+ ".psd", ".pdd", ".psb",
+#endif
+#ifdef WITH_WEBP
+ ".webp",
#endif
NULL,
};
diff --git a/source/blender/imbuf/intern/webp.c b/source/blender/imbuf/intern/webp.c
new file mode 100644
index 00000000000..19fe2373ea0
--- /dev/null
+++ b/source/blender/imbuf/intern/webp.c
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup imbuf
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <webp/decode.h>
+#include <webp/encode.h>
+
+#include "BLI_fileops.h"
+#include "BLI_utildefines.h"
+
+#include "IMB_colormanagement.h"
+#include "IMB_colormanagement_intern.h"
+#include "IMB_filetype.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "MEM_guardedalloc.h"
+
+bool imb_is_a_webp(const unsigned char *buf, size_t size)
+{
+ if (WebPGetInfo(buf, size, NULL, NULL)) {
+ return true;
+ }
+ return false;
+}
+
+ImBuf *imb_loadwebp(const unsigned char *mem,
+ size_t size,
+ int flags,
+ char colorspace[IM_MAX_SPACE])
+{
+ if (!imb_is_a_webp(mem, size)) {
+ return NULL;
+ }
+
+ colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
+
+ WebPBitstreamFeatures features;
+ if (WebPGetFeatures(mem, size, &features) != VP8_STATUS_OK) {
+ fprintf(stderr, "WebP: Failed to parse features\n");
+ return NULL;
+ }
+
+ const int planes = features.has_alpha ? 32 : 24;
+ ImBuf *ibuf = IMB_allocImBuf(features.width, features.height, planes, 0);
+
+ if (ibuf == NULL) {
+ fprintf(stderr, "WebP: Failed to allocate image memory\n");
+ return NULL;
+ }
+
+ if ((flags & IB_test) == 0) {
+ ibuf->ftype = IMB_FTYPE_WEBP;
+ imb_addrectImBuf(ibuf);
+ /* Flip the image during decoding to match Blender. */
+ unsigned char *last_row = (unsigned char *)(ibuf->rect + (ibuf->y - 1) * ibuf->x);
+ if (WebPDecodeRGBAInto(mem, size, last_row, (size_t)(ibuf->x) * ibuf->y * 4, -4 * ibuf->x) ==
+ NULL) {
+ fprintf(stderr, "WebP: Failed to decode image\n");
+ }
+ }
+
+ return ibuf;
+}
+
+bool imb_savewebp(struct ImBuf *ibuf, const char *name, int UNUSED(flags))
+{
+ const int bytesperpixel = (ibuf->planes + 7) >> 3;
+ unsigned char *encoded_data, *last_row;
+ size_t encoded_data_size;
+
+ if (bytesperpixel == 3) {
+ /* We must convert the ImBuf RGBA buffer to RGB as WebP expects a RGB buffer. */
+ const size_t num_pixels = ibuf->x * ibuf->y;
+ const uint8_t *rgba_rect = (uint8_t *)ibuf->rect;
+ uint8_t *rgb_rect = MEM_mallocN(sizeof(uint8_t) * num_pixels * 3, "webp rgb_rect");
+ for (int i = 0; i < num_pixels; i++) {
+ rgb_rect[i * 3 + 0] = rgba_rect[i * 4 + 0];
+ rgb_rect[i * 3 + 1] = rgba_rect[i * 4 + 1];
+ rgb_rect[i * 3 + 2] = rgba_rect[i * 4 + 2];
+ }
+
+ last_row = (unsigned char *)(rgb_rect + (ibuf->y - 1) * ibuf->x * 3);
+
+ if (ibuf->foptions.quality == 100.0f) {
+ encoded_data_size = WebPEncodeLosslessRGB(
+ last_row, ibuf->x, ibuf->y, -3 * ibuf->x, &encoded_data);
+ }
+ else {
+ encoded_data_size = WebPEncodeRGB(
+ last_row, ibuf->x, ibuf->y, -3 * ibuf->x, ibuf->foptions.quality, &encoded_data);
+ }
+ MEM_freeN(rgb_rect);
+ }
+ else if (bytesperpixel == 4) {
+ last_row = (unsigned char *)(ibuf->rect + (ibuf->y - 1) * ibuf->x);
+
+ if (ibuf->foptions.quality == 100.0f) {
+ encoded_data_size = WebPEncodeLosslessRGBA(
+ last_row, ibuf->x, ibuf->y, -4 * ibuf->x, &encoded_data);
+ }
+ else {
+ encoded_data_size = WebPEncodeRGBA(
+ last_row, ibuf->x, ibuf->y, -4 * ibuf->x, ibuf->foptions.quality, &encoded_data);
+ }
+ }
+ else {
+ fprintf(stderr, "WebP: Unsupported bytes per pixel: %d for file: '%s'\n", bytesperpixel, name);
+ return false;
+ }
+
+ if (encoded_data != NULL) {
+ FILE *fp = BLI_fopen(name, "wb");
+ if (!fp) {
+ free(encoded_data);
+ fprintf(stderr, "WebP: Cannot open file for writing: '%s'\n", name);
+ return false;
+ }
+ fwrite(encoded_data, encoded_data_size, 1, fp);
+ free(encoded_data);
+ fclose(fp);
+ }
+
+ return true;
+}
diff --git a/source/blender/io/alembic/ABC_alembic.h b/source/blender/io/alembic/ABC_alembic.h
index a9ade9b02fa..d0c10bd7f76 100644
--- a/source/blender/io/alembic/ABC_alembic.h
+++ b/source/blender/io/alembic/ABC_alembic.h
@@ -111,7 +111,7 @@ struct Mesh *ABC_read_mesh(struct CacheReader *reader,
bool ABC_mesh_topology_changed(struct CacheReader *reader,
struct Object *ob,
- struct Mesh *existing_mesh,
+ const struct Mesh *existing_mesh,
float time,
const char **err_str);
diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
index 11693eeb4de..bbb196dc383 100644
--- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc
@@ -158,6 +158,7 @@ void ABCGenericMeshWriter::do_write(HierarchyContext &context)
BMeshCreateParams bmesh_create_params{};
BMeshFromMeshParams bmesh_from_mesh_params{};
bmesh_from_mesh_params.calc_face_normal = true;
+ bmesh_from_mesh_params.calc_vert_normal = true;
BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params);
BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, nullptr, nullptr, nullptr);
diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc
index ecb1fa0a752..c413fbf0ff9 100644
--- a/source/blender/io/alembic/intern/abc_customdata.cc
+++ b/source/blender/io/alembic/intern/abc_customdata.cc
@@ -61,7 +61,7 @@ static void get_uvs(const CDStreamConfig &config,
MLoop *mloop = config.mloop;
if (!config.pack_uvs) {
- int cnt = 0;
+ int count = 0;
uvidx.resize(config.totloop);
uvs.resize(config.totloop);
@@ -70,12 +70,12 @@ static void get_uvs(const CDStreamConfig &config,
MPoly &current_poly = polygons[i];
MLoopUV *loopuv = mloopuv_array + current_poly.loopstart + current_poly.totloop;
- for (int j = 0; j < current_poly.totloop; j++, cnt++) {
+ for (int j = 0; j < current_poly.totloop; j++, count++) {
loopuv--;
- uvidx[cnt] = cnt;
- uvs[cnt][0] = loopuv->uv[0];
- uvs[cnt][1] = loopuv->uv[1];
+ uvidx[count] = count;
+ uvs[count][0] = loopuv->uv[0];
+ uvs[count][1] = loopuv->uv[1];
}
}
}
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index 1d00b55ca78..47f4dd2ea5d 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -658,7 +658,7 @@ bool AbcMeshReader::accepts_object_type(
return true;
}
-bool AbcMeshReader::topology_changed(Mesh *existing_mesh, const ISampleSelector &sample_sel)
+bool AbcMeshReader::topology_changed(const Mesh *existing_mesh, const ISampleSelector &sample_sel)
{
IPolyMeshSchema::Sample sample;
try {
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.h b/source/blender/io/alembic/intern/abc_reader_mesh.h
index bc853e3b6e4..f97525297b7 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.h
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.h
@@ -15,8 +15,6 @@ namespace blender::io::alembic {
class AbcMeshReader final : public AbcObjectReader {
Alembic::AbcGeom::IPolyMeshSchema m_schema;
- CDStreamConfig m_mesh_data;
-
public:
AbcMeshReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
@@ -32,7 +30,7 @@ class AbcMeshReader final : public AbcObjectReader {
const char *velocity_name,
float velocity_scale,
const char **err_str) override;
- bool topology_changed(Mesh *existing_mesh,
+ bool topology_changed(const Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel) override;
private:
@@ -49,8 +47,6 @@ class AbcMeshReader final : public AbcObjectReader {
class AbcSubDReader final : public AbcObjectReader {
Alembic::AbcGeom::ISubDSchema m_schema;
- CDStreamConfig m_mesh_data;
-
public:
AbcSubDReader(const Alembic::Abc::IObject &object, ImportSettings &settings);
diff --git a/source/blender/io/alembic/intern/abc_reader_object.cc b/source/blender/io/alembic/intern/abc_reader_object.cc
index 72aec8f4336..dac0890e7c5 100644
--- a/source/blender/io/alembic/intern/abc_reader_object.cc
+++ b/source/blender/io/alembic/intern/abc_reader_object.cc
@@ -140,7 +140,7 @@ struct Mesh *AbcObjectReader::read_mesh(struct Mesh *existing_mesh,
return existing_mesh;
}
-bool AbcObjectReader::topology_changed(Mesh * /*existing_mesh*/,
+bool AbcObjectReader::topology_changed(const Mesh * /*existing_mesh*/,
const Alembic::Abc::ISampleSelector & /*sample_sel*/)
{
/* The default implementation of read_mesh() just returns the original mesh, so never changes the
diff --git a/source/blender/io/alembic/intern/abc_reader_object.h b/source/blender/io/alembic/intern/abc_reader_object.h
index d33eabfbee5..5898d1bd529 100644
--- a/source/blender/io/alembic/intern/abc_reader_object.h
+++ b/source/blender/io/alembic/intern/abc_reader_object.h
@@ -139,7 +139,7 @@ class AbcObjectReader {
const char *velocity_name,
float velocity_scale,
const char **err_str);
- virtual bool topology_changed(Mesh *existing_mesh,
+ virtual bool topology_changed(const Mesh *existing_mesh,
const Alembic::Abc::ISampleSelector &sample_sel);
/** Reads the object matrix and sets up an object transform if animated. */
diff --git a/source/blender/io/alembic/intern/alembic_capi.cc b/source/blender/io/alembic/intern/alembic_capi.cc
index f8267d19d8f..c9c982aad6c 100644
--- a/source/blender/io/alembic/intern/alembic_capi.cc
+++ b/source/blender/io/alembic/intern/alembic_capi.cc
@@ -274,6 +274,7 @@ static std::pair<bool, AbcObjectReader *> visit_object(
children_claiming_this_object += child_claims_this_object ? 1 : 0;
}
BLI_assert(children_claiming_this_object == claiming_child_readers.size());
+ UNUSED_VARS_NDEBUG(children_claiming_this_object);
AbcObjectReader *reader = nullptr;
const MetaData &md = object.getMetaData();
@@ -800,8 +801,11 @@ Mesh *ABC_read_mesh(CacheReader *reader,
existing_mesh, sample_sel, read_flag, velocity_name, velocity_scale, err_str);
}
-bool ABC_mesh_topology_changed(
- CacheReader *reader, Object *ob, Mesh *existing_mesh, const float time, const char **err_str)
+bool ABC_mesh_topology_changed(CacheReader *reader,
+ Object *ob,
+ const Mesh *existing_mesh,
+ const float time,
+ const char **err_str)
{
AbcObjectReader *abc_reader = get_abc_reader(reader, ob, err_str);
if (abc_reader == nullptr) {
diff --git a/source/blender/io/avi/intern/avi_mjpeg.c b/source/blender/io/avi/intern/avi_mjpeg.c
index 53366a7b0e3..fb42274fef2 100644
--- a/source/blender/io/avi/intern/avi_mjpeg.c
+++ b/source/blender/io/avi/intern/avi_mjpeg.c
@@ -525,14 +525,14 @@ static boolean jpegmemsrcmgr_fill_input_buffer(j_decompress_ptr dinfo)
return true;
}
-static void jpegmemsrcmgr_skip_input_data(j_decompress_ptr dinfo, long skipcnt)
+static void jpegmemsrcmgr_skip_input_data(j_decompress_ptr dinfo, long skip_count)
{
- if (dinfo->src->bytes_in_buffer < skipcnt) {
- skipcnt = dinfo->src->bytes_in_buffer;
+ if (dinfo->src->bytes_in_buffer < skip_count) {
+ skip_count = dinfo->src->bytes_in_buffer;
}
- dinfo->src->next_input_byte += skipcnt;
- dinfo->src->bytes_in_buffer -= skipcnt;
+ dinfo->src->next_input_byte += skip_count;
+ dinfo->src->bytes_in_buffer -= skip_count;
}
static void jpegmemsrcmgr_term_source(j_decompress_ptr dinfo)
diff --git a/source/blender/io/collada/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp
index 2c9f16c7624..3b21d423df5 100644
--- a/source/blender/io/collada/GeometryExporter.cpp
+++ b/source/blender/io/collada/GeometryExporter.cpp
@@ -120,7 +120,7 @@ void GeometryExporter::operator()(Object *ob)
/* skip the basis */
kb = kb->next;
for (; kb; kb = kb->next) {
- BKE_keyblock_convert_to_mesh(kb, me);
+ BKE_keyblock_convert_to_mesh(kb, me->mvert, me->totvert);
export_key_mesh(ob, me, kb);
}
}
diff --git a/source/blender/io/collada/ImageExporter.cpp b/source/blender/io/collada/ImageExporter.cpp
index f57c5dd5e53..1223abbaf95 100644
--- a/source/blender/io/collada/ImageExporter.cpp
+++ b/source/blender/io/collada/ImageExporter.cpp
@@ -14,6 +14,7 @@
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
@@ -48,7 +49,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
bool is_dirty = BKE_image_is_dirty(image);
ImageFormatData imageFormat;
- BKE_imbuf_to_image_format(&imageFormat, imbuf);
+ BKE_image_format_from_imbuf(&imageFormat, imbuf);
short image_source = image->source;
bool is_generated = image_source == IMA_SRC_GENERATED;
diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp
index 79ac5be35f8..8d7ada4a600 100644
--- a/source/blender/io/collada/collada_utils.cpp
+++ b/source/blender/io/collada/collada_utils.cpp
@@ -411,6 +411,7 @@ void bc_triangulate_mesh(Mesh *me)
BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_create_params);
BMeshFromMeshParams bm_from_me_params{};
bm_from_me_params.calc_face_normal = true;
+ bm_from_me_params.calc_vert_normal = true;
BM_mesh_bm_from_me(bm, me, &bm_from_me_params);
BM_mesh_triangulate(bm, quad_method, use_beauty, 4, tag_only, nullptr, nullptr, nullptr);
diff --git a/source/blender/io/gpencil/gpencil_io.h b/source/blender/io/gpencil/gpencil_io.h
index 6cd9fe087a6..215891e3e48 100644
--- a/source/blender/io/gpencil/gpencil_io.h
+++ b/source/blender/io/gpencil/gpencil_io.h
@@ -72,11 +72,11 @@ typedef enum eGpencilExportFrame {
/**
* Main export entry point function.
*/
-bool gpencil_io_export(const char *filename, struct GpencilIOParams *iparams);
+bool gpencil_io_export(const char *filepath, struct GpencilIOParams *iparams);
/**
* Main import entry point function.
*/
-bool gpencil_io_import(const char *filename, struct GpencilIOParams *iparams);
+bool gpencil_io_import(const char *filepath, 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 9379e72bdd9..05f1158c57d 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_base.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_base.cc
@@ -174,10 +174,10 @@ void GpencilIO::create_object_list()
});
}
-void GpencilIO::filename_set(const char *filename)
+void GpencilIO::filepath_set(const char *filepath)
{
- BLI_strncpy(filename_, filename, FILE_MAX);
- BLI_path_abs(filename_, BKE_main_blendfile_path(bmain_));
+ BLI_strncpy(filepath_, filepath, FILE_MAX);
+ BLI_path_abs(filepath_, BKE_main_blendfile_path(bmain_));
}
bool GpencilIO::gpencil_3D_point_to_screen_space(const float3 co, float2 &r_co)
diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.hh b/source/blender/io/gpencil/intern/gpencil_io_base.hh
index 96ba49c31b1..a89b723ed6c 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_base.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_base.hh
@@ -40,7 +40,7 @@ class GpencilIO {
bool invert_axis_[2];
float4x4 diff_mat_;
- char filename_[FILE_MAX];
+ char filepath_[FILE_MAX];
/* Used for sorting objects. */
struct ObjectZ {
@@ -94,9 +94,9 @@ class GpencilIO {
void selected_objects_boundbox_get(rctf *boundbox);
/**
* Set file input_text full path.
- * \param filename: Path of the file provided by save dialog.
+ * \param filepath: Path of the file provided by save dialog.
*/
- void filename_set(const char *filename);
+ void filepath_set(const char *filepath);
private:
float avg_opacity_;
diff --git a/source/blender/io/gpencil/intern/gpencil_io_capi.cc b/source/blender/io/gpencil/intern/gpencil_io_capi.cc
index 5acac885a38..84b273bc570 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_capi.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_capi.cc
@@ -161,32 +161,32 @@ static bool gpencil_io_export_frame_svg(GpencilExporterSVG *exporter,
}
#endif
-bool gpencil_io_import(const char *filename, GpencilIOParams *iparams)
+bool gpencil_io_import(const char *filepath, GpencilIOParams *iparams)
{
- GpencilImporterSVG importer = GpencilImporterSVG(filename, iparams);
+ GpencilImporterSVG importer = GpencilImporterSVG(filepath, iparams);
return gpencil_io_import_frame(&importer, *iparams);
}
-bool gpencil_io_export(const char *filename, GpencilIOParams *iparams)
+bool gpencil_io_export(const char *filepath, GpencilIOParams *iparams)
{
Depsgraph *depsgraph_ = CTX_data_depsgraph_pointer(iparams->C);
Scene *scene_ = CTX_data_scene(iparams->C);
Object *ob = CTX_data_active_object(iparams->C);
- UNUSED_VARS(filename, depsgraph_, scene_, ob);
+ UNUSED_VARS(filepath, depsgraph_, scene_, ob);
switch (iparams->mode) {
#ifdef WITH_PUGIXML
case GP_EXPORT_TO_SVG: {
- GpencilExporterSVG exporter = GpencilExporterSVG(filename, iparams);
+ GpencilExporterSVG exporter = GpencilExporterSVG(filepath, iparams);
return gpencil_io_export_frame_svg(&exporter, scene_, iparams, true, true, true);
break;
}
#endif
#ifdef WITH_HARU
case GP_EXPORT_TO_PDF: {
- GpencilExporterPDF exporter = GpencilExporterPDF(filename, iparams);
+ GpencilExporterPDF exporter = GpencilExporterPDF(filepath, iparams);
return gpencil_io_export_pdf(depsgraph_, scene_, ob, &exporter, iparams);
break;
}
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 cc3eab02e07..205ab788e6d 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
@@ -43,10 +43,10 @@ static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no, void *UNU
}
/* Constructor. */
-GpencilExporterPDF::GpencilExporterPDF(const char *filename, const GpencilIOParams *iparams)
+GpencilExporterPDF::GpencilExporterPDF(const char *filepath, const GpencilIOParams *iparams)
: GpencilExporter(iparams)
{
- filename_set(filename);
+ filepath_set(filepath);
invert_axis_[0] = false;
invert_axis_[1] = false;
@@ -78,16 +78,16 @@ bool GpencilExporterPDF::write()
/* TODO: It looks `libharu` does not support unicode. */
#if 0 /* `ifdef WIN32` */
- char filename_cstr[FILE_MAX];
- BLI_strncpy(filename_cstr, filename_, FILE_MAX);
+ char filepath_cstr[FILE_MAX];
+ BLI_strncpy(filepath_cstr, filepath_, FILE_MAX);
- UTF16_ENCODE(filename_cstr);
- std::wstring wstr(filename_cstr_16);
+ UTF16_ENCODE(filepath_cstr);
+ std::wstring wstr(filepath_cstr_16);
res = HPDF_SaveToFile(pdf_, wstr.c_str());
- UTF16_UN_ENCODE(filename_cstr);
+ UTF16_UN_ENCODE(filepath_cstr);
#else
- res = HPDF_SaveToFile(pdf_, filename_);
+ res = HPDF_SaveToFile(pdf_, filepath_);
#endif
return (res == 0) ? true : false;
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 f6b9fe4fec1..bfec6bc506b 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.hh
@@ -21,7 +21,7 @@ namespace blender::io::gpencil {
class GpencilExporterPDF : public GpencilExporter {
public:
- GpencilExporterPDF(const char *filename, const struct GpencilIOParams *iparams);
+ GpencilExporterPDF(const char *filepath, const struct GpencilIOParams *iparams);
bool new_document();
bool add_newpage();
bool add_body();
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 f8d30546e39..5d33a2806bd 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
@@ -40,10 +40,10 @@
namespace blender ::io ::gpencil {
/* Constructor. */
-GpencilExporterSVG::GpencilExporterSVG(const char *filename, const GpencilIOParams *iparams)
+GpencilExporterSVG::GpencilExporterSVG(const char *filepath, const GpencilIOParams *iparams)
: GpencilExporter(iparams)
{
- filename_set(filename);
+ filepath_set(filepath);
invert_axis_[0] = false;
invert_axis_[1] = true;
@@ -66,16 +66,16 @@ bool GpencilExporterSVG::write()
bool result = true;
/* Support unicode character paths on Windows. */
#ifdef WIN32
- char filename_cstr[FILE_MAX];
- BLI_strncpy(filename_cstr, filename_, FILE_MAX);
+ char filepath_cstr[FILE_MAX];
+ BLI_strncpy(filepath_cstr, filepath_, FILE_MAX);
- UTF16_ENCODE(filename_cstr);
- std::wstring wstr(filename_cstr_16);
+ UTF16_ENCODE(filepath_cstr);
+ std::wstring wstr(filepath_cstr_16);
result = main_doc_.save_file(wstr.c_str());
- UTF16_UN_ENCODE(filename_cstr);
+ UTF16_UN_ENCODE(filepath_cstr);
#else
- result = main_doc_.save_file(filename_);
+ result = main_doc_.save_file(filepath_);
#endif
return result;
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 2e1cc231e68..7bbc2710693 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.hh
@@ -20,7 +20,7 @@ namespace blender::io::gpencil {
class GpencilExporterSVG : public GpencilExporter {
public:
- GpencilExporterSVG(const char *filename, const struct GpencilIOParams *iparams);
+ GpencilExporterSVG(const char *filepath, const struct GpencilIOParams *iparams);
bool add_newpage();
bool add_body();
bool write();
diff --git a/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc
index bad5c7d6401..06460a1beba 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc
@@ -33,17 +33,17 @@ using blender::MutableSpan;
namespace blender::io::gpencil {
/* Constructor. */
-GpencilImporterSVG::GpencilImporterSVG(const char *filename, const GpencilIOParams *iparams)
+GpencilImporterSVG::GpencilImporterSVG(const char *filepath, const GpencilIOParams *iparams)
: GpencilImporter(iparams)
{
- filename_set(filename);
+ filepath_set(filepath);
}
bool GpencilImporterSVG::read()
{
bool result = true;
NSVGimage *svg_data = nullptr;
- svg_data = nsvgParseFromFile(filename_, "mm", 96.0f);
+ svg_data = nsvgParseFromFile(filepath_, "mm", 96.0f);
if (svg_data == nullptr) {
std::cout << " Could not open SVG.\n ";
return false;
diff --git a/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh b/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh
index f1f4e9a6290..d868e672567 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh
+++ b/source/blender/io/gpencil/intern/gpencil_io_import_svg.hh
@@ -21,7 +21,7 @@ namespace blender::io::gpencil {
class GpencilImporterSVG : public GpencilImporter {
public:
- GpencilImporterSVG(const char *filename, const struct GpencilIOParams *iparams);
+ GpencilImporterSVG(const char *filepath, const struct GpencilIOParams *iparams);
bool read();
diff --git a/source/blender/io/usd/intern/usd_capi_import.cc b/source/blender/io/usd/intern/usd_capi_import.cc
index 49d5251198a..e5083700d7d 100644
--- a/source/blender/io/usd/intern/usd_capi_import.cc
+++ b/source/blender/io/usd/intern/usd_capi_import.cc
@@ -391,7 +391,7 @@ bool USD_import(struct bContext *C,
else {
/* Fake a job context, so that we don't need NULL pointer checks while importing. */
short stop = 0, do_update = 0;
- float progress = 0.f;
+ float progress = 0.0f;
import_startjob(job, &stop, &do_update, &progress);
import_endjob(job);
diff --git a/source/blender/io/usd/intern/usd_reader_geom.h b/source/blender/io/usd/intern/usd_reader_geom.h
index 6dcad2ffac8..b73279250f2 100644
--- a/source/blender/io/usd/intern/usd_reader_geom.h
+++ b/source/blender/io/usd/intern/usd_reader_geom.h
@@ -24,7 +24,7 @@ class USDGeomReader : public USDXformReader {
int read_flag,
const char **err_str) = 0;
- virtual bool topology_changed(Mesh * /* existing_mesh */, double /* motionSampleTime */)
+ virtual bool topology_changed(const Mesh * /* existing_mesh */, double /* motionSampleTime */)
{
return true;
}
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 1f97c7b48b3..646d1ba1fde 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -232,7 +232,7 @@ bool USDMeshReader::valid() const
return static_cast<bool>(mesh_prim_);
}
-bool USDMeshReader::topology_changed(Mesh *existing_mesh, const double motionSampleTime)
+bool USDMeshReader::topology_changed(const Mesh *existing_mesh, const double motionSampleTime)
{
/* TODO(makowalski): Is it the best strategy to cache the mesh
* geometry in this function? This needs to be revisited. */
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h
index fdd814f56d4..5e33ce8b5e8 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.h
+++ b/source/blender/io/usd/intern/usd_reader_mesh.h
@@ -53,7 +53,7 @@ class USDMeshReader : public USDGeomReader {
int read_flag,
const char **err_str) override;
- bool topology_changed(Mesh *existing_mesh, double motionSampleTime) override;
+ bool topology_changed(const Mesh *existing_mesh, double motionSampleTime) override;
private:
void process_normals_vertex_varying(Mesh *mesh);
diff --git a/source/blender/io/usd/intern/usd_reader_volume.cc b/source/blender/io/usd/intern/usd_reader_volume.cc
index aec30539ee6..13044de5002 100644
--- a/source/blender/io/usd/intern/usd_reader_volume.cc
+++ b/source/blender/io/usd/intern/usd_reader_volume.cc
@@ -54,18 +54,6 @@ void USDVolumeReader::read_object_data(Main *bmain, const double motionSampleTim
pxr::UsdVolOpenVDBAsset fieldBase(fieldPrim);
- pxr::UsdAttribute fieldNameAttr = fieldBase.GetFieldNameAttr();
-
- if (fieldNameAttr.IsAuthored()) {
- pxr::TfToken fieldName;
- fieldNameAttr.Get(&fieldName, motionSampleTime);
-
- /* A Blender volume creates density by default. */
- if (fieldName != usdtokens::density) {
- BKE_volume_grid_add(volume, fieldName.GetString().c_str(), VOLUME_GRID_FLOAT);
- }
- }
-
pxr::UsdAttribute filepathAttr = fieldBase.GetFilePathAttr();
if (filepathAttr.IsAuthored()) {
diff --git a/source/blender/io/usd/intern/usd_writer_material.cc b/source/blender/io/usd/intern/usd_writer_material.cc
index 09cb0d07493..29ab0479f6e 100644
--- a/source/blender/io/usd/intern/usd_writer_material.cc
+++ b/source/blender/io/usd/intern/usd_writer_material.cc
@@ -6,6 +6,7 @@
#include "usd_exporter_context.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_main.h"
#include "BKE_node.h"
@@ -335,7 +336,7 @@ static std::string get_in_memory_texture_filename(Image *ima)
}
ImageFormatData imageFormat;
- BKE_imbuf_to_image_format(&imageFormat, imbuf);
+ BKE_image_format_from_imbuf(&imageFormat, imbuf);
char file_name[FILE_MAX];
/* Use the image name for the file name. */
@@ -368,7 +369,7 @@ static void export_in_memory_texture(Image *ima,
}
ImageFormatData imageFormat;
- BKE_imbuf_to_image_format(&imageFormat, imbuf);
+ BKE_image_format_from_imbuf(&imageFormat, imbuf);
/* This image in its current state only exists in Blender memory.
* So we have to export it. The export will keep the image state intact,
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
index 5631bdde2f8..acfdaa29b52 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
@@ -43,16 +43,33 @@ void OBJWriter::write_vert_uv_normal_indices(FormatHandler<eFileType::OBJ> &fh,
const IndexOffsets &offsets,
Span<int> vert_indices,
Span<int> uv_indices,
- Span<int> normal_indices) const
+ Span<int> normal_indices,
+ bool flip) const
{
BLI_assert(vert_indices.size() == uv_indices.size() &&
vert_indices.size() == normal_indices.size());
+ const int vertex_offset = offsets.vertex_offset + 1;
+ const int uv_offset = offsets.uv_vertex_offset + 1;
+ const int normal_offset = offsets.normal_offset + 1;
+ const int n = vert_indices.size();
fh.write<eOBJSyntaxElement::poly_element_begin>();
- for (int j = 0; j < vert_indices.size(); j++) {
- fh.write<eOBJSyntaxElement::vertex_uv_normal_indices>(
- vert_indices[j] + offsets.vertex_offset + 1,
- uv_indices[j] + offsets.uv_vertex_offset + 1,
- normal_indices[j] + offsets.normal_offset + 1);
+ if (!flip) {
+ for (int j = 0; j < n; ++j) {
+ fh.write<eOBJSyntaxElement::vertex_uv_normal_indices>(vert_indices[j] + vertex_offset,
+ uv_indices[j] + uv_offset,
+ normal_indices[j] + normal_offset);
+ }
+ }
+ else {
+ /* For a transform that is mirrored (negative scale on odd number of axes),
+ * we want to flip the face index order. Start from the same index, and
+ * then go backwards. Same logic in other write_*_indices functions below. */
+ for (int k = 0; k < n; ++k) {
+ int j = k == 0 ? 0 : n - k;
+ fh.write<eOBJSyntaxElement::vertex_uv_normal_indices>(vert_indices[j] + vertex_offset,
+ uv_indices[j] + uv_offset,
+ normal_indices[j] + normal_offset);
+ }
}
fh.write<eOBJSyntaxElement::poly_element_end>();
}
@@ -61,14 +78,26 @@ void OBJWriter::write_vert_normal_indices(FormatHandler<eFileType::OBJ> &fh,
const IndexOffsets &offsets,
Span<int> vert_indices,
Span<int> /*uv_indices*/,
- Span<int> normal_indices) const
+ Span<int> normal_indices,
+ bool flip) const
{
BLI_assert(vert_indices.size() == normal_indices.size());
+ const int vertex_offset = offsets.vertex_offset + 1;
+ const int normal_offset = offsets.normal_offset + 1;
+ const int n = vert_indices.size();
fh.write<eOBJSyntaxElement::poly_element_begin>();
- for (int j = 0; j < vert_indices.size(); j++) {
- fh.write<eOBJSyntaxElement::vertex_normal_indices>(vert_indices[j] + offsets.vertex_offset + 1,
- normal_indices[j] + offsets.normal_offset +
- 1);
+ if (!flip) {
+ for (int j = 0; j < n; ++j) {
+ fh.write<eOBJSyntaxElement::vertex_normal_indices>(vert_indices[j] + vertex_offset,
+ normal_indices[j] + normal_offset);
+ }
+ }
+ else {
+ for (int k = 0; k < n; ++k) {
+ int j = k == 0 ? 0 : n - k;
+ fh.write<eOBJSyntaxElement::vertex_normal_indices>(vert_indices[j] + vertex_offset,
+ normal_indices[j] + normal_offset);
+ }
}
fh.write<eOBJSyntaxElement::poly_element_end>();
}
@@ -77,13 +106,26 @@ void OBJWriter::write_vert_uv_indices(FormatHandler<eFileType::OBJ> &fh,
const IndexOffsets &offsets,
Span<int> vert_indices,
Span<int> uv_indices,
- Span<int> /*normal_indices*/) const
+ Span<int> /*normal_indices*/,
+ bool flip) const
{
BLI_assert(vert_indices.size() == uv_indices.size());
+ const int vertex_offset = offsets.vertex_offset + 1;
+ const int uv_offset = offsets.uv_vertex_offset + 1;
+ const int n = vert_indices.size();
fh.write<eOBJSyntaxElement::poly_element_begin>();
- for (int j = 0; j < vert_indices.size(); j++) {
- fh.write<eOBJSyntaxElement::vertex_uv_indices>(vert_indices[j] + offsets.vertex_offset + 1,
- uv_indices[j] + offsets.uv_vertex_offset + 1);
+ if (!flip) {
+ for (int j = 0; j < n; ++j) {
+ fh.write<eOBJSyntaxElement::vertex_uv_indices>(vert_indices[j] + vertex_offset,
+ uv_indices[j] + uv_offset);
+ }
+ }
+ else {
+ for (int k = 0; k < n; ++k) {
+ int j = k == 0 ? 0 : n - k;
+ fh.write<eOBJSyntaxElement::vertex_uv_indices>(vert_indices[j] + vertex_offset,
+ uv_indices[j] + uv_offset);
+ }
}
fh.write<eOBJSyntaxElement::poly_element_end>();
}
@@ -92,11 +134,22 @@ void OBJWriter::write_vert_indices(FormatHandler<eFileType::OBJ> &fh,
const IndexOffsets &offsets,
Span<int> vert_indices,
Span<int> /*uv_indices*/,
- Span<int> /*normal_indices*/) const
+ Span<int> /*normal_indices*/,
+ bool flip) const
{
+ const int vertex_offset = offsets.vertex_offset + 1;
+ const int n = vert_indices.size();
fh.write<eOBJSyntaxElement::poly_element_begin>();
- for (const int vert_index : vert_indices) {
- fh.write<eOBJSyntaxElement::vertex_indices>(vert_index + offsets.vertex_offset + 1);
+ if (!flip) {
+ for (int j = 0; j < n; ++j) {
+ fh.write<eOBJSyntaxElement::vertex_indices>(vert_indices[j] + vertex_offset);
+ }
+ }
+ else {
+ for (int k = 0; k < n; ++k) {
+ int j = k == 0 ? 0 : n - k;
+ fh.write<eOBJSyntaxElement::vertex_indices>(vert_indices[j] + vertex_offset);
+ }
}
fh.write<eOBJSyntaxElement::poly_element_end>();
}
@@ -121,34 +174,14 @@ void OBJWriter::write_mtllib_name(const StringRefNull mtl_filepath) const
fh.write_to_file(outfile_);
}
-void OBJWriter::write_object_group(FormatHandler<eFileType::OBJ> &fh,
- const OBJMesh &obj_mesh_data) const
-{
- /* "o object_name" is not mandatory. A valid .OBJ file may contain neither
- * "o name" nor "g group_name". */
- BLI_assert(export_params_.export_object_groups);
- if (!export_params_.export_object_groups) {
- return;
- }
- const std::string object_name = obj_mesh_data.get_object_name();
- const char *object_mesh_name = obj_mesh_data.get_object_mesh_name();
- const char *object_material_name = obj_mesh_data.get_object_material_name(0);
- if (export_params_.export_materials && export_params_.export_material_groups &&
- object_material_name) {
- fh.write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name + "_" +
- object_material_name);
- }
- else {
- fh.write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name);
- }
-}
-
void OBJWriter::write_object_name(FormatHandler<eFileType::OBJ> &fh,
const OBJMesh &obj_mesh_data) const
{
const char *object_name = obj_mesh_data.get_object_name();
if (export_params_.export_object_groups) {
- write_object_group(fh, obj_mesh_data);
+ const std::string object_name = obj_mesh_data.get_object_name();
+ const char *mesh_name = obj_mesh_data.get_object_mesh_name();
+ fh.write<eOBJSyntaxElement::object_group>(object_name + "_" + mesh_name);
return;
}
fh.write<eOBJSyntaxElement::object_name>(object_name);
@@ -275,14 +308,20 @@ void OBJWriter::write_poly_elements(FormatHandler<eFileType::OBJ> &fh,
obj_mesh_data.tot_uv_vertices());
const int tot_polygons = obj_mesh_data.tot_polygons();
- obj_parallel_chunked_output(fh, tot_polygons, [&](FormatHandler<eFileType::OBJ> &buf, int i) {
+ obj_parallel_chunked_output(fh, tot_polygons, [&](FormatHandler<eFileType::OBJ> &buf, int idx) {
+ /* Polygon order for writing into the file is not necessarily the same
+ * as order in the mesh; it will be sorted by material indices. Remap current
+ * and previous indices here according to the order. */
+ int prev_i = obj_mesh_data.remap_poly_index(idx - 1);
+ int i = obj_mesh_data.remap_poly_index(idx);
+
Vector<int> poly_vertex_indices = obj_mesh_data.calc_poly_vertex_indices(i);
Span<int> poly_uv_indices = obj_mesh_data.calc_poly_uv_indices(i);
Vector<int> poly_normal_indices = obj_mesh_data.calc_poly_normal_indices(i);
/* Write smoothing group if different from previous. */
{
- const int prev_group = get_smooth_group(obj_mesh_data, export_params_, i - 1);
+ const int prev_group = get_smooth_group(obj_mesh_data, export_params_, prev_i);
const int group = get_smooth_group(obj_mesh_data, export_params_, i);
if (group != prev_group) {
buf.write<eOBJSyntaxElement::smooth_group>(group);
@@ -291,8 +330,8 @@ void OBJWriter::write_poly_elements(FormatHandler<eFileType::OBJ> &fh,
/* Write vertex group if different from previous. */
if (export_params_.export_vertex_groups) {
- const int16_t prev_group = i == 0 ? NEGATIVE_INIT :
- obj_mesh_data.get_poly_deform_group_index(i - 1);
+ const int16_t prev_group = idx == 0 ? NEGATIVE_INIT :
+ obj_mesh_data.get_poly_deform_group_index(prev_i);
const int16_t group = obj_mesh_data.get_poly_deform_group_index(i);
if (group != prev_group) {
buf.write<eOBJSyntaxElement::object_group>(
@@ -303,28 +342,33 @@ void OBJWriter::write_poly_elements(FormatHandler<eFileType::OBJ> &fh,
/* Write material name and material group if different from previous. */
if (export_params_.export_materials && obj_mesh_data.tot_materials() > 0) {
- const int16_t prev_mat = i == 0 ? NEGATIVE_INIT : obj_mesh_data.ith_poly_matnr(i - 1);
+ const int16_t prev_mat = idx == 0 ? NEGATIVE_INIT : obj_mesh_data.ith_poly_matnr(prev_i);
const int16_t mat = obj_mesh_data.ith_poly_matnr(i);
if (mat != prev_mat) {
if (mat == NOT_FOUND) {
buf.write<eOBJSyntaxElement::poly_usemtl>(MATERIAL_GROUP_DISABLED);
}
else {
- if (export_params_.export_object_groups) {
- write_object_group(buf, obj_mesh_data);
- }
const char *mat_name = matname_fn(mat);
if (!mat_name) {
mat_name = MATERIAL_GROUP_DISABLED;
}
+ if (export_params_.export_material_groups) {
+ const std::string object_name = obj_mesh_data.get_object_name();
+ fh.write<eOBJSyntaxElement::object_group>(object_name + "_" + mat_name);
+ }
buf.write<eOBJSyntaxElement::poly_usemtl>(mat_name);
}
}
}
/* Write polygon elements. */
- (this->*poly_element_writer)(
- buf, offsets, poly_vertex_indices, poly_uv_indices, poly_normal_indices);
+ (this->*poly_element_writer)(buf,
+ offsets,
+ poly_vertex_indices,
+ poly_uv_indices,
+ poly_normal_indices,
+ obj_mesh_data.is_mirrored_transform());
});
}
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
index 6048c6d8d7b..96f7d434338 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
@@ -67,10 +67,6 @@ class OBJWriter : NonMovable, NonCopyable {
*/
void write_object_name(FormatHandler<eFileType::OBJ> &fh, const OBJMesh &obj_mesh_data) const;
/**
- * Write an object's group with mesh and/or material name appended conditionally.
- */
- void write_object_group(FormatHandler<eFileType::OBJ> &fh, const OBJMesh &obj_mesh_data) const;
- /**
* Write file name of Material Library in .OBJ file.
*/
void write_mtllib_name(const StringRefNull mtl_filepath) const;
@@ -115,7 +111,8 @@ class OBJWriter : NonMovable, NonCopyable {
const IndexOffsets &offsets,
Span<int> vert_indices,
Span<int> uv_indices,
- Span<int> normal_indices) const;
+ Span<int> normal_indices,
+ bool flip) const;
/**
* \return Writer function with appropriate polygon-element syntax.
*/
@@ -128,7 +125,8 @@ class OBJWriter : NonMovable, NonCopyable {
const IndexOffsets &offsets,
Span<int> vert_indices,
Span<int> uv_indices,
- Span<int> normal_indices) const;
+ Span<int> normal_indices,
+ bool flip) const;
/**
* Write one line of polygon indices as "f v1//vn1 v2//vn2 ...".
*/
@@ -136,7 +134,8 @@ class OBJWriter : NonMovable, NonCopyable {
const IndexOffsets &offsets,
Span<int> vert_indices,
Span<int> /*uv_indices*/,
- Span<int> normal_indices) const;
+ Span<int> normal_indices,
+ bool flip) const;
/**
* Write one line of polygon indices as "f v1/vt1 v2/vt2 ...".
*/
@@ -144,7 +143,8 @@ class OBJWriter : NonMovable, NonCopyable {
const IndexOffsets &offsets,
Span<int> vert_indices,
Span<int> uv_indices,
- Span<int> /*normal_indices*/) const;
+ Span<int> /*normal_indices*/,
+ bool flip) const;
/**
* Write one line of polygon indices as "f v1 v2 ...".
*/
@@ -152,7 +152,8 @@ class OBJWriter : NonMovable, NonCopyable {
const IndexOffsets &offsets,
Span<int> vert_indices,
Span<int> /*uv_indices*/,
- Span<int> /*normal_indices*/) const;
+ Span<int> /*normal_indices*/,
+ bool flip) const;
};
/**
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
index b730c93bb7b..aa63e65b1e8 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
@@ -17,6 +17,7 @@
#include "BLI_listbase.h"
#include "BLI_map.hh"
#include "BLI_math.h"
+#include "BLI_sort.hh"
#include "DEG_depsgraph_query.h"
@@ -76,6 +77,7 @@ void OBJMesh::clear()
uv_coords_.clear_and_make_inline();
loop_to_normal_index_.clear_and_make_inline();
normal_coords_.clear_and_make_inline();
+ poly_order_.clear_and_make_inline();
if (poly_smooth_groups_) {
MEM_freeN(poly_smooth_groups_);
poly_smooth_groups_ = nullptr;
@@ -87,8 +89,13 @@ std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval()
if (export_mesh_eval_->totpoly <= 0) {
return {export_mesh_eval_, false};
}
- const struct BMeshCreateParams bm_create_params = {0u};
- const struct BMeshFromMeshParams bm_convert_params = {1u, 0, 0, 0};
+ const BMeshCreateParams bm_create_params = {false};
+ BMeshFromMeshParams bm_convert_params{};
+ bm_convert_params.calc_face_normal = true;
+ bm_convert_params.calc_vert_normal = true;
+ bm_convert_params.add_key_index = false;
+ bm_convert_params.use_shapekey = false;
+
/* Lower threshold where triangulation of a polygon starts, i.e. a quadrilateral will be
* triangulated here. */
const int triangulate_min_verts = 4;
@@ -123,6 +130,13 @@ void OBJMesh::set_world_axes_transform(const eTransformAxisForward forward,
/* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */
mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, export_object_eval_.obmat[3]);
world_and_axes_transform_[3][3] = export_object_eval_.obmat[3][3];
+
+ /* Normals need inverse transpose of the regular matrix to handle non-uniform scale. */
+ float normal_matrix[3][3];
+ copy_m3_m4(normal_matrix, world_and_axes_transform_);
+ invert_m3_m3(world_and_axes_normal_transform_, normal_matrix);
+ transpose_m3(world_and_axes_normal_transform_);
+ mirrored_transform_ = determinant_m3_array(world_and_axes_normal_transform_) < 0;
}
int OBJMesh::tot_vertices() const
@@ -186,6 +200,25 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags)
use_bitflags);
}
+void OBJMesh::calc_poly_order()
+{
+ const int tot_polys = tot_polygons();
+ poly_order_.resize(tot_polys);
+ for (int i = 0; i < tot_polys; ++i) {
+ poly_order_[i] = i;
+ }
+ const MPoly *mpolys = export_mesh_eval_->mpoly;
+ /* Sort polygons by their material index. */
+ blender::parallel_sort(poly_order_.begin(), poly_order_.end(), [&](int a, int b) {
+ int mat_a = mpolys[a].mat_nr;
+ int mat_b = mpolys[b].mat_nr;
+ if (mat_a != mat_b) {
+ return mat_a < mat_b;
+ }
+ return a < b;
+ });
+}
+
const Material *OBJMesh::get_object_material(const int16_t mat_nr) const
{
/**
@@ -196,11 +229,6 @@ const Material *OBJMesh::get_object_material(const int16_t mat_nr) const
*/
Object *obj = const_cast<Object *>(&export_object_eval_);
const Material *r_mat = BKE_object_material_get(obj, mat_nr + 1);
-#ifdef DEBUG
- if (!r_mat) {
- std::cerr << "Material not found for mat_nr = " << mat_nr << std::endl;
- }
-#endif
return r_mat;
}
@@ -239,8 +267,8 @@ float3 OBJMesh::calc_vertex_coords(const int vert_index, const float scaling_fac
{
float3 r_coords;
copy_v3_v3(r_coords, export_mesh_eval_->mvert[vert_index].co);
- mul_v3_fl(r_coords, scaling_factor);
mul_m4_v3(world_and_axes_transform_, r_coords);
+ mul_v3_fl(r_coords, scaling_factor);
return r_coords;
}
@@ -319,7 +347,8 @@ float3 OBJMesh::calc_poly_normal(const int poly_index) const
const MLoop &mloop = export_mesh_eval_->mloop[poly.loopstart];
const MVert &mvert = *(export_mesh_eval_->mvert);
BKE_mesh_calc_poly_normal(&poly, &mloop, &mvert, r_poly_normal);
- mul_mat3_m4_v3(world_and_axes_transform_, r_poly_normal);
+ mul_m3_v3(world_and_axes_normal_transform_, r_poly_normal);
+ normalize_v3(r_poly_normal);
return r_poly_normal;
}
@@ -364,7 +393,8 @@ void OBJMesh::store_normal_coords_and_indices()
int loop_index = mpoly.loopstart + loop_of_poly;
BLI_assert(loop_index < export_mesh_eval_->totloop);
copy_v3_v3(loop_normal, lnors[loop_index]);
- mul_mat3_m4_v3(world_and_axes_transform_, loop_normal);
+ mul_m3_v3(world_and_axes_normal_transform_, loop_normal);
+ normalize_v3(loop_normal);
float3 rounded_loop_normal = round_float3_to_n_digits(loop_normal, round_digits);
int loop_norm_index = normal_to_index.lookup_default(rounded_loop_normal, -1);
if (loop_norm_index == -1) {
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
index 5b11c85b7a4..7650a220810 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
@@ -59,6 +59,8 @@ class OBJMesh : NonCopyable {
* object's world transform matrix.
*/
float world_and_axes_transform_[4][4];
+ float world_and_axes_normal_transform_[3][3];
+ bool mirrored_transform_;
/**
* Total UV vertices in a mesh's texture map.
@@ -93,6 +95,10 @@ class OBJMesh : NonCopyable {
* Polygon aligned array of their smooth groups.
*/
int *poly_smooth_groups_ = nullptr;
+ /**
+ * Order in which the polygons should be written into the file (sorted by material index).
+ */
+ Vector<int> poly_order_;
public:
/**
@@ -110,6 +116,10 @@ class OBJMesh : NonCopyable {
int tot_uv_vertices() const;
int tot_normal_indices() const;
int tot_edges() const;
+ bool is_mirrored_transform() const
+ {
+ return mirrored_transform_;
+ }
/**
* \return Total materials in the object.
@@ -212,6 +222,22 @@ class OBJMesh : NonCopyable {
*/
std::optional<std::array<int, 2>> calc_loose_edge_vert_indices(int edge_index) const;
+ /**
+ * Calculate the order in which the polygons should be written into the file (sorted by material
+ * index).
+ */
+ void calc_poly_order();
+
+ /**
+ * Remap polygon index according to polygon writing order.
+ * When materials are not being written, the polygon order array
+ * might be empty, in which case remap is a no-op.
+ */
+ int remap_poly_index(int i) const
+ {
+ return i < 0 || i >= poly_order_.size() ? i : poly_order_[i];
+ }
+
private:
/**
* Free the mesh if _the exporter_ created it.
diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
index 2cef5192337..30670d45ef7 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
@@ -204,6 +204,9 @@ static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_me
if (export_params.export_smooth_groups) {
obj.calc_smooth_groups(export_params.smooth_groups_bitflags);
}
+ if (export_params.export_materials) {
+ obj.calc_poly_order();
+ }
if (export_params.export_normals) {
obj_writer.write_poly_normals(fh, obj);
}
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
index cc1cca74a38..b8fecfb25f3 100644
--- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
@@ -405,6 +405,16 @@ TEST_F(obj_exporter_regression_test, vertices)
"io_tests/blend_geometry/vertices.blend", "io_tests/obj/vertices.obj", "", _export.params);
}
+TEST_F(obj_exporter_regression_test, non_uniform_scale)
+{
+ OBJExportParamsDefault _export;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden("io_tests/blend_geometry/non_uniform_scale.blend",
+ "io_tests/obj/non_uniform_scale.obj",
+ "",
+ _export.params);
+}
+
TEST_F(obj_exporter_regression_test, nurbs_as_nurbs)
{
OBJExportParamsDefault _export;
@@ -465,6 +475,17 @@ TEST_F(obj_exporter_regression_test, cube_normal_edit)
_export.params);
}
+TEST_F(obj_exporter_regression_test, cubes_positioned)
+{
+ OBJExportParamsDefault _export;
+ _export.params.export_materials = false;
+ _export.params.scaling_factor = 2.0f;
+ compare_obj_export_to_golden("io_tests/blend_geometry/cubes_positioned.blend",
+ "io_tests/obj/cubes_positioned.obj",
+ "",
+ _export.params);
+}
+
TEST_F(obj_exporter_regression_test, suzanne_all_data)
{
OBJExportParamsDefault _export;
@@ -490,4 +511,17 @@ TEST_F(obj_exporter_regression_test, all_objects)
_export.params);
}
+TEST_F(obj_exporter_regression_test, all_objects_mat_groups)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_smooth_groups = true;
+ _export.params.export_material_groups = true;
+ compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend",
+ "io_tests/obj/all_objects_mat_groups.obj",
+ "io_tests/obj/all_objects_mat_groups.mtl",
+ _export.params);
+}
+
} // namespace blender::io::obj
diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h
index f8ffe6a0a47..783e79898ce 100644
--- a/source/blender/makesdna/DNA_brush_enums.h
+++ b/source/blender/makesdna/DNA_brush_enums.h
@@ -460,8 +460,9 @@ typedef enum eBrushCurvesSculptTool {
CURVES_SCULPT_TOOL_COMB = 0,
CURVES_SCULPT_TOOL_DELETE = 1,
CURVES_SCULPT_TOOL_SNAKE_HOOK = 2,
- CURVES_SCULPT_TOOL_TEST1 = 3,
- CURVES_SCULPT_TOOL_TEST2 = 4,
+ CURVES_SCULPT_TOOL_ADD = 3,
+ CURVES_SCULPT_TOOL_TEST1 = 4,
+ CURVES_SCULPT_TOOL_TEST2 = 5,
} eBrushCurvesSculptTool;
/** When #BRUSH_ACCUMULATE is used */
@@ -602,10 +603,10 @@ typedef enum eBlurKernelType {
} eBlurKernelType;
/* Brush.falloff_shape */
-enum {
+typedef enum eBrushFalloffShape {
PAINT_FALLOFF_SHAPE_SPHERE = 0,
PAINT_FALLOFF_SHAPE_TUBE = 1,
-};
+} eBrushFalloffShape;
#define MAX_BRUSH_PIXEL_RADIUS 500
#define GP_MAX_BRUSH_PIXEL_RADIUS 1000
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index fe80220b1dd..564f34b1f72 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -137,6 +137,11 @@ typedef struct BrushGpencilSettings {
struct Material *material;
} BrushGpencilSettings;
+typedef struct BrushCurvesSculptSettings {
+ /* Number of curves added by the add brush. */
+ int add_amount;
+} BrushCurvesSculptSettings;
+
typedef struct Brush {
ID id;
@@ -256,7 +261,7 @@ typedef struct Brush {
char gpencil_sculpt_tool;
/** Active grease pencil weight tool. */
char gpencil_weight_tool;
- /** Active curves sculpt tool. */
+ /** Active curves sculpt tool (#eBrushCurvesSculptTool). */
char curves_sculpt_tool;
char _pad1[5];
@@ -360,7 +365,7 @@ typedef struct Brush {
float mask_stencil_dimension[2];
struct BrushGpencilSettings *gpencil_settings;
-
+ struct BrushCurvesSculptSettings *curves_sculpt_settings;
} Brush;
/* Struct to hold palette colors for sorting. */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 2f9f63cb966..56e223cda5f 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -52,7 +52,7 @@ typedef struct CustomDataLayer {
typedef struct CustomDataExternal {
/** FILE_MAX. */
- char filename[1024];
+ char filepath[1024];
} CustomDataExternal;
/**
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
index 3e06259dfd5..a87e7a7c397 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_defaults.h
@@ -366,5 +366,14 @@
.smooth_step = 1, \
}
+#define _DNA_DEFAULT_EnvelopeGpencilModifierData \
+ { \
+ .spread = 10, \
+ .mode = GP_ENVELOPE_SEGMENTS, \
+ .mat_nr = -1, \
+ .thickness = 1.0f, \
+ .strength = 1.0f, \
+ }
+
/* clang-format off */
diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h
index 0539b84e093..1054c309ee5 100644
--- a/source/blender/makesdna/DNA_gpencil_modifier_types.h
+++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h
@@ -46,6 +46,7 @@ typedef enum GpencilModifierType {
eGpencilModifierType_Dash = 22,
eGpencilModifierType_WeightAngle = 23,
eGpencilModifierType_Shrinkwrap = 24,
+ eGpencilModifierType_Envelope = 25,
/* Keep last. */
NUM_GREASEPENCIL_MODIFIER_TYPES,
} GpencilModifierType;
@@ -1127,6 +1128,46 @@ typedef enum eShrinkwrapGpencil_Flag {
GP_SHRINKWRAP_INVERT_VGROUP = (1 << 6),
} eShrinkwrapGpencil_Flag;
+typedef struct EnvelopeGpencilModifierData {
+ GpencilModifierData modifier;
+ /** Material for filtering. */
+ struct Material *material;
+ /** Layer name. */
+ char layername[64];
+ /** Optional vertexgroup name, MAX_VGROUP_NAME. */
+ char vgname[64];
+ /** Custom index for passes. */
+ int pass_index;
+ /** Several flags. */
+ int flag;
+ int mode;
+ /** Material for the new strokes. */
+ int mat_nr;
+ /** Thickness multiplier for the new strokes. */
+ float thickness;
+ /** Strength multiplier for the new strokes. */
+ float strength;
+ /** Custom index for passes. */
+ int layer_pass;
+ /* Length of the envelope effect. */
+ int spread;
+} EnvelopeGpencilModifierData;
+
+typedef enum eEnvelopeGpencil_Flag {
+ GP_ENVELOPE_INVERT_LAYER = (1 << 0),
+ GP_ENVELOPE_INVERT_PASS = (1 << 1),
+ GP_ENVELOPE_INVERT_VGROUP = (1 << 2),
+ GP_ENVELOPE_INVERT_LAYERPASS = (1 << 3),
+ GP_ENVELOPE_INVERT_MATERIAL = (1 << 4),
+} eEnvelopeGpencil_Flag;
+
+/* Texture->mode */
+typedef enum eEnvelopeGpencil_Mode {
+ GP_ENVELOPE_DEFORM = 0,
+ GP_ENVELOPE_SEGMENTS = 1,
+ GP_ENVELOPE_FILLS = 2,
+} eEnvelopeGpencil_Mode;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index fe3613548a6..8a30a7e8c99 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -25,8 +25,6 @@ struct MDeformVert;
#define GP_DEFAULT_GRID_LINES 4
#define GP_MAX_INPUT_SAMPLES 10
-#define GP_MATERIAL_BUFFER_LEN 256
-
#define GP_DEFAULT_CURVE_RESOLUTION 32
#define GP_DEFAULT_CURVE_ERROR 0.1f
#define GP_DEFAULT_CURVE_EDIT_CORNER_ANGLE M_PI_2
diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h
index 465ec6e7db5..7b6fe3773f8 100644
--- a/source/blender/makesdna/DNA_layer_types.h
+++ b/source/blender/makesdna/DNA_layer_types.h
@@ -113,7 +113,7 @@ typedef struct ViewLayerEEVEE {
int _pad[1];
} ViewLayerEEVEE;
-/* AOV Renderpass definition. */
+/** AOV Render-pass definition. */
typedef struct ViewLayerAOV {
struct ViewLayerAOV *next, *prev;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 5bd44868741..99d7e15fa7a 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -761,7 +761,7 @@ typedef struct NodeImageLayer {
/* index in the Image->layers->passes lists */
int pass_index DNA_DEPRECATED;
/* render pass name */
- /** Amount defined in openexr_multi.h. */
+ /** Amount defined in IMB_openexr.h. */
char pass_name[64];
} NodeImageLayer;
@@ -1210,53 +1210,6 @@ typedef struct NodeMapRange {
char _pad[5];
} NodeMapRange;
-typedef struct NodeAttributeClamp {
- /* CustomDataType. */
- uint8_t data_type;
-
- /* NodeClampOperation. */
- uint8_t operation;
-} NodeAttributeClamp;
-
-typedef struct NodeAttributeCompare {
- /* FloatCompareOperation. */
- uint8_t operation;
-
- /* GeometryNodeAttributeInputMode */
- uint8_t input_type_a;
- uint8_t input_type_b;
-
- char _pad[5];
-} NodeAttributeCompare;
-
-typedef struct NodeAttributeMapRange {
- /* GeometryNodeAttributeDataType */
- uint8_t data_type;
-
- /* NodeMapRangeType. */
- uint8_t interpolation_type;
-} NodeAttributeMapRange;
-
-typedef struct NodeAttributeMath {
- /* NodeMathOperation. */
- uint8_t operation;
-
- /* GeometryNodeAttributeInputMode */
- uint8_t input_type_a;
- uint8_t input_type_b;
- uint8_t input_type_c;
-} NodeAttributeMath;
-
-typedef struct NodeAttributeMix {
- /* e.g. MA_RAMP_BLEND. */
- uint8_t blend_type;
-
- /* GeometryNodeAttributeInputMode */
- uint8_t input_type_factor;
- uint8_t input_type_a;
- uint8_t input_type_b;
-} NodeAttributeMix;
-
typedef struct NodeRandomValue {
/* CustomDataType. */
uint8_t data_type;
@@ -1269,51 +1222,6 @@ typedef struct NodeAccumulateField {
uint8_t domain;
} NodeAccumulateField;
-typedef struct NodeAttributeRandomize {
- /* CustomDataType. */
- uint8_t data_type;
- /* AttributeDomain. */
- uint8_t domain;
- /* GeometryNodeAttributeRandomizeMode. */
- uint8_t operation;
- char _pad[1];
-} NodeAttributeRandomize;
-
-typedef struct NodeAttributeVectorMath {
- /* NodeVectorMathOperation */
- uint8_t operation;
-
- /* GeometryNodeAttributeInputMode */
- uint8_t input_type_a;
- uint8_t input_type_b;
- uint8_t input_type_c;
-} NodeAttributeVectorMath;
-
-typedef struct NodeAttributeVectorRotate {
- /* GeometryNodeAttributeVectorRotateMode */
- uint8_t mode;
-
- /* GeometryNodeAttributeInputMode */
- uint8_t input_type_vector;
- uint8_t input_type_center;
- uint8_t input_type_axis;
- uint8_t input_type_angle;
- uint8_t input_type_rotation;
- char _pad[2];
-} NodeAttributeVectorRotate;
-
-typedef struct NodeAttributeColorRamp {
- ColorBand color_ramp;
-} NodeAttributeColorRamp;
-
-typedef struct NodeAttributeCurveMap {
- /* CustomDataType. */
- uint8_t data_type;
- char _pad[7];
- CurveMapping *curve_vec;
- CurveMapping *curve_rgb;
-} NodeAttributeCurveMap;
-
typedef struct NodeInputBool {
uint8_t boolean;
} NodeInputBool;
@@ -1334,40 +1242,6 @@ typedef struct NodeInputString {
char *string;
} NodeInputString;
-typedef struct NodeGeometryRotatePoints {
- /* GeometryNodeRotatePointsType */
- uint8_t type;
- /* GeometryNodeRotatePointsSpace */
- uint8_t space;
-
- /* GeometryNodeAttributeInputMode */
- uint8_t input_type_axis;
- uint8_t input_type_angle;
- uint8_t input_type_rotation;
- char _pad[3];
-} NodeGeometryRotatePoints;
-
-typedef struct NodeGeometryAlignRotationToVector {
- /* GeometryNodeAlignRotationToVectorAxis */
- uint8_t axis;
- /* GeometryNodeAlignRotationToVectorPivotAxis */
- uint8_t pivot_axis;
-
- /* GeometryNodeAttributeInputMode */
- uint8_t input_type_factor;
- uint8_t input_type_vector;
-} NodeGeometryAlignRotationToVector;
-
-typedef struct NodeGeometryPointScale {
- /* GeometryNodeAttributeInputMode */
- uint8_t input_type;
-} NodeGeometryPointScale;
-
-typedef struct NodeGeometryPointTranslate {
- /* GeometryNodeAttributeInputMode */
- uint8_t input_type;
-} NodeGeometryPointTranslate;
-
typedef struct NodeGeometryExtrudeMesh {
/* GeometryNodeExtrudeMeshMode */
uint8_t mode;
@@ -1378,13 +1252,6 @@ typedef struct NodeGeometryObjectInfo {
uint8_t transform_space;
} NodeGeometryObjectInfo;
-typedef struct NodeGeometryPointInstance {
- /* GeometryNodePointInstanceType. */
- uint8_t instance_type;
- /* GeometryNodePointInstanceFlag. */
- uint8_t flag;
-} NodeGeometryPointInstance;
-
typedef struct NodeGeometryPointsToVolume {
/* GeometryNodePointsToVolumeResolutionMode */
uint8_t resolution_mode;
@@ -1397,11 +1264,6 @@ typedef struct NodeGeometryCollectionInfo {
uint8_t transform_space;
} NodeGeometryCollectionInfo;
-typedef struct NodeGeometryAttributeProximity {
- /* GeometryNodeAttributeProximityTargetType. */
- uint8_t target_geometry_element;
-} NodeGeometryAttributeProximity;
-
typedef struct NodeGeometryProximity {
/* GeometryNodeProximityTargetType. */
uint8_t target_element;
@@ -1412,27 +1274,6 @@ typedef struct NodeGeometryVolumeToMesh {
uint8_t resolution_mode;
} NodeGeometryVolumeToMesh;
-typedef struct NodeAttributeCombineXYZ {
- /* GeometryNodeAttributeInputMode. */
- uint8_t input_type_x;
- uint8_t input_type_y;
- uint8_t input_type_z;
-
- char _pad[1];
-} NodeAttributeCombineXYZ;
-
-typedef struct NodeAttributeSeparateXYZ {
- /* GeometryNodeAttributeInputMode. */
- uint8_t input_type;
-} NodeAttributeSeparateXYZ;
-
-typedef struct NodeAttributeConvert {
- /* CustomDataType. */
- int8_t data_type;
- /* AttributeDomain. */
- int8_t domain;
-} NodeAttributeConvert;
-
typedef struct NodeGeometrySubdivisionSurface {
/* eSubsurfUVSmooth. */
uint8_t uv_smooth;
@@ -1521,11 +1362,6 @@ typedef struct NodeGeometryCurveResample {
uint8_t mode;
} NodeGeometryCurveResample;
-typedef struct NodeGeometryCurveSubdivide {
- /* GeometryNodeAttributeInputMode (integer or attribute). */
- uint8_t cuts_type;
-} NodeGeometryCurveSubdivide;
-
typedef struct NodeGeometryCurveFillet {
/* GeometryNodeCurveFilletMode. */
uint8_t mode;
@@ -1546,13 +1382,6 @@ typedef struct NodeGeometryCurveSample {
uint8_t mode;
} NodeGeometryCurveSample;
-typedef struct NodeGeometryAttributeTransfer {
- /* AttributeDomain. */
- int8_t domain;
- /* GeometryNodeAttributeTransferMapMode. */
- uint8_t mapping;
-} NodeGeometryAttributeTransfer;
-
typedef struct NodeGeometryTransferAttribute {
/* CustomDataType. */
int8_t data_type;
@@ -2080,12 +1909,6 @@ typedef enum NodeShaderOutputTarget {
/* Geometry Nodes */
-typedef enum GeometryNodeAttributeProximityTargetType {
- GEO_NODE_PROXIMITY_TARGET_POINTS = 0,
- GEO_NODE_PROXIMITY_TARGET_EDGES = 1,
- GEO_NODE_PROXIMITY_TARGET_FACES = 2,
-} GeometryNodeAttributeProximityTargetType;
-
typedef enum GeometryNodeProximityTargetType {
GEO_NODE_PROX_TARGET_POINTS = 0,
GEO_NODE_PROX_TARGET_EDGES = 1,
@@ -2134,30 +1957,6 @@ typedef enum GeometryNodeTriangulateQuads {
GEO_NODE_TRIANGULATE_QUAD_LONGEDGE = 4,
} GeometryNodeTriangulateQuads;
-typedef enum GeometryNodePointInstanceType {
- GEO_NODE_POINT_INSTANCE_TYPE_OBJECT = 0,
- GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION = 1,
- GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY = 2,
-} GeometryNodePointInstanceType;
-
-typedef enum GeometryNodePointInstanceFlag {
- GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION = (1 << 0),
-} GeometryNodePointInstanceFlag;
-
-typedef enum GeometryNodeAttributeInputMode {
- GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE = 0,
- GEO_NODE_ATTRIBUTE_INPUT_FLOAT = 1,
- GEO_NODE_ATTRIBUTE_INPUT_VECTOR = 2,
- GEO_NODE_ATTRIBUTE_INPUT_COLOR = 3,
- GEO_NODE_ATTRIBUTE_INPUT_BOOLEAN = 4,
- GEO_NODE_ATTRIBUTE_INPUT_INTEGER = 5,
-} GeometryNodeAttributeInputMode;
-
-typedef enum GeometryNodePointDistributeMode {
- GEO_NODE_POINT_DISTRIBUTE_RANDOM = 0,
- GEO_NODE_POINT_DISTRIBUTE_POISSON = 1,
-} GeometryNodePointDistributeMode;
-
typedef enum GeometryNodeDistributePointsOnFacesMode {
GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM = 0,
GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON = 1,
@@ -2169,54 +1968,16 @@ typedef enum GeometryNodeExtrudeMeshMode {
GEO_NODE_EXTRUDE_MESH_FACES = 2,
} GeometryNodeExtrudeMeshMode;
-typedef enum GeometryNodeRotatePointsType {
- GEO_NODE_POINT_ROTATE_TYPE_EULER = 0,
- GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE = 1,
-} GeometryNodeRotatePointsType;
-
-typedef enum FunctionNodeRotatePointsType {
+typedef enum FunctionNodeRotateEulerType {
FN_NODE_ROTATE_EULER_TYPE_EULER = 0,
FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE = 1,
-} FunctionNodeRotatePointsType;
-
-typedef enum GeometryNodeAttributeVectorRotateMode {
- GEO_NODE_VECTOR_ROTATE_TYPE_AXIS = 0,
- GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_X = 1,
- GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Y = 2,
- GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Z = 3,
- GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ = 4,
-} GeometryNodeAttributeVectorRotateMode;
-
-typedef enum GeometryNodeAttributeRandomizeMode {
- GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE = 0,
- GEO_NODE_ATTRIBUTE_RANDOMIZE_ADD = 1,
- GEO_NODE_ATTRIBUTE_RANDOMIZE_SUBTRACT = 2,
- GEO_NODE_ATTRIBUTE_RANDOMIZE_MULTIPLY = 3,
-} GeometryNodeAttributeRandomizeMode;
-
-typedef enum GeometryNodeRotatePointsSpace {
- GEO_NODE_POINT_ROTATE_SPACE_OBJECT = 0,
- GEO_NODE_POINT_ROTATE_SPACE_POINT = 1,
-} GeometryNodeRotatePointsSpace;
+} FunctionNodeRotateEulerType;
typedef enum FunctionNodeRotateEulerSpace {
FN_NODE_ROTATE_EULER_SPACE_OBJECT = 0,
FN_NODE_ROTATE_EULER_SPACE_LOCAL = 1,
} FunctionNodeRotateEulerSpace;
-typedef enum GeometryNodeAlignRotationToVectorAxis {
- GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_X = 0,
- GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_Y = 1,
- GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_Z = 2,
-} GeometryNodeAlignRotationToVectorAxis;
-
-typedef enum GeometryNodeAlignRotationToVectorPivotAxis {
- GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_AUTO = 0,
- GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_X = 1,
- GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_Y = 2,
- GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_Z = 3,
-} GeometryNodeAlignRotationToVectorPivotAxis;
-
typedef enum NodeAlignEulerToVectorAxis {
FN_NODE_ALIGN_EULER_TO_VECTOR_AXIS_X = 0,
FN_NODE_ALIGN_EULER_TO_VECTOR_AXIS_Y = 1,
@@ -2295,11 +2056,6 @@ typedef enum GeometryNodeCurveFilletMode {
GEO_NODE_CURVE_FILLET_POLY = 1,
} GeometryNodeCurveFilletMode;
-typedef enum GeometryNodeAttributeTransferMapMode {
- GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED = 0,
- GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER_NEAREST = 1,
-} GeometryNodeAttributeTransferMapMode;
-
typedef enum GeometryNodeAttributeTransferMode {
GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED = 0,
GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST = 1,
diff --git a/source/blender/makesdna/DNA_particle_defaults.h b/source/blender/makesdna/DNA_particle_defaults.h
index 138aa6f1f98..108252a5e6c 100644
--- a/source/blender/makesdna/DNA_particle_defaults.h
+++ b/source/blender/makesdna/DNA_particle_defaults.h
@@ -56,8 +56,8 @@
.rotmode = PART_ROT_VEL, \
.avemode = PART_AVE_VELOCITY, \
\
- .child_nbr = 10, \
- .ren_child_nbr = 100, \
+ .child_percent = 10, \
+ .child_render_percent = 100, \
.childrad = 0.2f, \
.childflat = 0.0f, \
.clumppow = 0.0f, \
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index 397385c0f5b..f3d342e4849 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -226,7 +226,7 @@ typedef struct ParticleSettings {
/* children */
int child_flag;
char _pad3[4];
- int child_nbr, ren_child_nbr;
+ int child_percent, child_render_percent;
float parents, childsize, childrandsize;
float childrad, childflat;
/* clumping */
diff --git a/source/blender/makesdna/DNA_pointcache_types.h b/source/blender/makesdna/DNA_pointcache_types.h
index b247176f537..1133237199b 100644
--- a/source/blender/makesdna/DNA_pointcache_types.h
+++ b/source/blender/makesdna/DNA_pointcache_types.h
@@ -131,7 +131,7 @@ enum {
PTCACHE_FRAMES_SKIPPED = 1 << 8,
PTCACHE_EXTERNAL = 1 << 9,
PTCACHE_READ_INFO = 1 << 10,
- /** Don't use the filename of the blend-file the data is linked from (write a local cache). */
+ /** Don't use the file-path of the blend-file the data is linked from (write a local cache). */
PTCACHE_IGNORE_LIBPATH = 1 << 11,
/**
* High resolution cache is saved for smoke for backwards compatibility,
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 2f8d1c5eafe..e6b2f2769b8 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -429,8 +429,11 @@ typedef struct ImageFormatData {
Stereo3dFormat stereo3d_format;
/* color management */
+ char color_management;
+ char _pad1[7];
ColorManagedViewSettings view_settings;
ColorManagedDisplaySettings display_settings;
+ ColorManagedColorspaceSettings linear_colorspace_settings;
} ImageFormatData;
/** #ImageFormatData.imtype */
@@ -462,12 +465,13 @@ typedef struct ImageFormatData {
#define R_IMF_IMTYPE_XVID 32
#define R_IMF_IMTYPE_THEORA 33
#define R_IMF_IMTYPE_PSD 34
+#define R_IMF_IMTYPE_WEBP 35
#define R_IMF_IMTYPE_INVALID 255
/** #ImageFormatData.flag */
-#define R_IMF_FLAG_ZBUF (1 << 0) /* was R_OPENEXR_ZBUF */
-#define R_IMF_FLAG_PREVIEW_JPG (1 << 1) /* was R_PREVIEW_JPG */
+#define R_IMF_FLAG_ZBUF (1 << 0)
+#define R_IMF_FLAG_PREVIEW_JPG (1 << 1)
/* Return values from #BKE_imtype_valid_depths, note this is depths per channel. */
/** #ImageFormatData.depth */
@@ -526,6 +530,10 @@ enum {
R_IMF_TIFF_CODEC_NONE = 3,
};
+/** #ImageFormatData.color_management */
+#define R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE 0
+#define R_IMF_COLOR_MANAGEMENT_OVERRIDE 1
+
typedef struct BakeData {
struct ImageFormatData im_format;
@@ -992,11 +1000,23 @@ typedef struct Sculpt {
struct Object *gravity_object;
} Sculpt;
+typedef enum CurvesSculptFlag {
+ CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH = (1 << 0),
+ CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE = (1 << 1),
+} CurvesSculptFlag;
+
typedef struct CurvesSculpt {
Paint paint;
/** Minimum distance between newly added curves on a surface. */
float distance;
- char _pad1[4];
+
+ /** CurvesSculptFlag. */
+ uint32_t flag;
+
+ /** Length of newly added curves when it is not interpolated from other curves. */
+ float curve_length;
+
+ char _pad[4];
} CurvesSculpt;
typedef struct UvSculpt {
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index e6c163d94ba..f538917143b 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -309,7 +309,6 @@ typedef enum eSpaceOutliner_Flag {
typedef enum eSpaceOutliner_Filter {
SO_FILTER_SEARCH = (1 << 0), /* Run-time flag. */
SO_FILTER_CLEARED_1 = (1 << 1),
- SO_FILTER_NO_LIB_OVERRIDE = SO_FILTER_CLEARED_1, /* re-use */
SO_FILTER_NO_OBJECT = (1 << 2),
SO_FILTER_NO_OB_CONTENT = (1 << 3), /* Not only mesh, but modifiers, constraints, ... */
SO_FILTER_NO_CHILDREN = (1 << 4),
@@ -345,7 +344,7 @@ typedef enum eSpaceOutliner_Filter {
#define SO_FILTER_ANY \
(SO_FILTER_NO_OB_CONTENT | SO_FILTER_NO_CHILDREN | SO_FILTER_OB_TYPE | SO_FILTER_OB_STATE | \
- SO_FILTER_NO_COLLECTION | SO_FILTER_NO_VIEW_LAYERS | SO_FILTER_NO_LIB_OVERRIDE)
+ SO_FILTER_NO_COLLECTION | SO_FILTER_NO_VIEW_LAYERS)
/** #SpaceOutliner.filter_state */
typedef enum eSpaceOutliner_StateFilter {
@@ -782,7 +781,7 @@ typedef struct FileSelectParams {
char _pad1[2];
/* short */
- /** XXXXX for now store type here, should be moved to the operator. */
+ /** XXX: for now store type here, should be moved to the operator. */
short type; /* eFileSelectType */
/** Settings for filter, hiding dots files. */
short flag;
@@ -797,7 +796,7 @@ typedef struct FileSelectParams {
/** Filter when (flags & FILE_FILTER) is true. */
int filter;
- /** Max number of levels in dirtree to show at once, 0 to disable recursion. */
+ /** Max number of levels in directory tree to show at once, 0 to disable recursion. */
short recursion_level;
char _pad4[2];
@@ -1141,8 +1140,8 @@ typedef struct FileDirEntry {
#
typedef struct FileDirEntryArr {
ListBase entries;
- int nbr_entries;
- int nbr_entries_filtered;
+ int entries_num;
+ int entries_filtered_num;
/** FILE_MAX. */
char root[1024];
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 5784d437048..5fb8d0328f1 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -637,7 +637,6 @@ typedef struct UserDef_Experimental {
char use_undo_legacy;
char no_override_auto_resync;
char use_cycles_debug;
- char use_geometry_nodes_legacy;
char show_asset_debug_info;
char no_asset_indexing;
char SANITIZE_AFTER_HERE;
@@ -651,7 +650,9 @@ typedef struct UserDef_Experimental {
char use_extended_asset_browser;
char use_override_templates;
char use_named_attribute_nodes;
- char _pad[1];
+ char use_select_nearest_on_first_click;
+ char enable_eevee_next;
+ // char _pad[0];
/** `makesdna` does not allow empty structs. */
} UserDef_Experimental;
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index e507831424f..2afaf04a8d7 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -122,10 +122,10 @@ set(SRC
../DNA_camera_defaults.h
../DNA_collection_defaults.h
../DNA_curve_defaults.h
+ ../DNA_curves_defaults.h
../DNA_defaults.h
../DNA_fluid_defaults.h
../DNA_gpencil_modifier_defaults.h
- ../DNA_curves_defaults.h
../DNA_image_defaults.h
../DNA_lattice_defaults.h
../DNA_light_defaults.h
diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c
index b7f942e2502..197a863db72 100644
--- a/source/blender/makesdna/intern/dna_defaults.c
+++ b/source/blender/makesdna/intern/dna_defaults.c
@@ -316,6 +316,7 @@ SDNA_DEFAULT_DECL_STRUCT(LengthGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(DashGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(DashGpencilModifierSegment);
SDNA_DEFAULT_DECL_STRUCT(ShrinkwrapGpencilModifierData);
+SDNA_DEFAULT_DECL_STRUCT(EnvelopeGpencilModifierData);
#undef SDNA_DEFAULT_DECL_STRUCT
@@ -555,6 +556,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
SDNA_DEFAULT_DECL(DashGpencilModifierData),
SDNA_DEFAULT_DECL(DashGpencilModifierSegment),
SDNA_DEFAULT_DECL(ShrinkwrapGpencilModifierData),
+ SDNA_DEFAULT_DECL(EnvelopeGpencilModifierData),
};
#undef SDNA_DEFAULT_DECL
#undef SDNA_DEFAULT_DECL_EX
diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h
index 7b155df3084..b2896c80db3 100644
--- a/source/blender/makesdna/intern/dna_rename_defs.h
+++ b/source/blender/makesdna/intern/dna_rename_defs.h
@@ -61,6 +61,7 @@ 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(CustomDataExternal, filename, filepath)
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)
@@ -86,9 +87,11 @@ DNA_STRUCT_RENAME_ELEM(Object, dup_group, instance_collection)
DNA_STRUCT_RENAME_ELEM(Object, dupfacesca, instance_faces_scale)
DNA_STRUCT_RENAME_ELEM(Object, restrictflag, visibility_flag)
DNA_STRUCT_RENAME_ELEM(Object, size, scale)
+DNA_STRUCT_RENAME_ELEM(ParticleSettings, child_nbr, child_percent)
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(ParticleSettings, ren_child_nbr, child_render_percent)
DNA_STRUCT_RENAME_ELEM(RigidBodyWorld, steps_per_second, substeps_per_frame)
DNA_STRUCT_RENAME_ELEM(RenderData, bake_filter, bake_margin)
DNA_STRUCT_RENAME_ELEM(SpaceSeq, overlay_type, overlay_frame_type)
diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h
index d4c38060e1b..3ebcae5f947 100644
--- a/source/blender/makesrna/RNA_types.h
+++ b/source/blender/makesrna/RNA_types.h
@@ -179,7 +179,7 @@ typedef enum PropertySubType {
/* Make sure enums are updated with these */
/* HIGHEST FLAG IN USE: 1 << 31
- * FREE FLAGS: 2, 9, 11, 13, 14, 15, 30 */
+ * FREE FLAGS: 2, 9, 11, 13, 14, 15. */
typedef enum PropertyFlag {
/**
* Editable means the property is editable in the user
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 4e3a4aae727..9980545c19d 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -236,6 +236,10 @@ if(WITH_IMAGE_HDR)
add_definitions(-DWITH_HDR)
endif()
+if(WITH_IMAGE_WEBP)
+ add_definitions(-DWITH_WEBP)
+endif()
+
if(WITH_AUDASPACE)
add_definitions(-DWITH_AUDASPACE)
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index a9725da7841..82d90a5c54b 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -137,7 +137,11 @@ const struct IDFilterEnumPropertyItem rna_enum_id_type_filter_items[] = {
ICON_OUTLINER_COLLECTION,
"Collections",
"Show Collection data-blocks"},
- {FILTER_ID_CV, "filter_hair", ICON_CURVES_DATA, "Hairs", "Show/hide Hair data-blocks"},
+ {FILTER_ID_CV,
+ "filter_curves",
+ ICON_CURVES_DATA,
+ "Hair Curves",
+ "Show/hide Curves data-blocks"},
{FILTER_ID_IM, "filter_image", ICON_IMAGE_DATA, "Images", "Show Image data-blocks"},
{FILTER_ID_LA, "filter_light", ICON_LIGHT_DATA, "Lights", "Show Light data-blocks"},
{FILTER_ID_LP,
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 943b2fccbb7..b4617321f44 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -160,7 +160,7 @@ void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
bool RNA_pointer_is_null(const PointerRNA *ptr)
{
- return !((ptr->data != NULL) && (ptr->owner_id != NULL) && (ptr->type != NULL));
+ return (ptr->data == NULL) || (ptr->owner_id == NULL) || (ptr->type == NULL);
}
static void rna_pointer_inherit_id(StructRNA *type, PointerRNA *parent, PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 6052a742ad5..c86a852b0ea 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -33,7 +33,7 @@ static const EnumPropertyItem prop_direction_items[] = {
#ifdef RNA_RUNTIME
static const EnumPropertyItem prop_smooth_direction_items[] = {
- {0, "SMOOTH", ICON_ADD, "Smooth", "Smooth the surfae"},
+ {0, "SMOOTH", ICON_ADD, "Smooth", "Smooth the surface"},
{BRUSH_DIR_IN,
"ENHANCE_DETAILS",
ICON_REMOVE,
@@ -247,6 +247,7 @@ const EnumPropertyItem rna_enum_brush_curves_sculpt_tool_items[] = {
{CURVES_SCULPT_TOOL_COMB, "COMB", ICON_NONE, "Comb", ""},
{CURVES_SCULPT_TOOL_DELETE, "DELETE", ICON_NONE, "Delete", ""},
{CURVES_SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", ICON_NONE, "Snake Hook", ""},
+ {CURVES_SCULPT_TOOL_ADD, "ADD", ICON_NONE, "Add", ""},
{CURVES_SCULPT_TOOL_TEST1, "TEST1", ICON_NONE, "Test 1", ""},
{CURVES_SCULPT_TOOL_TEST2, "TEST2", ICON_NONE, "Test 2", ""},
{0, NULL, 0, NULL, NULL},
@@ -1913,6 +1914,20 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
}
+static void rna_def_curves_sculpt_options(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "BrushCurvesSculptSettings", NULL);
+ RNA_def_struct_sdna(srna, "BrushCurvesSculptSettings");
+ RNA_def_struct_ui_text(srna, "Curves Sculpt Brush Settings", "");
+
+ prop = RNA_def_property(srna, "add_amount", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, INT32_MAX);
+ RNA_def_property_ui_text(prop, "Add Amount", "Number of curves added by the Add brush");
+}
+
static void rna_def_brush(BlenderRNA *brna)
{
StructRNA *srna;
@@ -3491,6 +3506,11 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "gpencil_settings");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Gpencil Settings", "");
+
+ prop = RNA_def_property(srna, "curves_sculpt_settings", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "BrushCurvesSculptSettings");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Curves Sculpt Settings", "");
}
/**
@@ -3577,6 +3597,7 @@ void RNA_def_brush(BlenderRNA *brna)
rna_def_vertex_paint_capabilities(brna);
rna_def_weight_paint_capabilities(brna);
rna_def_gpencil_options(brna);
+ rna_def_curves_sculpt_options(brna);
rna_def_brush_texture_slot(brna);
rna_def_operator_stroke_element(brna);
}
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 31b67d4eb19..840674c7bc6 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -173,11 +173,7 @@ static char *rna_ColorRamp_path(PointerRNA *ptr)
char *node_path;
for (node = ntree->nodes.first; node; node = node->next) {
- if (ELEM(node->type,
- SH_NODE_VALTORGB,
- CMP_NODE_VALTORGB,
- TEX_NODE_VALTORGB,
- GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP)) {
+ if (ELEM(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) {
if (node->storage == ptr->data) {
/* all node color ramp properties called 'color_ramp'
* prepend path from ID to the node
@@ -304,11 +300,7 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
- if (ELEM(node->type,
- SH_NODE_VALTORGB,
- CMP_NODE_VALTORGB,
- TEX_NODE_VALTORGB,
- GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP)) {
+ if (ELEM(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) {
BKE_ntree_update_tag_node_property(ntree, node);
ED_node_tree_propagate_change(NULL, bmain, ntree);
}
@@ -613,6 +605,11 @@ static void rna_ColorManagedColorspaceSettings_reload_update(Main *bmain,
{
ID *id = ptr->owner_id;
+ if (!id) {
+ /* Happens for color space settings on operators. */
+ return;
+ }
+
if (GS(id->name) == ID_IM) {
Image *ima = (Image *)id;
diff --git a/source/blender/makesrna/intern/rna_curve_api.c b/source/blender/makesrna/intern/rna_curve_api.c
index f31e72ce652..b7be5293578 100644
--- a/source/blender/makesrna/intern/rna_curve_api.c
+++ b/source/blender/makesrna/intern/rna_curve_api.c
@@ -43,22 +43,19 @@ static void rna_Nurb_valid_message(Nurb *nu, int direction, int *result_len, con
int pnts;
short order, flag;
- const char *dir;
if (direction == 0) {
pnts = nu->pntsu;
order = nu->orderu;
flag = nu->flagu;
- dir = "U";
}
else {
pnts = nu->pntsv;
order = nu->orderv;
flag = nu->flagv;
- dir = "V";
}
char buf[64];
- if (BKE_nurb_valid_message(pnts, order, flag, type, is_surf, dir, buf, sizeof(buf))) {
+ if (BKE_nurb_valid_message(pnts, order, flag, type, is_surf, direction, buf, sizeof(buf))) {
const int buf_len = strlen(buf);
*r_result = BLI_strdupn(buf, buf_len);
*result_len = buf_len;
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index ce0598d355d..dab3cd68d4c 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -2446,8 +2446,10 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "cfl_condition", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "cfl_condition");
RNA_def_property_range(prop, 0.0, 10.0);
- RNA_def_property_ui_text(
- prop, "CFL", "Maximal velocity per cell (higher value results in greater timesteps)");
+ RNA_def_property_ui_text(prop,
+ "CFL",
+ "Maximal velocity per cell (greater CFL numbers will minimize the "
+ "number of simulation steps and the computation time.)");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Fluid_datacache_reset");
prop = RNA_def_property(srna, "use_adaptive_timesteps", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c
index 33c0b29f6d0..edeb7443957 100644
--- a/source/blender/makesrna/intern/rna_gpencil_modifier.c
+++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c
@@ -79,6 +79,11 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
ICON_MOD_DASH,
"Dot Dash",
"Generate dot-dash styled strokes"},
+ {eGpencilModifierType_Envelope,
+ "GP_ENVELOPE",
+ ICON_MOD_SKIN,
+ "Envelope",
+ "Create an envelope shape"},
{eGpencilModifierType_Length,
"GP_LENGTH",
ICON_MOD_LENGTH,
@@ -208,6 +213,25 @@ static const EnumPropertyItem gpencil_length_mode_items[] = {
{GP_LENGTH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Length in geometry space"},
{0, NULL, 0, NULL, NULL},
};
+
+static const EnumPropertyItem gpencil_envelope_mode_items[] = {
+ {GP_ENVELOPE_DEFORM,
+ "DEFORM",
+ 0,
+ "Deform",
+ "Deform the stroke to best match the envelope shape"},
+ {GP_ENVELOPE_SEGMENTS,
+ "SEGMENTS",
+ 0,
+ "Segments",
+ "Add segments to create the envelope. Keep the original stroke"},
+ {GP_ENVELOPE_FILLS,
+ "FILLS",
+ 0,
+ "Fills",
+ "Add fill segments to create the envelope. Don't keep the original stroke"},
+ {0, NULL, 0, NULL, NULL},
+};
#endif
#ifdef RNA_RUNTIME
@@ -279,6 +303,8 @@ static StructRNA *rna_GpencilModifier_refine(struct PointerRNA *ptr)
return &RNA_LineartGpencilModifier;
case eGpencilModifierType_Dash:
return &RNA_DashGpencilModifierData;
+ case eGpencilModifierType_Envelope:
+ return &RNA_EnvelopeGpencilModifier;
/* Default */
case eGpencilModifierType_None:
case NUM_GREASEPENCIL_MODIFIER_TYPES:
@@ -355,6 +381,7 @@ 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);
+RNA_GP_MOD_VGROUP_NAME_SET(Envelope, vgname);
# undef RNA_GP_MOD_VGROUP_NAME_SET
@@ -775,6 +802,16 @@ static void rna_ShrinkwrapGpencilModifier_face_cull_set(struct PointerRNA *ptr,
swm->shrink_opts = (swm->shrink_opts & ~MOD_SHRINKWRAP_CULL_TARGET_MASK) | value;
}
+static void rna_EnvelopeGpencilModifier_material_set(PointerRNA *ptr,
+ PointerRNA value,
+ struct ReportList *reports)
+{
+ EnvelopeGpencilModifierData *emd = (EnvelopeGpencilModifierData *)ptr->data;
+ Material **ma_target = &emd->material;
+
+ rna_GpencilModifier_material_set(ptr, value, ma_target, reports);
+}
+
#else
static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
@@ -3676,7 +3713,7 @@ static void rna_def_modifier_gpencildash(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "gap", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 1, INT16_MAX);
+ RNA_def_property_range(prop, 0, INT16_MAX);
RNA_def_property_ui_text(prop, "Gap", "The number of points skipped after this segment");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
@@ -3968,6 +4005,112 @@ static void rna_def_modifier_gpencilshrinkwrap(BlenderRNA *brna)
RNA_define_lib_overridable(false);
}
+static void rna_def_modifier_gpencilenvelope(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "EnvelopeGpencilModifier", "GpencilModifier");
+ RNA_def_struct_ui_text(srna, "Envelope Modifier", "Envelope stroke effect modifier");
+ RNA_def_struct_sdna(srna, "EnvelopeGpencilModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_SKIN);
+
+ RNA_define_lib_overridable(true);
+
+ 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_EnvelopeGpencilModifier_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_EnvelopeGpencilModifier_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, "spread", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "spread");
+ RNA_def_property_range(prop, 1, INT_MAX);
+ RNA_def_property_ui_text(
+ prop, "Spread Length", "The number of points to skip to create straight segments");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, gpencil_envelope_mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "Algorithm to use for generating the envelope");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "mat_nr", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "mat_nr");
+ RNA_def_property_range(prop, -1, INT16_MAX);
+ RNA_def_property_ui_text(prop, "Material Index", "The material to use for the new strokes");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "thickness", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "thickness");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1, 10, 3);
+ RNA_def_property_ui_text(prop, "Thickness", "Multiplier for the thickness of the new strokes");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "strength");
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1, 10, 3);
+ RNA_def_property_ui_text(prop, "Strength", "Multiplier for the strength of the new strokes");
+ 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_ENVELOPE_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_ENVELOPE_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_ENVELOPE_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", GP_ENVELOPE_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_ENVELOPE_INVERT_LAYERPASS);
+ RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
+ RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
+
+ RNA_define_lib_overridable(false);
+}
+
void RNA_def_greasepencil_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@@ -4058,6 +4201,7 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna)
rna_def_modifier_gpencillength(brna);
rna_def_modifier_gpencildash(brna);
rna_def_modifier_gpencilshrinkwrap(brna);
+ rna_def_modifier_gpencilenvelope(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 56e23278176..3a93a44e0d1 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -13,6 +13,7 @@
#include "BLI_utildefines.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_node_tree_update.h"
#include "DEG_depsgraph.h"
@@ -238,8 +239,8 @@ static int rna_Image_file_format_get(PointerRNA *ptr)
{
Image *image = (Image *)ptr->data;
ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
- int imtype = BKE_image_ftype_to_imtype(ibuf ? ibuf->ftype : IMB_FTYPE_NONE,
- ibuf ? &ibuf->foptions : NULL);
+ int imtype = BKE_ftype_to_imtype(ibuf ? ibuf->ftype : IMB_FTYPE_NONE,
+ ibuf ? &ibuf->foptions : NULL);
BKE_image_release_ibuf(image, ibuf, NULL);
@@ -251,7 +252,7 @@ static void rna_Image_file_format_set(PointerRNA *ptr, int value)
Image *image = (Image *)ptr->data;
if (BKE_imtype_is_movie(value) == 0) { /* should be able to throw an error here */
ImbFormatOptions options;
- int ftype = BKE_image_imtype_to_ftype(value, &options);
+ int ftype = BKE_imtype_to_ftype(value, &options);
BKE_image_file_format_set(image, ftype, &options);
}
}
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 92e3254765c..0b188b2b3db 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -25,7 +25,9 @@
#ifdef RNA_RUNTIME
# include "BKE_image.h"
+# include "BKE_image_format.h"
# include "BKE_main.h"
+# include "BKE_scene.h"
# include <errno.h>
# include "IMB_colormanagement.h"
@@ -68,19 +70,23 @@ static void rna_Image_save_render(
else {
ImBuf *write_ibuf;
- write_ibuf = IMB_colormanagement_imbuf_for_write(
- ibuf, true, true, &scene->view_settings, &scene->display_settings, &scene->r.im_format);
+ ImageFormatData image_format;
+ BKE_image_format_init_for_write(&image_format, scene, NULL);
- write_ibuf->planes = scene->r.im_format.planes;
+ write_ibuf = IMB_colormanagement_imbuf_for_write(ibuf, true, true, &image_format);
+
+ write_ibuf->planes = image_format.planes;
write_ibuf->dither = scene->r.dither_intensity;
- if (!BKE_imbuf_write(write_ibuf, path, &scene->r.im_format)) {
+ if (!BKE_imbuf_write(write_ibuf, path, &image_format)) {
BKE_reportf(reports, RPT_ERROR, "Could not write image: %s, '%s'", strerror(errno), path);
}
if (write_ibuf != ibuf) {
IMB_freeImBuf(write_ibuf);
}
+
+ BKE_image_format_free(&image_format);
}
BKE_image_release_ibuf(image, ibuf, lock);
@@ -96,14 +102,14 @@ static void rna_Image_save(Image *image, Main *bmain, bContext *C, ReportList *r
ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
if (ibuf) {
- char filename[FILE_MAX];
- BLI_strncpy(filename, image->filepath, sizeof(filename));
- BLI_path_abs(filename, ID_BLEND_PATH(bmain, &image->id));
+ char filepath[FILE_MAX];
+ BLI_strncpy(filepath, image->filepath, sizeof(filepath));
+ BLI_path_abs(filepath, ID_BLEND_PATH(bmain, &image->id));
/* NOTE: we purposefully ignore packed files here,
* developers need to explicitly write them via 'packed_files' */
- if (IMB_saveiff(ibuf, filename, ibuf->flags)) {
+ if (IMB_saveiff(ibuf, filepath, ibuf->flags)) {
image->type = IMA_TYPE_IMAGE;
if (image->source == IMA_SRC_GENERATED) {
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index c59fd2a0535..84f083cb37a 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -393,7 +393,15 @@ char *rna_TextureSlot_path(struct PointerRNA *ptr);
char *rna_Node_ImageUser_path(struct PointerRNA *ptr);
/* Set U.is_dirty and redraw. */
+
+/**
+ * Use single function so we can more easily break-point it.
+ */
void rna_userdef_is_dirty_update_impl(void);
+/**
+ * Use as a fallback update handler to ensure #U.runtime.is_dirty is set.
+ * So the preferences are saved when modified.
+ */
void rna_userdef_is_dirty_update(struct Main *bmain, struct Scene *scene, struct PointerRNA *ptr);
/* API functions */
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index b12b33c67af..2ef2e776842 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1074,7 +1074,7 @@ static void rna_MultiresModifier_filepath_get(PointerRNA *ptr, char *value)
Object *ob = (Object *)ptr->owner_id;
CustomDataExternal *external = ((Mesh *)ob->data)->ldata.external;
- BLI_strncpy(value, (external) ? external->filename : "", sizeof(external->filename));
+ BLI_strncpy(value, (external) ? external->filepath : "", sizeof(external->filepath));
}
static void rna_MultiresModifier_filepath_set(PointerRNA *ptr, const char *value)
@@ -1082,8 +1082,8 @@ static void rna_MultiresModifier_filepath_set(PointerRNA *ptr, const char *value
Object *ob = (Object *)ptr->owner_id;
CustomDataExternal *external = ((Mesh *)ob->data)->ldata.external;
- if (external && !STREQ(external->filename, value)) {
- BLI_strncpy(external->filename, value, sizeof(external->filename));
+ if (external && !STREQ(external->filepath, value)) {
+ BLI_strncpy(external->filepath, value, sizeof(external->filepath));
multires_force_external_reload(ob);
}
}
@@ -1093,7 +1093,7 @@ static int rna_MultiresModifier_filepath_length(PointerRNA *ptr)
Object *ob = (Object *)ptr->owner_id;
CustomDataExternal *external = ((Mesh *)ob->data)->ldata.external;
- return strlen((external) ? external->filename : "");
+ return strlen((external) ? external->filepath : "");
}
static int rna_ShrinkwrapModifier_face_cull_get(PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index f212b4a1d23..70b335446fc 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -461,30 +461,6 @@ const EnumPropertyItem rna_enum_node_filter_items[] = {
{0, NULL, 0, NULL, NULL},
};
-static const EnumPropertyItem rna_node_geometry_attribute_randomize_operation_items[] = {
- {GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE,
- "REPLACE_CREATE",
- ICON_NONE,
- "Replace/Create",
- "Replace the value and data type of an existing attribute, or create a new one"},
- {GEO_NODE_ATTRIBUTE_RANDOMIZE_ADD,
- "ADD",
- ICON_NONE,
- "Add",
- "Add the random values to the existing attribute values"},
- {GEO_NODE_ATTRIBUTE_RANDOMIZE_SUBTRACT,
- "SUBTRACT",
- ICON_NONE,
- "Subtract",
- "Subtract random values from the existing attribute values"},
- {GEO_NODE_ATTRIBUTE_RANDOMIZE_MULTIPLY,
- "MULTIPLY",
- ICON_NONE,
- "Multiply",
- "Multiply the existing attribute values with the random values"},
- {0, NULL, 0, NULL, NULL},
-};
-
static const EnumPropertyItem rna_node_geometry_curve_handle_type_items[] = {
{GEO_NODE_CURVE_HANDLE_FREE,
"FREE",
@@ -547,73 +523,8 @@ static EnumPropertyItem rna_node_geometry_mesh_circle_fill_type_items[] = {
};
#endif
-#define ITEM_ATTRIBUTE \
- { \
- GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE, "ATTRIBUTE", 0, "Attribute", "" \
- }
-#define ITEM_FLOAT \
- { \
- GEO_NODE_ATTRIBUTE_INPUT_FLOAT, "FLOAT", 0, "Float", "" \
- }
-#define ITEM_VECTOR \
- { \
- GEO_NODE_ATTRIBUTE_INPUT_VECTOR, "VECTOR", 0, "Vector", "" \
- }
-#define ITEM_COLOR \
- { \
- GEO_NODE_ATTRIBUTE_INPUT_COLOR, "COLOR", 0, "Color", "" \
- }
-#define ITEM_INTEGER \
- { \
- GEO_NODE_ATTRIBUTE_INPUT_INTEGER, "INTEGER", 0, "Integer", "" \
- }
-#define ITEM_BOOLEAN \
- { \
- GEO_NODE_ATTRIBUTE_INPUT_BOOLEAN, "BOOLEAN", 0, "Boolean", "" \
- }
-
-/* Used in both runtime and static code. */
-static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_any[] = {
- ITEM_ATTRIBUTE,
- ITEM_FLOAT,
- ITEM_VECTOR,
- ITEM_COLOR,
- ITEM_INTEGER,
- ITEM_BOOLEAN,
- {0, NULL, 0, NULL, NULL},
-};
-
#ifndef RNA_RUNTIME
-static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_vector[] = {
- ITEM_ATTRIBUTE,
- ITEM_VECTOR,
- {0, NULL, 0, NULL, NULL},
-};
-static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_float_vector[] = {
- ITEM_ATTRIBUTE,
- ITEM_FLOAT,
- ITEM_VECTOR,
- {0, NULL, 0, NULL, NULL},
-};
-static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_float[] = {
- ITEM_ATTRIBUTE,
- ITEM_FLOAT,
- {0, NULL, 0, NULL, NULL},
-};
-static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_int[] = {
- ITEM_ATTRIBUTE,
- ITEM_INTEGER,
- {0, NULL, 0, NULL, NULL},
-};
-static const EnumPropertyItem rna_node_geometry_attribute_input_type_items_no_boolean[] = {
- ITEM_ATTRIBUTE,
- ITEM_FLOAT,
- ITEM_VECTOR,
- ITEM_COLOR,
- {0, NULL, 0, NULL, NULL},
-};
-
#endif
#undef ITEM_ATTRIBUTE
@@ -2170,31 +2081,6 @@ static const EnumPropertyItem *rna_FunctionNodeCompare_operation_itemf(bContext
}
}
-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),
- bool *r_free)
-{
- *r_free = true;
- return itemf_function_check(rna_enum_attribute_type_items, attribute_clamp_type_supported);
-}
-
-static bool attribute_random_type_supported(const EnumPropertyItem *item)
-{
- return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_BOOL, CD_PROP_INT32);
-}
-static const EnumPropertyItem *rna_GeometryNodeAttributeRandom_type_itemf(
- bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- *r_free = true;
- return itemf_function_check(rna_enum_attribute_type_items, attribute_random_type_supported);
-}
-
static bool random_value_type_supported(const EnumPropertyItem *item)
{
return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_BOOL, CD_PROP_INT32);
@@ -2222,49 +2108,6 @@ static const EnumPropertyItem *rna_GeoNodeAccumulateField_type_itemf(bContext *U
return itemf_function_check(rna_enum_attribute_type_items, accumulate_field_type_supported);
}
-static const EnumPropertyItem *rna_GeometryNodeAttributeRandomize_operation_itemf(
- bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
-{
- bNode *node = ptr->data;
- const NodeAttributeRandomize *node_storage = (NodeAttributeRandomize *)node->storage;
- const CustomDataType data_type = (CustomDataType)node_storage->data_type;
-
- EnumPropertyItem *item_array = NULL;
- int items_len = 0;
- for (const EnumPropertyItem *item = rna_node_geometry_attribute_randomize_operation_items;
- item->identifier != NULL;
- item++) {
- if (data_type == CD_PROP_BOOL) {
- if (item->value == GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE) {
- RNA_enum_item_add(&item_array, &items_len, item);
- }
- }
- else {
- RNA_enum_item_add(&item_array, &items_len, item);
- }
- }
- RNA_enum_item_end(&item_array, &items_len);
-
- *r_free = true;
- return item_array;
-}
-
-static void rna_GeometryNodeAttributeRandomize_data_type_update(Main *bmain,
- Scene *scene,
- PointerRNA *ptr)
-{
- bNode *node = ptr->data;
- NodeAttributeRandomize *node_storage = (NodeAttributeRandomize *)node->storage;
-
- /* The boolean data type has no extra operations besides,
- * replace, so make sure the enum value is set properly. */
- if (node_storage->data_type == CD_PROP_BOOL) {
- node_storage->operation = GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE;
- }
-
- rna_Node_socket_update(bmain, scene, ptr);
-}
-
static void rna_GeometryNodeCompare_data_type_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
bNode *node = ptr->data;
@@ -2289,37 +2132,18 @@ static void rna_GeometryNodeCompare_data_type_update(Main *bmain, Scene *scene,
rna_Node_socket_update(bmain, scene, ptr);
}
-static bool attribute_convert_type_supported(const EnumPropertyItem *item)
-{
- return ELEM(item->value,
- CD_AUTO_FROM_NAME,
- CD_PROP_FLOAT,
- CD_PROP_FLOAT2,
- CD_PROP_FLOAT3,
- CD_PROP_COLOR,
- CD_PROP_BOOL,
- CD_PROP_INT32);
-}
-static const EnumPropertyItem *rna_GeometryNodeAttributeConvert_type_itemf(
- bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- *r_free = true;
- return itemf_function_check(rna_enum_attribute_type_with_auto_items,
- attribute_convert_type_supported);
-}
-
-static bool attribute_fill_type_supported(const EnumPropertyItem *item)
+static bool generic_attribute_type_supported(const EnumPropertyItem *item)
{
return ELEM(
item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_COLOR, CD_PROP_BOOL, CD_PROP_INT32);
}
-static const EnumPropertyItem *rna_GeometryNodeAttributeFill_type_itemf(bContext *UNUSED(C),
+static const EnumPropertyItem *rna_GeometryNodeAttributeType_type_itemf(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
bool *r_free)
{
*r_free = true;
- return itemf_function_check(rna_enum_attribute_type_items, attribute_fill_type_supported);
+ return itemf_function_check(rna_enum_attribute_type_items, generic_attribute_type_supported);
}
static bool transfer_attribute_type_supported(const EnumPropertyItem *item)
@@ -2327,7 +2151,6 @@ static bool transfer_attribute_type_supported(const EnumPropertyItem *item)
return ELEM(
item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_COLOR, CD_PROP_BOOL, CD_PROP_INT32);
}
-
static const EnumPropertyItem *rna_NodeGeometryTransferAttribute_type_itemf(
bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -2346,122 +2169,6 @@ static const EnumPropertyItem *rna_GeometryNodeAttributeStatistic_type_itemf(
return itemf_function_check(rna_enum_attribute_type_items, attribute_statistic_type_supported);
}
-/**
- * This bit of ugly code makes sure the float / attribute option shows up instead of
- * vector / attribute if the node uses an operation that uses a float for input B or C.
- */
-static const EnumPropertyItem *rna_GeometryNodeAttributeVectorMath_input_type_b_itemf(
- bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
-{
- bNode *node = ptr->data;
- NodeAttributeVectorMath *node_storage = (NodeAttributeVectorMath *)node->storage;
-
- EnumPropertyItem *item_array = NULL;
- int items_len = 0;
- for (const EnumPropertyItem *item = rna_node_geometry_attribute_input_type_items_any;
- item->identifier != NULL;
- item++) {
- if (item->value == GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE) {
- RNA_enum_item_add(&item_array, &items_len, item);
- }
- else if (item->value == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) {
- if (node_storage->operation == NODE_VECTOR_MATH_SCALE) {
- RNA_enum_item_add(&item_array, &items_len, item);
- }
- }
- else if (item->value == GEO_NODE_ATTRIBUTE_INPUT_VECTOR) {
- if (node_storage->operation != NODE_VECTOR_MATH_SCALE) {
- RNA_enum_item_add(&item_array, &items_len, item);
- }
- }
- }
- RNA_enum_item_end(&item_array, &items_len);
-
- *r_free = true;
- return item_array;
-}
-
-static const EnumPropertyItem *rna_GeometryNodeAttributeVectorMath_input_type_c_itemf(
- bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
-{
- bNode *node = ptr->data;
- NodeAttributeVectorMath *node_storage = (NodeAttributeVectorMath *)node->storage;
-
- EnumPropertyItem *item_array = NULL;
- int items_len = 0;
- for (const EnumPropertyItem *item = rna_node_geometry_attribute_input_type_items_any;
- item->identifier != NULL;
- item++) {
- if (item->value == GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE) {
- RNA_enum_item_add(&item_array, &items_len, item);
- }
- else if (item->value == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) {
- if (node_storage->operation == NODE_VECTOR_MATH_REFRACT) {
- RNA_enum_item_add(&item_array, &items_len, item);
- }
- }
- else if (item->value == GEO_NODE_ATTRIBUTE_INPUT_VECTOR) {
- if (node_storage->operation != NODE_VECTOR_MATH_REFRACT) {
- RNA_enum_item_add(&item_array, &items_len, item);
- }
- }
- }
- RNA_enum_item_end(&item_array, &items_len);
-
- *r_free = true;
- return item_array;
-}
-
-static void rna_GeometryNodeAttributeVectorMath_operation_update(Main *bmain,
- Scene *scene,
- PointerRNA *ptr)
-{
- bNode *node = ptr->data;
- NodeAttributeVectorMath *node_storage = (NodeAttributeVectorMath *)node->storage;
-
- const NodeVectorMathOperation operation = (NodeVectorMathOperation)node_storage->operation;
-
- /* The scale operation can't use a vector input, so reset
- * the input type enum in case it's set to vector. */
- if (operation == NODE_VECTOR_MATH_SCALE) {
- if (node_storage->input_type_b == GEO_NODE_ATTRIBUTE_INPUT_VECTOR) {
- node_storage->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
- }
- }
-
- /* Scale is also the only operation that uses the float input type, so a
- * a check is also necessary for the other direction. */
- if (operation != NODE_VECTOR_MATH_SCALE) {
- if (node_storage->input_type_b == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) {
- node_storage->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
- }
- }
-
- rna_Node_socket_update(bmain, scene, ptr);
-}
-
-static bool attribute_map_range_type_supported(const EnumPropertyItem *item)
-{
- return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3);
-}
-static const EnumPropertyItem *rna_GeometryNodeAttributeMapRange_type_itemf(
- bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- *r_free = true;
- return itemf_function_check(rna_enum_attribute_type_items, attribute_map_range_type_supported);
-}
-
-static bool attribute_curve_map_type_supported(const EnumPropertyItem *item)
-{
- return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_COLOR);
-}
-static const EnumPropertyItem *rna_GeometryNodeAttributeCurveMap_type_itemf(
- bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- *r_free = true;
- return itemf_function_check(rna_enum_attribute_type_items, attribute_curve_map_type_supported);
-}
-
static StructRNA *rna_ShaderNode_register(Main *bmain,
ReportList *reports,
void *data,
@@ -9636,71 +9343,6 @@ static void def_fn_random_value(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
-static void def_geo_attribute_randomize(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeAttributeRandomize", "storage");
-
- prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "data_type");
- RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeRandom_type_itemf");
- RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
- RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute");
- RNA_def_property_update(
- prop, NC_NODE | NA_EDITED, "rna_GeometryNodeAttributeRandomize_data_type_update");
-
- prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "operation");
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_randomize_operation_items);
- RNA_def_property_enum_funcs(
- prop, NULL, NULL, "rna_GeometryNodeAttributeRandomize_operation_itemf");
- RNA_def_property_enum_default(prop, GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE);
- RNA_def_property_ui_text(prop, "Operation", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
-static void def_geo_attribute_fill(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom1");
- RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeFill_type_itemf");
- RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
- RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
-
- prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom2");
- RNA_def_property_enum_items(prop, rna_enum_attribute_domain_with_auto_items);
- RNA_def_property_enum_default(prop, ATTR_DOMAIN_AUTO);
- RNA_def_property_ui_text(prop, "Domain", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-}
-
-static void def_geo_attribute_convert(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeAttributeConvert", "storage");
-
- prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_enum_attribute_type_with_auto_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeConvert_type_itemf");
- RNA_def_property_enum_default(prop, CD_AUTO_FROM_NAME);
- RNA_def_property_ui_text(prop, "Data Type", "The data type to save the result attribute with");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
-
- prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_enum_attribute_domain_with_auto_items);
- RNA_def_property_enum_default(prop, ATTR_DOMAIN_AUTO);
- RNA_def_property_ui_text(prop, "Domain", "The geometry domain to save the result attribute in");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-}
-
static void def_geo_attribute_statistic(StructRNA *srna)
{
PropertyRNA *prop;
@@ -9724,229 +9366,6 @@ static void def_geo_attribute_statistic(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
-static void def_geo_attribute_math(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeAttributeMath", "storage");
-
- prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "operation");
- RNA_def_property_enum_items(prop, rna_enum_node_math_items);
- RNA_def_property_enum_default(prop, NODE_MATH_ADD);
- 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, "input_type_a", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_a");
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
- RNA_def_property_ui_text(prop, "Input Type A", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_b", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_b");
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
- RNA_def_property_ui_text(prop, "Input Type B", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_c", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_c");
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
- RNA_def_property_ui_text(prop, "Input Type C", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
-static void def_geo_attribute_vector_math(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeAttributeVectorMath", "storage");
-
- prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "operation");
- RNA_def_property_enum_items(prop, rna_enum_node_vec_math_items);
- RNA_def_property_ui_text(prop, "Operation", "");
- RNA_def_property_update(
- prop, NC_NODE | NA_EDITED, "rna_GeometryNodeAttributeVectorMath_operation_update");
-
- prop = RNA_def_property(srna, "input_type_a", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_a");
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
- RNA_def_property_ui_text(prop, "Input Type A", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_b", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_b");
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_any);
- RNA_def_property_enum_funcs(
- prop, NULL, NULL, "rna_GeometryNodeAttributeVectorMath_input_type_b_itemf");
- RNA_def_property_ui_text(prop, "Input Type B", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_c", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_c");
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_any);
- RNA_def_property_enum_funcs(
- prop, NULL, NULL, "rna_GeometryNodeAttributeVectorMath_input_type_c_itemf");
- RNA_def_property_ui_text(prop, "Input Type C", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
-static void def_geo_attribute_map_range(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeAttributeMapRange", "storage");
-
- 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_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeMapRange_type_itemf");
- RNA_def_property_ui_text(prop, "Data Type", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "interpolation_type", PROP_ENUM, PROP_NONE);
- 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");
-}
-
-static void def_geo_point_instance(StructRNA *srna)
-{
- static const EnumPropertyItem instance_type_items[] = {
- {GEO_NODE_POINT_INSTANCE_TYPE_OBJECT,
- "OBJECT",
- ICON_NONE,
- "Object",
- "Instance an individual object on all points"},
- {GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION,
- "COLLECTION",
- ICON_NONE,
- "Collection",
- "Instance an entire collection on all points"},
- {GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY,
- "GEOMETRY",
- ICON_NONE,
- "Geometry",
- "Copy geometry to all points"},
- {0, NULL, 0, NULL, NULL},
- };
-
- PropertyRNA *prop;
- RNA_def_struct_sdna_from(srna, "NodeGeometryPointInstance", "storage");
-
- prop = RNA_def_property(srna, "instance_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "instance_type");
- RNA_def_property_enum_items(prop, instance_type_items);
- RNA_def_property_enum_default(prop, GEO_NODE_POINT_INSTANCE_TYPE_OBJECT);
- RNA_def_property_ui_text(prop, "Instance Type", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "use_whole_collection", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION);
- RNA_def_property_ui_text(prop, "Whole Collection", "Instance entire collection on each point");
- RNA_def_property_update(prop, 0, "rna_Node_socket_update");
-}
-
-static void def_geo_attribute_mix(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeAttributeMix", "storage");
-
- prop = RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_enum_ramp_blend_items);
- RNA_def_property_enum_default(prop, MA_RAMP_BLEND);
- RNA_def_property_ui_text(prop, "Blending Mode", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "input_type_factor", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
- RNA_def_property_ui_text(prop, "Input Type Factor", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_a", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_no_boolean);
- RNA_def_property_ui_text(prop, "Input Type A", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_b", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_no_boolean);
- RNA_def_property_ui_text(prop, "Input Type B", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
-static void def_geo_attribute_clamp(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeAttributeClamp", "storage");
-
- 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_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeClamp_type_itemf");
- RNA_def_property_ui_text(prop, "Data Type", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_enum_node_clamp_items);
- RNA_def_property_enum_default(prop, NODE_CLAMP_MINMAX);
- RNA_def_property_ui_text(prop, "Operation", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-}
-
-static void def_geo_attribute_attribute_compare(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeAttributeCompare", "storage");
-
- 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_COMPARE_GREATER_THAN);
- 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, "input_type_a", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_no_boolean);
- RNA_def_property_ui_text(prop, "Input Type A", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_b", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_no_boolean);
- RNA_def_property_ui_text(prop, "Input Type B", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
-static void def_geo_point_distribute(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- static const EnumPropertyItem rna_node_geometry_point_distribute_method_items[] = {
- {GEO_NODE_POINT_DISTRIBUTE_RANDOM,
- "RANDOM",
- 0,
- "Random",
- "Distribute points randomly on the surface"},
- {GEO_NODE_POINT_DISTRIBUTE_POISSON,
- "POISSON",
- 0,
- "Poisson Disk",
- "Distribute the points randomly on the surface while taking a minimum distance between "
- "points into account"},
- {0, NULL, 0, NULL, NULL},
- };
-
- prop = RNA_def_property(srna, "distribute_method", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom1");
- RNA_def_property_enum_items(prop, rna_node_geometry_point_distribute_method_items);
- RNA_def_property_enum_default(prop, GEO_NODE_POINT_DISTRIBUTE_RANDOM);
- RNA_def_property_ui_text(prop, "Distribution Method", "Method to use for scattering points");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
static void def_geo_extrude_mesh(StructRNA *srna)
{
PropertyRNA *prop;
@@ -9995,97 +9414,6 @@ static void def_geo_distribute_points_on_faces(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
-static void def_geo_attribute_color_ramp(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeAttributeColorRamp", "storage");
-
- prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "ColorRamp");
- RNA_def_property_ui_text(prop, "Color Ramp", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-}
-
-static void def_geo_attribute_curve_map(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeAttributeCurveMap", "storage");
-
- prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "data_type");
- RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeCurveMap_type_itemf");
- RNA_def_property_ui_text(prop, "Data Type", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "curve_vec", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "CurveMapping");
- RNA_def_property_ui_text(prop, "Mapping", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "curve_rgb", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "CurveMapping");
- RNA_def_property_ui_text(prop, "Mapping", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-}
-
-static void def_geo_attribute_vector_rotate(StructRNA *srna)
-{
- static const EnumPropertyItem rotate_mode_items[] = {
- {GEO_NODE_VECTOR_ROTATE_TYPE_AXIS,
- "AXIS_ANGLE",
- 0,
- "Axis Angle",
- "Rotate a point using axis angle"},
- {GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_X, "X_AXIS", 0, "X Axis", "Rotate a point using X axis"},
- {GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Y, "Y_AXIS", 0, "Y Axis", "Rotate a point using Y axis"},
- {GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Z, "Z_AXIS", 0, "Z Axis", "Rotate a point using Z axis"},
- {GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ,
- "EULER_XYZ",
- 0,
- "Euler",
- "Rotate a point using XYZ order"},
- {0, NULL, 0, NULL, NULL},
- };
-
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeAttributeVectorRotate", "storage");
-
- prop = RNA_def_property(srna, "rotation_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "mode");
- RNA_def_property_enum_items(prop, rotate_mode_items);
- RNA_def_property_ui_text(prop, "Mode", "Type of rotation");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
-
- prop = RNA_def_property(srna, "input_type_vector", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
- RNA_def_property_ui_text(prop, "Input Type Vector", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_center", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
- RNA_def_property_ui_text(prop, "Input Type Center", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
- RNA_def_property_ui_text(prop, "Input Type Axis", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_angle", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
- RNA_def_property_ui_text(prop, "Input Type Angle", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_rotation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
- RNA_def_property_ui_text(prop, "Input Type Rotation", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
static void def_geo_curve_spline_type(StructRNA *srna)
{
static const EnumPropertyItem type_items[] = {
@@ -10121,24 +9449,6 @@ static void def_geo_curve_set_handle_type(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
-static void def_geo_legacy_curve_set_handles(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSetHandles", "storage");
-
- prop = RNA_def_property(srna, "handle_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "handle_type");
- RNA_def_property_enum_items(prop, rna_node_geometry_curve_handle_type_items);
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_curve_handle_side_items);
- RNA_def_property_ui_text(prop, "Mode", "Whether to update left and right handles");
- RNA_def_property_flag(prop, PROP_ENUM_FLAG);
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
static void def_geo_curve_set_handle_positions(StructRNA *srna)
{
PropertyRNA *prop;
@@ -10151,24 +9461,6 @@ static void def_geo_curve_set_handle_positions(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
-static void def_geo_curve_select_handles(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSelectHandles", "storage");
-
- prop = RNA_def_property(srna, "handle_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "handle_type");
- RNA_def_property_enum_items(prop, rna_node_geometry_curve_handle_type_items);
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_curve_handle_side_items);
- RNA_def_property_ui_text(prop, "Mode", "Whether to check the type of left and right handles");
- RNA_def_property_flag(prop, PROP_ENUM_FLAG);
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
static void def_geo_curve_handle_type_selection(StructRNA *srna)
{
PropertyRNA *prop;
@@ -10266,66 +9558,6 @@ static void def_geo_curve_primitive_line(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
-static void def_geo_point_rotate(StructRNA *srna)
-{
- static const EnumPropertyItem type_items[] = {
- {GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE,
- "AXIS_ANGLE",
- ICON_NONE,
- "Axis Angle",
- "Rotate around an axis by an angle"},
- {GEO_NODE_POINT_ROTATE_TYPE_EULER,
- "EULER",
- ICON_NONE,
- "Euler",
- "Rotate around the X, Y, and Z axes"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem space_items[] = {
- {GEO_NODE_POINT_ROTATE_SPACE_OBJECT,
- "OBJECT",
- ICON_NONE,
- "Object",
- "Rotate points in the local space of the object"},
- {GEO_NODE_POINT_ROTATE_SPACE_POINT,
- "POINT",
- ICON_NONE,
- "Point",
- "Rotate every point in its local space (as defined by the 'rotation' attribute)"},
- {0, NULL, 0, NULL, NULL},
- };
-
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeGeometryRotatePoints", "storage");
-
- prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, type_items);
- RNA_def_property_ui_text(prop, "Type", "Method used to describe the rotation");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, space_items);
- RNA_def_property_ui_text(prop, "Space", "Base orientation of the points");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "input_type_axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
- RNA_def_property_ui_text(prop, "Input Type Axis", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_angle", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
- RNA_def_property_ui_text(prop, "Input Type Angle", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_rotation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
- RNA_def_property_ui_text(prop, "Input Type Rotation", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
static void def_fn_rotate_euler(StructRNA *srna)
{
static const EnumPropertyItem type_items[] = {
@@ -10371,76 +9603,6 @@ static void def_fn_rotate_euler(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
-static void def_geo_align_rotation_to_vector(StructRNA *srna)
-{
- static const EnumPropertyItem axis_items[] = {
- {GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_X,
- "X",
- ICON_NONE,
- "X",
- "Align the X axis with the vector"},
- {GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_Y,
- "Y",
- ICON_NONE,
- "Y",
- "Align the Y axis with the vector"},
- {GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_Z,
- "Z",
- ICON_NONE,
- "Z",
- "Align the Z axis with the vector"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static const EnumPropertyItem pivot_axis_items[] = {
- {GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_AUTO,
- "AUTO",
- ICON_NONE,
- "Auto",
- "Automatically detect the best rotation axis to rotate towards the vector"},
- {GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_X,
- "X",
- ICON_NONE,
- "X",
- "Rotate around the local X axis"},
- {GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_Y,
- "Y",
- ICON_NONE,
- "Y",
- "Rotate around the local Y axis"},
- {GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_Z,
- "Z",
- ICON_NONE,
- "Z",
- "Rotate around the local Z axis"},
- {0, NULL, 0, NULL, NULL},
- };
-
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeGeometryAlignRotationToVector", "storage");
-
- prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, axis_items);
- RNA_def_property_ui_text(prop, "Axis", "Axis to align to the vector");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "pivot_axis", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, pivot_axis_items);
- RNA_def_property_ui_text(prop, "Pivot Axis", "Axis to rotate around");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "input_type_factor", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
- RNA_def_property_ui_text(prop, "Input Type Factor", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_vector", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
- RNA_def_property_ui_text(prop, "Input Type Vector", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
static void def_fn_align_euler_to_vector(StructRNA *srna)
{
static const EnumPropertyItem axis_items[] = {
@@ -10501,30 +9663,6 @@ static void def_fn_align_euler_to_vector(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
-static void def_geo_point_scale(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeGeometryPointScale", "storage");
-
- prop = RNA_def_property(srna, "input_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float_vector);
- RNA_def_property_ui_text(prop, "Input Type", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
-static void def_geo_point_translate(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeGeometryPointTranslate", "storage");
-
- prop = RNA_def_property(srna, "input_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
- RNA_def_property_ui_text(prop, "Input Type", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
static void def_geo_object_info(StructRNA *srna)
{
PropertyRNA *prop;
@@ -10555,37 +9693,6 @@ static void def_geo_object_info(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update_relations");
}
-static void def_geo_legacy_points_to_volume(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- static EnumPropertyItem resolution_mode_items[] = {
- {GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT,
- "VOXEL_AMOUNT",
- 0,
- "Amount",
- "Specify the approximate number of voxels along the diagonal"},
- {GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE,
- "VOXEL_SIZE",
- 0,
- "Size",
- "Specify the voxel side length"},
- {0, NULL, 0, NULL, NULL},
- };
-
- RNA_def_struct_sdna_from(srna, "NodeGeometryPointsToVolume", "storage");
-
- prop = RNA_def_property(srna, "resolution_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, resolution_mode_items);
- RNA_def_property_ui_text(prop, "Resolution Mode", "How the voxel size is specified");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_radius", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
- RNA_def_property_ui_text(prop, "Radius Input Type", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
static void def_geo_points_to_volume(StructRNA *srna)
{
PropertyRNA *prop;
@@ -10639,39 +9746,6 @@ static void def_geo_collection_info(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update_relations");
}
-static void def_geo_legacy_attribute_proximity(StructRNA *srna)
-{
- static const EnumPropertyItem target_geometry_element[] = {
- {GEO_NODE_PROXIMITY_TARGET_POINTS,
- "POINTS",
- ICON_NONE,
- "Points",
- "Calculate proximity to the target's points (usually faster than the other two modes)"},
- {GEO_NODE_PROXIMITY_TARGET_EDGES,
- "EDGES",
- ICON_NONE,
- "Edges",
- "Calculate proximity to the target's edges"},
- {GEO_NODE_PROXIMITY_TARGET_FACES,
- "FACES",
- ICON_NONE,
- "Faces",
- "Calculate proximity to the target's faces"},
- {0, NULL, 0, NULL, NULL},
- };
-
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeGeometryAttributeProximity", "storage");
-
- prop = RNA_def_property(srna, "target_geometry_element", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, target_geometry_element);
- RNA_def_property_enum_default(prop, GEO_NODE_PROXIMITY_TARGET_FACES);
- RNA_def_property_ui_text(
- prop, "Target Geometry", "Element of the target geometry to calculate the distance from");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
static void def_geo_proximity(StructRNA *srna)
{
static const EnumPropertyItem target_element_items[] = {
@@ -10736,40 +9810,6 @@ static void def_geo_volume_to_mesh(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
-static void def_geo_attribute_combine_xyz(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeAttributeCombineXYZ", "storage");
-
- prop = RNA_def_property(srna, "input_type_x", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
- RNA_def_property_ui_text(prop, "Input Type X", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_y", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
- RNA_def_property_ui_text(prop, "Input Type Y", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_z", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
- RNA_def_property_ui_text(prop, "Input Type Z", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
-static void def_geo_attribute_separate_xyz(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeAttributeSeparateXYZ", "storage");
-
- prop = RNA_def_property(srna, "input_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
- RNA_def_property_ui_text(prop, "Input Type", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
static void def_geo_mesh_circle(StructRNA *srna)
{
PropertyRNA *prop;
@@ -10936,18 +9976,6 @@ static void def_geo_curve_resample(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
-static void def_geo_legacy_curve_subdivide(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeGeometryCurveSubdivide", "storage");
-
- prop = RNA_def_property(srna, "cuts_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_int);
- RNA_def_property_ui_text(prop, "Cuts Type", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
static void def_geo_curve_fillet(StructRNA *srna)
{
PropertyRNA *prop;
@@ -10974,38 +10002,6 @@ static void def_geo_curve_fillet(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
-static void def_geo_legacy_curve_to_points(StructRNA *srna)
-{
- PropertyRNA *prop;
-
- static EnumPropertyItem mode_items[] = {
- {GEO_NODE_CURVE_RESAMPLE_EVALUATED,
- "EVALUATED",
- 0,
- "Evaluated",
- "Create points from the curve's evaluated points, based on the resolution attribute for "
- "NURBS and Bezier splines"},
- {GEO_NODE_CURVE_RESAMPLE_COUNT,
- "COUNT",
- 0,
- "Count",
- "Sample each spline by evenly distributing the specified number of points"},
- {GEO_NODE_CURVE_RESAMPLE_LENGTH,
- "LENGTH",
- 0,
- "Length",
- "Sample each spline by splitting it into segments with the specified length"},
- {0, NULL, 0, NULL, NULL},
- };
-
- RNA_def_struct_sdna_from(srna, "NodeGeometryCurveToPoints", "storage");
-
- prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, mode_items);
- RNA_def_property_ui_text(prop, "Mode", "How to generate points from the input curve");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
static void def_geo_curve_to_points(StructRNA *srna)
{
PropertyRNA *prop;
@@ -11100,40 +10096,6 @@ static void def_geo_curve_trim(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
-static void def_geo_attribute_transfer(StructRNA *srna)
-{
- static EnumPropertyItem mapping_items[] = {
- {GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED,
- "NEAREST_FACE_INTERPOLATED",
- 0,
- "Nearest Face Interpolated",
- "Transfer the attribute from the nearest face on a surface (loose points and edges are "
- "ignored)"},
- {GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER_NEAREST,
- "NEAREST",
- 0,
- "Nearest",
- "Transfer the element from the nearest element (using face and edge centers for the "
- "distance computation)"},
- {0, NULL, 0, NULL, NULL},
- };
-
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeGeometryAttributeTransfer", "storage");
-
- prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_enum_attribute_domain_with_auto_items);
- RNA_def_property_enum_default(prop, ATTR_DOMAIN_AUTO);
- RNA_def_property_ui_text(prop, "Domain", "The geometry domain to save the result attribute in");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, mapping_items);
- RNA_def_property_ui_text(prop, "Mapping", "Mapping between geometries");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-}
-
static void def_geo_transfer_attribute(StructRNA *srna)
{
static EnumPropertyItem mapping_items[] = {
@@ -11194,42 +10156,6 @@ static void def_geo_input_material(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
-static void def_geo_legacy_raycast(StructRNA *srna)
-{
- static EnumPropertyItem mapping_items[] = {
- {GEO_NODE_RAYCAST_INTERPOLATED,
- "INTERPOLATED",
- 0,
- "Interpolated",
- "Interpolate the attribute from the corners of the hit face"},
- {GEO_NODE_RAYCAST_NEAREST,
- "NEAREST",
- 0,
- "Nearest",
- "Use the attribute value of the closest mesh element"},
- {0, NULL, 0, NULL, NULL},
- };
-
- PropertyRNA *prop;
-
- RNA_def_struct_sdna_from(srna, "NodeGeometryRaycast", "storage");
-
- prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, mapping_items);
- RNA_def_property_ui_text(prop, "Mapping", "Mapping from the target geometry to hit points");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "input_type_ray_direction", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_vector);
- RNA_def_property_ui_text(prop, "Input Type Ray Direction", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-
- prop = RNA_def_property(srna, "input_type_ray_length", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
- RNA_def_property_ui_text(prop, "Input Type Ray Length", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
-}
-
static void def_geo_raycast(StructRNA *srna)
{
static EnumPropertyItem mapping_items[] = {
@@ -11257,7 +10183,7 @@ static void def_geo_raycast(StructRNA *srna)
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeFill_type_itemf");
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_itemf");
RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
@@ -11289,7 +10215,7 @@ static void def_geo_store_named_attribute(StructRNA *srna)
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeFill_type_itemf");
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_itemf");
RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
@@ -11309,7 +10235,7 @@ static void def_geo_input_named_attribute(StructRNA *srna)
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeFill_type_itemf");
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_itemf");
RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
RNA_def_property_ui_text(prop, "Data Type", "The data type used to read the attribute values");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
@@ -11323,7 +10249,7 @@ static void def_geo_attribute_capture(StructRNA *srna)
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeFill_type_itemf");
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_itemf");
RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
@@ -11550,7 +10476,7 @@ static void def_geo_viewer(StructRNA *srna)
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeFill_type_itemf");
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_itemf");
RNA_def_property_enum_default(prop, CD_PROP_FLOAT);
RNA_def_property_ui_text(prop, "Data Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
@@ -11580,7 +10506,7 @@ static void def_geo_field_at_index(StructRNA *srna)
prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom2");
RNA_def_property_enum_items(prop, rna_enum_attribute_type_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeFill_type_itemf");
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeType_type_itemf");
RNA_def_property_ui_text(prop, "Data Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_GeometryNode_socket_update");
}
@@ -13099,12 +12025,12 @@ static void rna_def_node_link(BlenderRNA *brna)
prop = RNA_def_property(srna, "is_valid", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_LINK_VALID);
- RNA_def_struct_ui_text(srna, "Valid", "Link is valid");
+ RNA_def_property_ui_text(prop, "Valid", "Link is valid");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL);
prop = RNA_def_property(srna, "is_muted", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_LINK_MUTED);
- RNA_def_struct_ui_text(srna, "Muted", "Link is muted and can be ignored");
+ RNA_def_property_ui_text(prop, "Muted", "Link is muted and can be ignored");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, NULL);
prop = RNA_def_property(srna, "from_node", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 2770255802d..03f800d14d1 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -3139,15 +3139,19 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Particle_redo");
/* children */
+
+ /* NOTE(@campbellbarton): name is not following conventions: `nbr`.
+ * Could be changed next major version. */
prop = RNA_def_property(srna, "child_nbr", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "child_nbr"); /* Optional if prop names are the same. */
+ RNA_def_property_int_sdna(
+ prop, NULL, "child_percent"); /* Optional if prop names are the same. */
RNA_def_property_range(prop, 0, 100000);
RNA_def_property_ui_range(prop, 0, 1000, 1, -1);
RNA_def_property_ui_text(prop, "Children Per Parent", "Number of children per parent");
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
prop = RNA_def_property(srna, "rendered_child_count", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "ren_child_nbr");
+ RNA_def_property_int_sdna(prop, NULL, "child_render_percent");
RNA_def_property_range(prop, 0, 100000);
RNA_def_property_ui_range(prop, 0, 10000, 1, -1);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index d398dadbec7..6be2c361ba9 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -20,6 +20,7 @@
#include "DNA_view3d_types.h"
#include "DNA_world_types.h"
+#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
#include "BLI_listbase.h"
@@ -29,6 +30,7 @@
#include "BKE_armature.h"
#include "BKE_editmesh.h"
+#include "BKE_idtype.h"
#include "BKE_paint.h"
#include "BKE_volume.h"
@@ -328,6 +330,13 @@ const EnumPropertyItem rna_enum_curve_fit_method_items[] = {
# define R_IMF_ENUM_TIFF
#endif
+#ifdef WITH_WEBP
+# define R_IMF_ENUM_WEBP \
+ {R_IMF_IMTYPE_WEBP, "WEBP", ICON_FILE_IMAGE, "WebP", "Output image in WebP format"},
+#else
+# define R_IMF_ENUM_WEBP
+#endif
+
#define IMAGE_TYPE_ITEMS_IMAGE_ONLY \
R_IMF_ENUM_BMP \
/* DDS save not supported yet R_IMF_ENUM_DDS */ \
@@ -338,7 +347,7 @@ const EnumPropertyItem rna_enum_curve_fit_method_items[] = {
R_IMF_ENUM_TAGA \
R_IMF_ENUM_TAGA_RAW{0, "", 0, " ", NULL}, \
R_IMF_ENUM_CINEON R_IMF_ENUM_DPX R_IMF_ENUM_EXR_MULTILAYER R_IMF_ENUM_EXR R_IMF_ENUM_HDR \
- R_IMF_ENUM_TIFF
+ R_IMF_ENUM_TIFF R_IMF_ENUM_WEBP
#ifdef RNA_RUNTIME
static const EnumPropertyItem image_only_type_items[] = {
@@ -633,6 +642,7 @@ const EnumPropertyItem rna_enum_transform_orientation_items[] = {
# include "BKE_gpencil.h"
# include "BKE_idprop.h"
# include "BKE_image.h"
+# include "BKE_image_format.h"
# include "BKE_layer.h"
# include "BKE_main.h"
# include "BKE_mesh.h"
@@ -1439,6 +1449,35 @@ static const EnumPropertyItem *rna_ImageFormatSettings_exr_codec_itemf(bContext
}
# endif
+
+static bool rna_ImageFormatSettings_has_linear_colorspace_get(PointerRNA *ptr)
+{
+ ImageFormatData *imf = (ImageFormatData *)ptr->data;
+ return BKE_imtype_requires_linear_float(imf->imtype);
+}
+
+static void rna_ImageFormatSettings_color_management_set(PointerRNA *ptr, int value)
+{
+ ImageFormatData *imf = (ImageFormatData *)ptr->data;
+
+ if (imf->color_management != value) {
+ imf->color_management = value;
+
+ /* Copy from scene when enabling override. */
+ if (imf->color_management == R_IMF_COLOR_MANAGEMENT_OVERRIDE) {
+ ID *owner_id = ptr->owner_id;
+ if (owner_id && GS(owner_id->name) == ID_NT) {
+ /* For compositing nodes, find the corresponding scene. */
+ const IDTypeInfo *type_info = BKE_idtype_get_info_from_id(owner_id);
+ owner_id = type_info->owner_get(G_MAIN, owner_id);
+ }
+ if (owner_id && GS(owner_id->name) == ID_SCE) {
+ BKE_image_format_color_management_copy_from_scene(imf, (Scene *)owner_id);
+ }
+ }
+ }
+}
+
static int rna_SceneRender_file_ext_length(PointerRNA *ptr)
{
RenderData *rd = (RenderData *)ptr->data;
@@ -5457,6 +5496,12 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
};
# endif
+ static const EnumPropertyItem color_management_items[] = {
+ {R_IMF_COLOR_MANAGEMENT_FOLLOW_SCENE, "FOLLOW_SCENE", 0, "Follow Scene", ""},
+ {R_IMF_COLOR_MANAGEMENT_OVERRIDE, "OVERRIDE", 0, "Override", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
StructRNA *srna;
PropertyRNA *prop;
@@ -5615,17 +5660,32 @@ static void rna_def_scene_image_format_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Stereo 3D Format", "Settings for stereo 3D");
/* color management */
+ prop = RNA_def_property(srna, "color_management", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, color_management_items);
+ RNA_def_property_ui_text(
+ prop, "Color Management", "Which color management settings to use for file saving");
+ RNA_def_property_enum_funcs(prop, NULL, "rna_ImageFormatSettings_color_management_set", NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "view_settings", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "view_settings");
RNA_def_property_struct_type(prop, "ColorManagedViewSettings");
RNA_def_property_ui_text(
prop, "View Settings", "Color management settings applied on image before saving");
prop = RNA_def_property(srna, "display_settings", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "display_settings");
RNA_def_property_struct_type(prop, "ColorManagedDisplaySettings");
RNA_def_property_ui_text(
prop, "Display Settings", "Settings of device saved image would be displayed on");
+
+ prop = RNA_def_property(srna, "linear_colorspace_settings", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings");
+ RNA_def_property_ui_text(prop, "Color Space Settings", "Output color space settings");
+
+ prop = RNA_def_property(srna, "has_linear_colorspace", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_ImageFormatSettings_has_linear_colorspace_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(
+ prop, "Has Linear Color Space", "File format expects linear color space");
}
static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
@@ -6160,7 +6220,8 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "hair_subdiv", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 0, 3);
- RNA_def_property_ui_text(prop, "Additional Subdiv", "Additional subdivision along the hair");
+ RNA_def_property_ui_text(
+ prop, "Additional Subdivision", "Additional subdivision along the hair");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
/* Performance */
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 40f3d79b363..97e1f325816 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -1518,6 +1518,23 @@ static void rna_def_curves_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Distance", "Radius around curves roots in which no new curves can be added");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
+ prop = RNA_def_property(srna, "interpolate_length", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CURVES_SCULPT_FLAG_INTERPOLATE_LENGTH);
+ RNA_def_property_ui_text(
+ prop, "Interpolate Length", "Use length of the curves in close proximity");
+
+ prop = RNA_def_property(srna, "interpolate_shape", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CURVES_SCULPT_FLAG_INTERPOLATE_SHAPE);
+ RNA_def_property_ui_text(
+ prop, "Interpolate Shape", "Use shape of the curves in close proximity");
+
+ prop = RNA_def_property(srna, "curve_length", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_text(
+ prop,
+ "Curve Length",
+ "Length of newly added curves when it is not interpolated from other curves");
}
void RNA_def_sculpt_paint(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c
index ae7772fcb62..cefa445740d 100644
--- a/source/blender/makesrna/intern/rna_shader_fx.c
+++ b/source/blender/makesrna/intern/rna_shader_fx.c
@@ -524,7 +524,6 @@ static void rna_def_shader_fx_glow(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "glow_color[3]");
RNA_def_property_range(prop, 0.0, 1.0f);
RNA_def_property_ui_text(prop, "Opacity", "Effect Opacity");
- RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
RNA_def_property_update(prop, NC_OBJECT | ND_SHADERFX, "rna_ShaderFx_update");
prop = RNA_def_property(srna, "select_color", PROP_FLOAT, PROP_COLOR);
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 2344aa42838..3839b3ba6a4 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -3773,13 +3773,6 @@ static void rna_def_space_outliner(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Filter by Type", "Data-block type to show");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
- prop = RNA_def_property(srna, "use_filter_lib_override", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_LIB_OVERRIDE);
- RNA_def_property_ui_text(prop,
- "Show Library Overrides",
- "For libraries with overrides created, show the overridden values");
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
-
prop = RNA_def_property(srna, "use_filter_lib_override_system", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_SHOW_SYSTEM_OVERRIDES);
RNA_def_property_ui_text(
diff --git a/source/blender/makesrna/intern/rna_text.c b/source/blender/makesrna/intern/rna_text.c
index 3d2df5b7411..e9c67d71ceb 100644
--- a/source/blender/makesrna/intern/rna_text.c
+++ b/source/blender/makesrna/intern/rna_text.c
@@ -25,7 +25,7 @@
#ifdef RNA_RUNTIME
-static void rna_Text_filename_get(PointerRNA *ptr, char *value)
+static void rna_Text_filepath_get(PointerRNA *ptr, char *value)
{
Text *text = (Text *)ptr->data;
@@ -37,13 +37,13 @@ static void rna_Text_filename_get(PointerRNA *ptr, char *value)
}
}
-static int rna_Text_filename_length(PointerRNA *ptr)
+static int rna_Text_filepath_length(PointerRNA *ptr)
{
Text *text = (Text *)ptr->data;
return (text->filepath) ? strlen(text->filepath) : 0;
}
-static void rna_Text_filename_set(PointerRNA *ptr, const char *value)
+static void rna_Text_filepath_set(PointerRNA *ptr, const char *value)
{
Text *text = (Text *)ptr->data;
@@ -204,7 +204,7 @@ static void rna_def_text(BlenderRNA *brna)
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(
- prop, "rna_Text_filename_get", "rna_Text_filename_length", "rna_Text_filename_set");
+ prop, "rna_Text_filepath_get", "rna_Text_filepath_length", "rna_Text_filepath_set");
RNA_def_property_ui_text(prop, "File Path", "Filename of the text file");
prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 3c8f1ee28c9..56d1b48811a 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -21,6 +21,7 @@
#include "BLI_utildefines.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_paint.h"
#include "RNA_define.h"
@@ -191,8 +192,23 @@ static void rna_Texture_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *pt
static void rna_Texture_mapping_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
+ ID *id = ptr->owner_id;
TexMapping *texmap = ptr->data;
BKE_texture_mapping_init(texmap);
+
+ if (GS(id->name) == ID_NT) {
+ bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
+ /* Try to find and tag the node that this #TexMapping belongs to. */
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ /* This assumes that the #TexMapping is stored at the beginning of the node storage. This is
+ * generally true, see #NodeTexBase. If the assumption happens to be false, there might be a
+ * missing update. */
+ if (node->storage == texmap) {
+ BKE_ntree_update_tag_node_property(ntree, node);
+ }
+ }
+ }
+
rna_Texture_update(bmain, scene, ptr);
}
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 78e6bfec03f..164564241ed 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -208,7 +208,6 @@ static void rna_userdef_version_get(PointerRNA *ptr, int *value)
/** Mark the preferences as being changed so they are saved on exit. */
# define USERDEF_TAG_DIRTY rna_userdef_is_dirty_update_impl()
-/** Use single function so we can more easily break-point it. */
void rna_userdef_is_dirty_update_impl(void)
{
/* We can't use 'ptr->data' because this update function
@@ -219,14 +218,11 @@ void rna_userdef_is_dirty_update_impl(void)
}
}
-/**
- * Use as a fallback update handler,
- * never use 'ptr' unless its type is checked.
- */
void rna_userdef_is_dirty_update(Main *UNUSED(bmain),
Scene *UNUSED(scene),
PointerRNA *UNUSED(ptr))
{
+ /* WARNING: never use 'ptr' unless its type is checked. */
rna_userdef_is_dirty_update_impl();
}
@@ -2198,7 +2194,7 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
srna = RNA_def_struct(brna, "ThemeView3D", NULL);
RNA_def_struct_sdna(srna, "ThemeSpace");
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
- RNA_def_struct_ui_text(srna, "Theme 3D View", "Theme settings for the 3D View");
+ RNA_def_struct_ui_text(srna, "Theme 3D Viewport", "Theme settings for the 3D viewport");
rna_def_userdef_theme_spaces_gradient(srna);
@@ -3959,7 +3955,7 @@ static void rna_def_userdef_themes(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "space_view3d");
RNA_def_property_struct_type(prop, "ThemeView3D");
- RNA_def_property_ui_text(prop, "3D View", "");
+ RNA_def_property_ui_text(prop, "3D Viewport", "");
prop = RNA_def_property(srna, "graph_editor", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@@ -4571,7 +4567,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_tooltips", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_TOOLTIPS);
RNA_def_property_ui_text(
- prop, "Tooltips", "Display tooltips (when off hold Alt to force display)");
+ prop, "Tooltips", "Display tooltips (when disabled, hold Alt to force display)");
prop = RNA_def_property(srna, "show_tooltips_python", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_TOOLTIPS_PYTHON);
@@ -4587,14 +4583,17 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_object_info", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_DRAWVIEWINFO);
- RNA_def_property_ui_text(
- prop, "Display Object Info", "Display objects name and frame number in 3D view");
+ RNA_def_property_ui_text(prop,
+ "Display Object Info",
+ "Include the name of the active object and the current frame number in "
+ "the text info overlay");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "show_view_name", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_SHOW_VIEWPORTNAME);
- RNA_def_property_ui_text(
- prop, "Show View Name", "Show the name of the view's direction in each 3D View");
+ RNA_def_property_ui_text(prop,
+ "Display View Name",
+ "Include the name of the view orientation in the text info overlay");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "show_splash", PROP_BOOLEAN, PROP_NONE);
@@ -4603,10 +4602,10 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_playback_fps", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_SHOW_FPS);
- RNA_def_property_ui_text(
- prop,
- "Show Playback FPS",
- "Show the frames per second screen refresh rate, while animation is played back");
+ RNA_def_property_ui_text(prop,
+ "Display Playback Frame Rate (FPS)",
+ "Include the number of frames displayed per second in the text info "
+ "overlay while animation is played back");
RNA_def_property_update(prop, 0, "rna_userdef_update");
USERDEF_TAG_DIRTY_PROPERTY_UPDATE_DISABLE;
@@ -4786,9 +4785,10 @@ static void rna_def_userdef_view(BlenderRNA *brna)
prop = RNA_def_property(srna, "mini_axis_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, mini_axis_type_items);
- RNA_def_property_ui_text(prop,
- "Mini Axes Type",
- "Show a small rotating 3D axes in the top right corner of the 3D View");
+ RNA_def_property_ui_text(
+ prop,
+ "Mini Axes Type",
+ "Show a small rotating 3D axes in the top right corner of the 3D viewport");
RNA_def_property_update(prop, 0, "rna_userdef_gizmo_update");
prop = RNA_def_property(srna, "mini_axis_size", PROP_INT, PROP_PIXEL);
@@ -4987,7 +4987,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
"VIEW",
0,
"View",
- "Align newly added objects to the active 3D View direction"},
+ "Align newly added objects to the active 3D view orientation"},
{USER_ADD_CURSORALIGNED,
"CURSOR",
0,
@@ -5016,15 +5016,12 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, object_align_items);
RNA_def_property_ui_text(
- prop,
- "Align Object To",
- "When adding objects from a 3D View menu, either align them with that view or "
- "with the world");
+ prop, "Align Object To", "The default alignment for objects added from a 3D viewport menu");
prop = RNA_def_property(srna, "use_enter_edit_mode", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_ADD_EDITMODE);
RNA_def_property_ui_text(
- prop, "Enter Edit Mode", "Enter Edit Mode automatically after adding a new object");
+ prop, "Enter Edit Mode", "Enter edit mode automatically after adding a new object");
prop = RNA_def_property(srna, "collection_instance_empty_size", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.001f, FLT_MAX);
@@ -5037,7 +5034,9 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_text_edit_auto_close", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "text_flag", USER_TEXT_EDIT_AUTO_CLOSE);
RNA_def_property_ui_text(
- prop, "Auto Close", "Auto close relevant characters inside the text editor");
+ prop,
+ "Auto Close Character Pairs",
+ "Automatically close relevant character pairs when typing in the text editor");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL);
/* Undo */
@@ -5279,10 +5278,10 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Duplicate GPencil", "Causes grease pencil data to be duplicated with the object");
- prop = RNA_def_property(srna, "use_duplicate_hair", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_duplicate_curves", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_CURVES);
RNA_def_property_ui_text(
- prop, "Duplicate Hair", "Causes hair data to be duplicated with the object");
+ prop, "Duplicate Curves", "Causes curves data to be duplicated with the object");
prop = RNA_def_property(srna, "use_duplicate_pointcloud", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_POINTCLOUD);
@@ -5539,9 +5538,10 @@ static void rna_def_userdef_system(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_edit_mode_smooth_wire", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(
prop, NULL, "gpu_flag", USER_GPU_FLAG_NO_EDIT_MODE_SMOOTH_WIRE);
- RNA_def_property_ui_text(prop,
- "Edit-Mode Smooth Wires",
- "Enable Edit-Mode edge smoothing, reducing aliasing, requires restart");
+ RNA_def_property_ui_text(
+ prop,
+ "Edit Mode Smooth Wires",
+ "Enable edit mode edge smoothing, reducing aliasing (requires restart)");
RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
prop = RNA_def_property(srna, "use_region_overlap", PROP_BOOLEAN, PROP_NONE);
@@ -5596,11 +5596,7 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "anisotropic_filter");
RNA_def_property_enum_items(prop, anisotropic_items);
RNA_def_property_enum_default(prop, 1);
- RNA_def_property_ui_text(
- prop,
- "Anisotropic Filter",
- "Quality of the anisotropic filtering (values greater than 1.0 enable anisotropic "
- "filtering)");
+ RNA_def_property_ui_text(prop, "Anisotropic Filtering", "Quality of anisotropic filtering");
RNA_def_property_update(prop, 0, "rna_userdef_anisotropic_update");
prop = RNA_def_property(srna, "gl_texture_limit", PROP_ENUM, PROP_NONE);
@@ -5649,9 +5645,9 @@ static void rna_def_userdef_system(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_select_pick_depth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "gpu_flag", USER_GPU_FLAG_NO_DEPT_PICK);
RNA_def_property_ui_text(prop,
- "OpenGL Depth Picking",
- "Use the depth buffer for picking 3D View selection "
- "(without this the front most object may not be selected first)");
+ "GPU Depth Picking",
+ "When making a selection in 3D View, use the GPU depth buffer to "
+ "ensure the frontmost object is selected first");
/* GPU subdivision evaluation. */
@@ -6437,16 +6433,21 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Override Templates", "Enable library override template in the python API");
- prop = RNA_def_property(srna, "use_geometry_nodes_legacy", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "use_geometry_nodes_legacy", 1);
- RNA_def_property_ui_text(
- prop, "Geometry Nodes Legacy", "Enable legacy geometry nodes in the menu");
-
prop = RNA_def_property(srna, "use_named_attribute_nodes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_named_attribute_nodes", 1);
RNA_def_property_ui_text(prop,
"Named Attribute Nodes",
"Enable named attribute nodes in the geometry nodes add menu");
+
+ prop = RNA_def_property(srna, "use_select_nearest_on_first_click", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "use_select_nearest_on_first_click", 1);
+ RNA_def_property_ui_text(prop,
+ "Object Select Nearest on First Click",
+ "When enabled, always select the front-most object on the first click");
+
+ prop = RNA_def_property(srna, "enable_eevee_next", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "enable_eevee_next", 1);
+ RNA_def_property_ui_text(prop, "EEVEE Next", "Enable the new EEVEE codebase, requires restart");
}
static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop)
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 88984a652d7..a5e5bf36dcd 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -61,7 +61,7 @@ set(SRC
intern/MOD_meshcache_pc2.c
intern/MOD_meshcache_util.c
intern/MOD_meshdeform.c
- intern/MOD_meshsequencecache.c
+ intern/MOD_meshsequencecache.cc
intern/MOD_mirror.c
intern/MOD_multires.c
intern/MOD_nodes.cc
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 8298f7c92b2..b237f952287 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -397,8 +397,10 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
Object *start_cap_ob = amd->start_cap;
if (start_cap_ob && start_cap_ob != ctx->object) {
- vgroup_start_cap_remap = BKE_object_defgroup_index_map_create(
- start_cap_ob, ctx->object, &vgroup_start_cap_remap_len);
+ if (start_cap_ob->type == OB_MESH && ctx->object->type == OB_MESH) {
+ vgroup_start_cap_remap = BKE_object_defgroup_index_map_create(
+ start_cap_ob, ctx->object, &vgroup_start_cap_remap_len);
+ }
start_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(start_cap_ob, false);
if (start_cap_mesh) {
@@ -410,8 +412,10 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
}
Object *end_cap_ob = amd->end_cap;
if (end_cap_ob && end_cap_ob != ctx->object) {
- vgroup_end_cap_remap = BKE_object_defgroup_index_map_create(
- end_cap_ob, ctx->object, &vgroup_end_cap_remap_len);
+ if (end_cap_ob->type == OB_MESH && ctx->object->type == OB_MESH) {
+ vgroup_end_cap_remap = BKE_object_defgroup_index_map_create(
+ end_cap_ob, ctx->object, &vgroup_end_cap_remap_len);
+ }
end_cap_mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(end_cap_ob, false);
if (end_cap_mesh) {
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index cbad4ccd662..b6cceade4e2 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -111,6 +111,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
.add_key_index = false,
.use_shapekey = false,
.active_shapekey = 0,
diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc
index 52773e6d3ef..915428f99da 100644
--- a/source/blender/modifiers/intern/MOD_boolean.cc
+++ b/source/blender/modifiers/intern/MOD_boolean.cc
@@ -244,6 +244,7 @@ static BMesh *BMD_mesh_bm_create(
BMeshFromMeshParams bmesh_from_mesh_params{};
bmesh_from_mesh_params.calc_face_normal = true;
+ bmesh_from_mesh_params.calc_vert_normal = true;
BM_mesh_bm_from_me(bm, mesh_operand_ob, &bmesh_from_mesh_params);
if (UNLIKELY(*r_is_flip)) {
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 8434446a074..67515478be5 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -91,6 +91,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
DecimateModifierData *dmd = (DecimateModifierData *)md;
Mesh *mesh = meshData, *result = NULL;
BMesh *bm;
+ bool calc_vert_normal;
bool calc_face_normal;
float *vweights = NULL;
@@ -107,18 +108,21 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
return mesh;
}
calc_face_normal = true;
+ calc_vert_normal = true;
break;
case MOD_DECIM_MODE_UNSUBDIV:
if (dmd->iter == 0) {
return mesh;
}
calc_face_normal = false;
+ calc_vert_normal = false;
break;
case MOD_DECIM_MODE_DISSOLVE:
if (dmd->angle == 0.0f) {
return mesh;
}
calc_face_normal = true;
+ calc_vert_normal = false;
break;
default:
return mesh;
@@ -160,6 +164,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = calc_face_normal,
+ .calc_vert_normal = calc_vert_normal,
.cd_mask_extra = {.vmask = CD_MASK_ORIGINDEX,
.emask = CD_MASK_ORIGINDEX,
.pmask = CD_MASK_ORIGINDEX},
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 3570bdda5a9..14431e5ff2e 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -57,6 +57,7 @@ Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd)
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = calc_face_normals,
+ .calc_vert_normal = false,
.add_key_index = false,
.use_shapekey = false,
.active_shapekey = 0,
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.cc
index 14af22645e3..cfc5b17f37e 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.cc
@@ -4,7 +4,7 @@
* \ingroup modifiers
*/
-#include <string.h>
+#include <cstring>
#include "BLI_math_vector.h"
#include "BLI_string.h"
@@ -60,11 +60,11 @@
static void initData(ModifierData *md)
{
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(mcmd, modifier));
- mcmd->cache_file = NULL;
+ mcmd->cache_file = nullptr;
mcmd->object_path[0] = '\0';
mcmd->read_flag = MOD_MESHSEQ_READ_ALL;
@@ -80,13 +80,13 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla
BKE_modifier_copydata_generic(md, target, flag);
- tmcmd->reader = NULL;
+ tmcmd->reader = nullptr;
tmcmd->reader_object_path[0] = '\0';
}
static void freeData(ModifierData *md)
{
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
if (mcmd->reader) {
mcmd->reader_object_path[0] = '\0';
@@ -98,10 +98,10 @@ static bool isDisabled(const struct Scene *UNUSED(scene),
ModifierData *md,
bool UNUSED(useRenderParams))
{
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
/* leave it up to the modifier to check the file is valid on calculation */
- return (mcmd->cache_file == NULL) || (mcmd->object_path[0] == '\0');
+ return (mcmd->cache_file == nullptr) || (mcmd->object_path[0] == '\0');
}
static Mesh *generate_bounding_box_mesh(Object *object, Mesh *org_mesh)
@@ -145,17 +145,17 @@ static Mesh *generate_bounding_box_mesh(Object *object, Mesh *org_mesh)
static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
#if defined(WITH_USD) || defined(WITH_ALEMBIC)
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
/* Only used to check whether we are operating on org data or not... */
- Mesh *me = (ctx->object->type == OB_MESH) ? ctx->object->data : NULL;
+ Mesh *me = (ctx->object->type == OB_MESH) ? static_cast<Mesh *>(ctx->object->data) : nullptr;
Mesh *org_mesh = mesh;
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
CacheFile *cache_file = mcmd->cache_file;
const float frame = DEG_get_ctime(ctx->depsgraph);
const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
- const char *err_str = NULL;
+ const char *err_str = nullptr;
if (!mcmd->reader || !STREQ(mcmd->reader_object_path, mcmd->object_path)) {
STRNCPY(mcmd->reader_object_path, mcmd->object_path);
@@ -196,7 +196,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
}
- if (me != NULL) {
+ if (me != nullptr) {
MVert *mvert = mesh->mvert;
MEdge *medge = mesh->medge;
MPoly *mpoly = mesh->mpoly;
@@ -205,15 +205,16 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
* flags) and duplicate those too. */
if ((me->mvert == mvert) || (me->medge == medge) || (me->mpoly == mpoly)) {
/* We need to duplicate data here, otherwise we'll modify org mesh, see T51701. */
- mesh = (Mesh *)BKE_id_copy_ex(NULL,
- &mesh->id,
- NULL,
- LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
- LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW);
+ mesh = reinterpret_cast<Mesh *>(
+ BKE_id_copy_ex(nullptr,
+ &mesh->id,
+ nullptr,
+ LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG | LIB_ID_COPY_NO_PREVIEW));
}
}
- Mesh *result = NULL;
+ Mesh *result = nullptr;
switch (cache_file->type) {
case CACHEFILE_TYPE_ALEMBIC: {
@@ -250,8 +251,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
BKE_modifier_set_error(ctx->object, md, "%s", err_str);
}
- if (!ELEM(result, NULL, mesh) && (mesh != org_mesh)) {
- BKE_id_free(NULL, mesh);
+ if (!ELEM(result, nullptr, mesh) && (mesh != org_mesh)) {
+ BKE_id_free(nullptr, mesh);
mesh = org_mesh;
}
@@ -265,9 +266,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
static bool dependsOnTime(Scene *scene, ModifierData *md, const int dag_eval_mode)
{
#if defined(WITH_USD) || defined(WITH_ALEMBIC)
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
/* Do not evaluate animations if using the render engine procedural. */
- return (mcmd->cache_file != NULL) &&
+ return (mcmd->cache_file != nullptr) &&
!BKE_cache_file_uses_render_procedural(mcmd->cache_file, scene, dag_eval_mode);
#else
UNUSED_VARS(scene, md, dag_eval_mode);
@@ -277,16 +278,16 @@ static bool dependsOnTime(Scene *scene, ModifierData *md, const int dag_eval_mod
static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
- walk(userData, ob, (ID **)&mcmd->cache_file, IDWALK_CB_USER);
+ walk(userData, ob, reinterpret_cast<ID **>(&mcmd->cache_file), IDWALK_CB_USER);
}
static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
- MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md;
+ MeshSeqCacheModifierData *mcmd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
- if (mcmd->cache_file != NULL) {
+ if (mcmd->cache_file != nullptr) {
DEG_add_object_cache_relation(
ctx->node, mcmd->cache_file, DEG_OB_COMP_CACHE, "Mesh Cache File");
}
@@ -307,12 +308,13 @@ static void panel_draw(const bContext *C, Panel *panel)
uiTemplateCacheFile(layout, C, ptr, "cache_file");
if (has_cache_file) {
- uiItemPointerR(layout, ptr, "object_path", &cache_file_ptr, "object_paths", NULL, ICON_NONE);
+ uiItemPointerR(
+ layout, ptr, "object_path", &cache_file_ptr, "object_paths", nullptr, ICON_NONE);
}
if (RNA_enum_get(&ob_ptr, "type") == OB_MESH) {
- uiItemR(layout, ptr, "read_data", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_vertex_interpolation", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "read_data", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+ uiItemR(layout, ptr, "use_vertex_interpolation", 0, nullptr, ICON_NONE);
}
modifier_panel_end(layout, ptr);
@@ -332,7 +334,7 @@ static void velocity_panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetPropSep(layout, true);
uiTemplateCacheFileVelocity(layout, &fileptr);
- uiItemR(layout, ptr, "velocity_scale", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "velocity_scale", 0, nullptr, ICON_NONE);
}
static void time_panel_draw(const bContext *UNUSED(C), Panel *panel)
@@ -387,27 +389,27 @@ static void panelRegister(ARegionType *region_type)
{
PanelType *panel_type = modifier_panel_register(
region_type, eModifierType_MeshSequenceCache, panel_draw);
- modifier_subpanel_register(region_type, "time", "Time", NULL, time_panel_draw, panel_type);
+ modifier_subpanel_register(region_type, "time", "Time", nullptr, time_panel_draw, panel_type);
modifier_subpanel_register(region_type,
"render_procedural",
"Render Procedural",
- NULL,
+ nullptr,
render_procedural_panel_draw,
panel_type);
modifier_subpanel_register(
- region_type, "velocity", "Velocity", NULL, velocity_panel_draw, panel_type);
+ region_type, "velocity", "Velocity", nullptr, velocity_panel_draw, panel_type);
modifier_subpanel_register(region_type,
"override_layers",
"Override Layers",
- NULL,
+ nullptr,
override_layers_panel_draw,
panel_type);
}
static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
{
- MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md;
- msmcd->reader = NULL;
+ MeshSeqCacheModifierData *msmcd = reinterpret_cast<MeshSeqCacheModifierData *>(md);
+ msmcd->reader = nullptr;
msmcd->reader_object_path[0] = '\0';
}
@@ -417,29 +419,30 @@ ModifierTypeInfo modifierType_MeshSequenceCache = {
/* structSize */ sizeof(MeshSeqCacheModifierData),
/* srna */ &RNA_MeshSequenceCacheModifier,
/* type */ eModifierTypeType_Constructive,
- /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs,
+ /* flags */
+ static_cast<ModifierTypeFlag>(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_AcceptsCVs),
/* icon */ ICON_MOD_MESHDEFORM, /* TODO: Use correct icon. */
/* copyData */ copyData,
- /* deformVerts */ NULL,
- /* deformMatrices */ NULL,
- /* deformVertsEM */ NULL,
- /* deformMatricesEM */ NULL,
+ /* deformVerts */ nullptr,
+ /* deformMatrices */ nullptr,
+ /* deformVertsEM */ nullptr,
+ /* deformMatricesEM */ nullptr,
/* modifyMesh */ modifyMesh,
- /* modifyGeometrySet */ NULL,
+ /* modifyGeometrySet */ nullptr,
/* initData */ initData,
- /* requiredDataMask */ NULL,
+ /* requiredDataMask */ nullptr,
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
- /* dependsOnNormals */ NULL,
+ /* dependsOnNormals */ nullptr,
/* foreachIDLink */ foreachIDLink,
- /* foreachTexLink */ NULL,
- /* freeRuntimeData */ NULL,
+ /* foreachTexLink */ nullptr,
+ /* freeRuntimeData */ nullptr,
/* panelRegister */ panelRegister,
- /* blendWrite */ NULL,
+ /* blendWrite */ nullptr,
/* blendRead */ blendRead,
};
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index 7cf425c6e27..e94f8e50fec 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -89,9 +89,14 @@
using blender::Array;
using blender::ColorGeometry4f;
+using blender::CPPType;
using blender::destruct_ptr;
using blender::float3;
using blender::FunctionRef;
+using blender::GMutablePointer;
+using blender::GMutableSpan;
+using blender::GPointer;
+using blender::GVArray;
using blender::IndexRange;
using blender::Map;
using blender::MultiValueMap;
@@ -104,9 +109,6 @@ 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::GVArray;
using blender::fn::ValueOrField;
using blender::fn::ValueOrFieldCPPType;
using blender::nodes::FieldInferencingInterface;
@@ -1607,29 +1609,17 @@ static void panel_draw(const bContext *C, Panel *panel)
}
/* Draw node warnings. */
- bool has_legacy_node = false;
if (nmd->runtime_eval_log != nullptr) {
const geo_log::ModifierLog &log = *static_cast<geo_log::ModifierLog *>(nmd->runtime_eval_log);
log.foreach_node_log([&](const geo_log::NodeLog &node_log) {
for (const geo_log::NodeWarning &warning : node_log.warnings()) {
- if (warning.type == geo_log::NodeWarningType::Legacy) {
- has_legacy_node = true;
- }
- else if (warning.type != geo_log::NodeWarningType::Info) {
+ if (warning.type != geo_log::NodeWarningType::Info) {
uiItemL(layout, warning.message.c_str(), ICON_ERROR);
}
}
});
}
- if (has_legacy_node) {
- uiLayout *row = uiLayoutRow(layout, false);
- uiItemL(row, TIP_("Node tree has legacy node"), ICON_ERROR);
- uiLayout *sub = uiLayoutRow(row, false);
- uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
- uiItemO(sub, "", ICON_VIEWZOOM, "NODE_OT_geometry_node_view_legacy");
- }
-
modifier_panel_end(layout, ptr);
}
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index c4aa023faa6..8e5f9dc429f 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -11,12 +11,12 @@
#include "FN_field.hh"
#include "FN_field_cpp_type.hh"
-#include "FN_generic_value_map.hh"
#include "FN_multi_function.hh"
#include "BLT_translation.h"
#include "BLI_enumerable_thread_specific.hh"
+#include "BLI_generic_value_map.hh"
#include "BLI_stack.hh"
#include "BLI_task.h"
#include "BLI_task.hh"
@@ -26,11 +26,8 @@
namespace blender::modifiers::geometry_nodes {
-using fn::CPPType;
using fn::Field;
using fn::GField;
-using fn::GValueMap;
-using fn::GVArray;
using fn::ValueOrField;
using fn::ValueOrFieldCPPType;
using nodes::GeoNodeExecParams;
@@ -980,15 +977,11 @@ class GeometryNodesEvaluator {
void execute_geometry_node(const DNode node, NodeState &node_state, NodeTaskRunState *run_state)
{
+ using Clock = std::chrono::steady_clock;
const bNode &bnode = *node->bnode();
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();
@@ -1004,14 +997,6 @@ class GeometryNodesEvaluator {
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, run_state};
- GeoNodeExecParams params{params_provider};
- params.error_message_add(geo_log::NodeWarningType::Legacy,
- TIP_("Legacy node will be removed before Blender 4.0"));
- }
-
LinearAllocator<> &allocator = local_allocators_.local();
bool any_input_is_field = false;
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.hh b/source/blender/modifiers/intern/MOD_nodes_evaluator.hh
index e981157da41..cbcbcab5679 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.hh
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.hh
@@ -2,14 +2,13 @@
#pragma once
+#include "BLI_generic_pointer.hh"
#include "BLI_map.hh"
#include "NOD_derived_node_tree.hh"
#include "NOD_geometry_nodes_eval_log.hh"
#include "NOD_multi_function.hh"
-#include "FN_generic_pointer.hh"
-
#include "DNA_modifier_types.h"
#include "FN_multi_function.hh"
@@ -19,8 +18,6 @@ namespace geo_log = blender::nodes::geometry_nodes_eval_log;
namespace blender::modifiers::geometry_nodes {
using namespace nodes::derived_node_tree_types;
-using fn::GMutablePointer;
-using fn::GPointer;
struct GeometryNodesEvaluationParams {
blender::LinearAllocator<> allocator;
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index e42223e2ad5..6ab6dc5d4c8 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -450,18 +450,18 @@ static Frame **collect_hull_frames(
{
SkinNode *f;
Frame **hull_frames;
- int nbr, i;
+ int hull_frames_num, i;
(*tothullframe) = emap[v].count;
hull_frames = MEM_calloc_arrayN(
(*tothullframe), sizeof(Frame *), "hull_from_frames.hull_frames");
- i = 0;
- for (nbr = 0; nbr < emap[v].count; nbr++) {
- const MEdge *e = &medge[emap[v].indices[nbr]];
+ hull_frames_num = 0;
+ for (i = 0; i < emap[v].count; i++) {
+ const MEdge *e = &medge[emap[v].indices[i]];
f = &frames[BKE_mesh_edge_other_vert(e, v)];
/* Can't have adjacent branch nodes yet */
if (f->totframe) {
- hull_frames[i++] = &f->frames[0];
+ hull_frames[hull_frames_num++] = &f->frames[0];
}
else {
(*tothullframe)--;
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
index ff25c1afd49..d896cab4688 100644
--- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -1982,6 +1982,18 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
result->dvert = dvert;
}
+ /* Get vertex crease layer and ensure edge creases are active if vertex creases are found, since
+ * they will introduce edge creases in the used custom interpolation method. */
+ const float *vertex_crease = CustomData_get_layer(&mesh->vdata, CD_CREASE);
+ if (vertex_crease) {
+ result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
+ /* delete all vertex creases in the result if a rim is used. */
+ if (do_rim) {
+ CustomData_free_layers(&result->vdata, CD_CREASE, result->totvert);
+ result->cd_flag &= (char)(~ME_CDFLAG_VERT_CREASE);
+ }
+ }
+
/* Make_new_verts. */
{
gs_ptr = orig_vert_groups_arr;
@@ -2105,6 +2117,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
EdgeGroup *g2 = gs;
EdgeGroup *last_g = NULL;
EdgeGroup *first_g = NULL;
+ char mv_crease = vertex_crease ? (char)(vertex_crease[i] * 255.0f) : 0;
/* Data calculation cache. */
char max_crease;
char last_max_crease = 0;
@@ -2174,7 +2187,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
medge[edge_index].v2 = g->new_vert;
medge[edge_index].flag = ME_EDGEDRAW | ME_EDGERENDER |
((last_flag | flag) & (ME_SEAM | ME_SHARP));
- medge[edge_index].crease = min_cc(last_max_crease, max_crease);
+ medge[edge_index].crease = max_cc(mv_crease, min_cc(last_max_crease, max_crease));
medge[edge_index++].bweight = max_cc(mv->bweight,
min_cc(last_max_bweight, max_bweight));
}
@@ -2202,7 +2215,8 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
medge[edge_index].v2 = first_g->new_vert;
medge[edge_index].flag = ME_EDGEDRAW | ME_EDGERENDER |
((last_flag | first_flag) & (ME_SEAM | ME_SHARP));
- medge[edge_index].crease = min_cc(last_max_crease, first_max_crease);
+ medge[edge_index].crease = max_cc(mv_crease,
+ min_cc(last_max_crease, first_max_crease));
medge[edge_index++].bweight = max_cc(mv->bweight,
min_cc(last_max_bweight, first_max_bweight));
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 79dcdf48402..e560a859735 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -61,6 +61,7 @@ static Mesh *triangulate_mesh(Mesh *mesh,
&((struct BMeshCreateParams){0}),
&((struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = false,
.cd_mask_extra = cd_mask_extra,
}));
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index 6d95a169319..dae7d19844e 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -69,6 +69,7 @@ static Mesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, Mesh *
&(struct BMeshCreateParams){0},
&(struct BMeshFromMeshParams){
.calc_face_normal = true,
+ .calc_vert_normal = true,
.add_key_index = false,
.use_shapekey = false,
.active_shapekey = 0,
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index d5d97f7be2e..3d3450d9252 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -143,8 +143,6 @@ void ntreeCompositExecTree(struct Scene *scene,
struct RenderData *rd,
int rendering,
int do_previews,
- const struct ColorManagedViewSettings *view_settings,
- const struct ColorManagedDisplaySettings *display_settings,
const char *view_name);
/**
diff --git a/source/blender/nodes/NOD_function.h b/source/blender/nodes/NOD_function.h
index a33cdc1b64c..cde4b67e120 100644
--- a/source/blender/nodes/NOD_function.h
+++ b/source/blender/nodes/NOD_function.h
@@ -6,8 +6,6 @@
extern "C" {
#endif
-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_compare(void);
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index be21dd4b88f..064112b7efd 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -15,45 +15,11 @@ void register_node_tree_type_geo(void);
void register_node_type_geo_group(void);
void register_node_type_geo_custom_group(bNodeType *ntype);
-void register_node_type_geo_legacy_attribute_proximity(void);
-void register_node_type_geo_legacy_attribute_randomize(void);
-void register_node_type_geo_legacy_attribute_transfer(void);
-void register_node_type_geo_legacy_curve_endpoints(void);
-void register_node_type_geo_legacy_curve_reverse(void);
-void register_node_type_geo_legacy_curve_set_handles(void);
-void register_node_type_geo_legacy_curve_spline_type(void);
-void register_node_type_geo_legacy_curve_subdivide(void);
-void register_node_type_geo_legacy_curve_to_points(void);
-void register_node_type_geo_legacy_delete_geometry(void);
-void register_node_type_geo_legacy_edge_split(void);
-void register_node_type_geo_legacy_material_assign(void);
-void register_node_type_geo_legacy_mesh_to_curve(void);
-void register_node_type_geo_legacy_points_to_volume(void);
-void register_node_type_geo_legacy_raycast(void);
-void register_node_type_geo_legacy_select_by_handle_type(void);
-void register_node_type_geo_legacy_select_by_material(void);
-void register_node_type_geo_legacy_subdivision_surface(void);
-void register_node_type_geo_legacy_volume_to_mesh(void);
-
void register_node_type_geo_accumulate_field(void);
-void register_node_type_geo_align_rotation_to_vector(void);
void register_node_type_geo_attribute_capture(void);
-void register_node_type_geo_attribute_clamp(void);
-void register_node_type_geo_attribute_color_ramp(void);
-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);
-void register_node_type_geo_attribute_mix(void);
-void register_node_type_geo_legacy_attribute_remove(void);
void register_node_type_geo_attribute_separate_xyz(void);
void register_node_type_geo_attribute_statistic(void);
-void register_node_type_geo_attribute_vector_math(void);
-void register_node_type_geo_attribute_vector_rotate(void);
void register_node_type_geo_boolean(void);
void register_node_type_geo_bounding_box(void);
void register_node_type_geo_collection_info(void);
@@ -134,12 +100,6 @@ void register_node_type_geo_mesh_subdivide(void);
void register_node_type_geo_mesh_to_curve(void);
void register_node_type_geo_mesh_to_points(void);
void register_node_type_geo_object_info(void);
-void register_node_type_geo_point_distribute(void);
-void register_node_type_geo_point_instance(void);
-void register_node_type_geo_point_rotate(void);
-void register_node_type_geo_point_scale(void);
-void register_node_type_geo_point_separate(void);
-void register_node_type_geo_point_translate(void);
void register_node_type_geo_points_to_vertices(void);
void register_node_type_geo_points_to_volume(void);
void register_node_type_geo_proximity(void);
@@ -147,7 +107,6 @@ void register_node_type_geo_raycast(void);
void register_node_type_geo_realize_instances(void);
void register_node_type_geo_remove_attribute(void);
void register_node_type_geo_rotate_instances(void);
-void register_node_type_geo_sample_texture(void);
void register_node_type_geo_scale_elements(void);
void register_node_type_geo_scale_instances(void);
void register_node_type_geo_select_by_handle_type(void);
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index 540afc41dba..dc0965f5d71 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -32,21 +32,12 @@ using bke::ReadAttributeLookup;
using bke::StrongAnonymousAttributeID;
using bke::WeakAnonymousAttributeID;
using bke::WriteAttributeLookup;
-using fn::CPPType;
using fn::Field;
using fn::FieldContext;
using fn::FieldEvaluator;
using fn::FieldInput;
using fn::FieldOperation;
using fn::GField;
-using fn::GMutablePointer;
-using fn::GMutableSpan;
-using fn::GPointer;
-using fn::GSpan;
-using fn::GVArray;
-using fn::GVArray_GSpan;
-using fn::GVMutableArray;
-using fn::GVMutableArray_GSpan;
using fn::ValueOrField;
using geometry_nodes_eval_log::NodeWarningType;
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
index 7ef149d5dc5..319fcdeebb7 100644
--- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -18,13 +18,12 @@
#include "BLI_enumerable_thread_specific.hh"
#include "BLI_function_ref.hh"
+#include "BLI_generic_pointer.hh"
#include "BLI_linear_allocator.hh"
#include "BLI_map.hh"
#include "BKE_geometry_set.hh"
-#include "FN_generic_pointer.hh"
-
#include "NOD_derived_node_tree.hh"
#include <chrono>
@@ -34,9 +33,6 @@ struct SpaceSpreadsheet;
namespace blender::nodes::geometry_nodes_eval_log {
-using fn::GMutablePointer;
-using fn::GPointer;
-
/** Contains information about a value that has been computed during geometry nodes evaluation. */
class ValueLog {
public:
@@ -67,7 +63,7 @@ class GenericValueLog : public ValueLog {
class GFieldValueLog : public ValueLog {
private:
fn::GField field_;
- const fn::CPPType &type_;
+ const CPPType &type_;
Vector<std::string> input_tooltips_;
public:
@@ -83,7 +79,7 @@ class GFieldValueLog : public ValueLog {
return input_tooltips_;
}
- const fn::CPPType &type() const
+ const CPPType &type() const
{
return type_;
}
@@ -144,7 +140,6 @@ enum class NodeWarningType {
Error,
Warning,
Info,
- Legacy,
};
struct NodeWarning {
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 97a6b8a6e63..0e1f181eff1 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -254,8 +254,6 @@ DefNode(TextureNode, TEX_NODE_PROC+TEX_NOISE, 0, "TEX_NO
DefNode(TextureNode, TEX_NODE_PROC+TEX_STUCCI, 0, "TEX_STUCCI", TexStucci, "Stucci", "" )
DefNode(TextureNode, TEX_NODE_PROC+TEX_DISTNOISE, 0, "TEX_DISTNOISE", TexDistNoise, "Distorted Noise", "" )
-DefNode(FunctionNode, FN_NODE_LEGACY_RANDOM_FLOAT, 0, "LEGACY_RANDOM_FLOAT", LegacyRandomFloat, "Random Float", "")
-
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, def_compare, "COMPARE", Compare, "Compare", "")
@@ -273,48 +271,6 @@ DefNode(FunctionNode, FN_NODE_SLICE_STRING, 0, "SLICE_STRING", SliceString, "Sli
DefNode(FunctionNode, FN_NODE_STRING_LENGTH, 0, "STRING_LENGTH", StringLength, "String Length", "")
DefNode(FunctionNode, FN_NODE_VALUE_TO_STRING, 0, "VALUE_TO_STRING", ValueToString, "Value to String", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ALIGN_ROTATION_TO_VECTOR, def_geo_align_rotation_to_vector, "LEGACY_ALIGN_ROTATION_TO_VECTOR", LegacyAlignRotationToVector, "Align Rotation to Vector", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, def_geo_attribute_clamp, "LEGACY_ATTRIBUTE_CLAMP", LegacyAttributeClamp, "Attribute Clamp", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP, def_geo_attribute_color_ramp, "LEGACY_ATTRIBUTE_COLOR_RAMP", LegacyAttributeColorRamp, "Attribute Color Ramp", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_COMBINE_XYZ, def_geo_attribute_combine_xyz, "LEGACY_ATTRIBUTE_COMBINE_XYZ", LegacyAttributeCombineXYZ, "Attribute Combine XYZ", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_COMPARE, def_geo_attribute_attribute_compare, "LEGACY_ATTRIBUTE_COMPARE", LegacyAttributeCompare, "Attribute Compare", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_CONVERT, def_geo_attribute_convert, "LEGACY_ATTRIBUTE_CONVERT", LegacyAttributeConvert, "Attribute Convert", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP, def_geo_attribute_curve_map, "LEGACY_ATTRIBUTE_CURVE_MAP", LegacyAttributeCurveMap, "Attribute Curve Map", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_FILL, def_geo_attribute_fill, "LEGACY_ATTRIBUTE_FILL", LegacyAttributeFill, "Attribute Fill", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE, def_geo_attribute_map_range, "LEGACY_ATTRIBUTE_MAP_RANGE", LegacyAttributeMapRange, "Attribute Map Range", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_MATH, def_geo_attribute_math, "LEGACY_ATTRIBUTE_MATH", LegacyAttributeMath, "Attribute Math", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_MIX, def_geo_attribute_mix, "LEGACY_ATTRIBUTE_MIX", LegacyAttributeMix, "Attribute Mix", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, def_geo_legacy_attribute_proximity, "LEGACY_ATTRIBUTE_PROXIMITY", LegacyAttributeProximity, "Attribute Proximity", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, def_geo_attribute_randomize, "LEGACY_ATTRIBUTE_RANDOMIZE", LegacyAttributeRandomize, "Attribute Randomize", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_REMOVE, 0, "LEGACY_ATTRIBUTE_REMOVE", LegacyAttributeRemove, "Attribute Remove", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE, 0, "LEGACY_ATTRIBUTE_SAMPLE_TEXTURE", LegacyAttributeSampleTexture, "Attribute Sample Texture", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ, def_geo_attribute_separate_xyz, "LEGACY_ATTRIBUTE_SEPARATE_XYZ", LegacyAttributeSeparateXYZ, "Attribute Separate XYZ", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, def_geo_attribute_transfer, "LEGACY_ATTRIBUTE_TRANSFER", LegacyAttributeTransfer, "Attribute Transfer", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_MATH, def_geo_attribute_vector_math, "LEGACY_ATTRIBUTE_VECTOR_MATH", LegacyAttributeVectorMath, "Attribute Vector Math", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_ROTATE, def_geo_attribute_vector_rotate, "LEGACY_ATTRIBUTE_VECTOR_ROTATE", LegacyAttributeVectorRotate, "Attribute Vector Rotate", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_ENDPOINTS, 0, "LEGACY_CURVE_ENDPOINTS", LegacyCurveEndpoints, "Curve Endpoints", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_REVERSE, 0, "LEGACY_CURVE_REVERSE", LegacyCurveReverse, "Curve Reverse", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SELECT_HANDLES, def_geo_curve_select_handles, "LEGACY_CURVE_SELECT_HANDLES", LegacyCurveSelectHandles, "Select by Handle Type", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SET_HANDLES, def_geo_legacy_curve_set_handles, "LEGACY_CURVE_SET_HANDLES", LegacyCurveSetHandles, "Set Handle Type", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, def_geo_curve_spline_type, "LEGACY_CURVE_SPLINE_TYPE", LegacyCurveSplineType, "Set Spline Type", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, def_geo_legacy_curve_subdivide, "LEGACY_CURVE_SUBDIVIDE", LegacyCurveSubdivide, "Curve Subdivide", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_CURVE_TO_POINTS, def_geo_legacy_curve_to_points, "LEGACY_CURVE_TO_POINTS", LegacyCurveToPoints, "Curve to Points", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_DELETE_GEOMETRY, 0, "LEGACY_DELETE_GEOMETRY", LegacyDeleteGeometry, "Delete Geometry", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_EDGE_SPLIT, 0, "LEGACY_EDGE_SPLIT", LegacyEdgeSplit, "Edge Split", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_MATERIAL_ASSIGN, 0, "LEGACY_MATERIAL_ASSIGN", LegacyMaterialAssign, "Material Assign", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_MESH_TO_CURVE, 0, "LEGACY_MESH_TO_CURVE", LegacyMeshToCurve, "Mesh to Curve", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_POINT_DISTRIBUTE, def_geo_point_distribute, "LEGACY_POINT_DISTRIBUTE", LegacyPointDistribute, "Point Distribute", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_POINT_INSTANCE, def_geo_point_instance, "LEGACY_POINT_INSTANCE", LegacyPointInstance, "Point Instance", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_POINT_ROTATE, def_geo_point_rotate, "LEGACY_POINT_ROTATE", LegacyRotatePoints, "Point Rotate", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_POINT_SCALE, def_geo_point_scale, "LEGACY_POINT_SCALE", LegacyPointScale, "Point Scale", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_POINT_SEPARATE, 0, "LEGACY_POINT_SEPARATE", LegacyPointSeparate, "Point Separate", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_POINT_TRANSLATE, def_geo_point_translate, "LEGACY_POINT_TRANSLATE", LegacyPointTranslate, "Point Translate", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_POINTS_TO_VOLUME, def_geo_legacy_points_to_volume, "LEGACY_POINTS_TO_VOLUME", LegacyPointsToVolume, "Points to Volume", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_RAYCAST, def_geo_legacy_raycast, "LEGACY_RAYCAST", LegacyRaycast, "Raycast", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, 0, "LEGACY_SELECT_BY_MATERIAL", LegacySelectByMaterial, "Select by Material", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "LEGACY_SUBDIVISION_SURFACE", LegacySubdivisionSurface, "Subdivision Surface", "")
-DefNode(GeometryNode, GEO_NODE_LEGACY_VOLUME_TO_MESH, def_geo_volume_to_mesh, "LEGACY_VOLUME_TO_MESH", LegacyVolumeToMesh, "Volume to Mesh", "")
-
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC", AttributeStatistic, "Attribute Statistic", "")
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "")
diff --git a/source/blender/nodes/composite/CMakeLists.txt b/source/blender/nodes/composite/CMakeLists.txt
index b8bdd9859e0..57f76f20ac6 100644
--- a/source/blender/nodes/composite/CMakeLists.txt
+++ b/source/blender/nodes/composite/CMakeLists.txt
@@ -93,9 +93,9 @@ set(SRC
nodes/node_composite_scene_time.cc
nodes/node_composite_sepcomb_hsva.cc
nodes/node_composite_sepcomb_rgba.cc
+ nodes/node_composite_sepcomb_xyz.cc
nodes/node_composite_sepcomb_ycca.cc
nodes/node_composite_sepcomb_yuva.cc
- nodes/node_composite_sepcomb_xyz.cc
nodes/node_composite_setalpha.cc
nodes/node_composite_split_viewer.cc
nodes/node_composite_stabilize2d.cc
diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc
index 7522ad1efe6..0b75dd9cef3 100644
--- a/source/blender/nodes/composite/node_composite_tree.cc
+++ b/source/blender/nodes/composite/node_composite_tree.cc
@@ -206,14 +206,12 @@ void ntreeCompositExecTree(Scene *scene,
RenderData *rd,
int rendering,
int do_preview,
- const ColorManagedViewSettings *view_settings,
- const ColorManagedDisplaySettings *display_settings,
const char *view_name)
{
#ifdef WITH_COMPOSITOR
- COM_execute(rd, scene, ntree, rendering, view_settings, display_settings, view_name);
+ COM_execute(rd, scene, ntree, rendering, view_name);
#else
- UNUSED_VARS(scene, ntree, rd, rendering, view_settings, display_settings, view_name);
+ UNUSED_VARS(scene, ntree, rd, rendering, view_name);
#endif
UNUSED_VARS(do_preview);
diff --git a/source/blender/nodes/composite/nodes/node_composite_output_file.cc b/source/blender/nodes/composite/nodes/node_composite_output_file.cc
index 2e1276dda24..1fd6e62b4c5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_output_file.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_output_file.cc
@@ -12,6 +12,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_image_format.h"
#include "RNA_access.h"
#include "RNA_prototypes.h"
@@ -21,9 +22,9 @@
#include "WM_api.h"
-#include "node_composite_util.hh"
+#include "IMB_openexr.h"
-#include "intern/openexr/openexr_multi.h"
+#include "node_composite_util.hh"
/* **************** OUTPUT FILE ******************** */
@@ -135,7 +136,7 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree,
}
}
else {
- BKE_imformat_defaults(&sockdata->format);
+ BKE_image_format_init(&sockdata->format, false);
}
/* use node data format by default */
sockdata->use_node_format = true;
@@ -205,7 +206,7 @@ static void init_output_file(const bContext *C, PointerRNA *ptr)
format = &nimf->format;
}
else {
- BKE_imformat_defaults(&nimf->format);
+ BKE_image_format_init(&nimf->format, false);
}
/* add one socket by default */
@@ -216,9 +217,13 @@ static void free_output_file(bNode *node)
{
/* free storage data in sockets */
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)sock->storage;
+ BKE_image_format_free(&sockdata->format);
MEM_freeN(sock->storage);
}
+ NodeImageMultiFile *nimf = (NodeImageMultiFile *)node->storage;
+ BKE_image_format_free(&nimf->format);
MEM_freeN(node->storage);
}
@@ -229,6 +234,9 @@ static void copy_output_file(bNodeTree *UNUSED(dest_ntree),
bNodeSocket *src_sock, *dest_sock;
dest_node->storage = MEM_dupallocN(src_node->storage);
+ NodeImageMultiFile *dest_nimf = (NodeImageMultiFile *)dest_node->storage;
+ NodeImageMultiFile *src_nimf = (NodeImageMultiFile *)src_node->storage;
+ BKE_image_format_copy(&dest_nimf->format, &src_nimf->format);
/* duplicate storage data in sockets */
for (src_sock = (bNodeSocket *)src_node->inputs.first,
@@ -236,6 +244,9 @@ static void copy_output_file(bNodeTree *UNUSED(dest_ntree),
src_sock && dest_sock;
src_sock = src_sock->next, dest_sock = (bNodeSocket *)dest_sock->next) {
dest_sock->storage = MEM_dupallocN(src_sock->storage);
+ NodeImageMultiFileSocket *dest_sockdata = (NodeImageMultiFileSocket *)dest_sock->storage;
+ NodeImageMultiFileSocket *src_sockdata = (NodeImageMultiFileSocket *)src_sock->storage;
+ BKE_image_format_copy(&dest_sockdata->format, &src_sockdata->format);
}
}
@@ -292,7 +303,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
node_composit_buts_file_output(layout, C, ptr);
- uiTemplateImageSettings(layout, &imfptr, false);
+ uiTemplateImageSettings(layout, &imfptr, true);
/* disable stereo output for multilayer, too much work for something that no one will use */
/* if someone asks for that we can implement it */
@@ -411,12 +422,16 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
ICON_NONE);
}
- col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, use_node_format == false);
- uiTemplateImageSettings(col, &imfptr, false);
+ if (!use_node_format) {
+ const bool use_color_management = RNA_boolean_get(&active_input_ptr, "save_as_render");
+
+ col = uiLayoutColumn(layout, false);
+ uiTemplateImageSettings(col, &imfptr, use_color_management);
- if (is_multiview) {
- uiTemplateImageFormatViews(layout, &imfptr, nullptr);
+ if (is_multiview) {
+ col = uiLayoutColumn(layout, false);
+ uiTemplateImageFormatViews(col, &imfptr, nullptr);
+ }
}
}
}
diff --git a/source/blender/nodes/function/CMakeLists.txt b/source/blender/nodes/function/CMakeLists.txt
index 7ffc5c71b66..6ccc4c7bf5c 100644
--- a/source/blender/nodes/function/CMakeLists.txt
+++ b/source/blender/nodes/function/CMakeLists.txt
@@ -18,8 +18,6 @@ set(INC
set(SRC
- nodes/legacy/node_fn_random_float.cc
-
nodes/node_fn_align_euler_to_vector.cc
nodes/node_fn_boolean_math.cc
nodes/node_fn_compare.cc
diff --git a/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc b/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
deleted file mode 100644
index a34cfe578d0..00000000000
--- a/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "node_function_util.hh"
-
-#include "BLI_hash.h"
-
-namespace blender::nodes::node_fn_random_float_cc {
-
-static void fn_node_legacy_random_float_declare(NodeDeclarationBuilder &b)
-{
- b.is_function_node();
- b.add_input<decl::Float>(N_("Min")).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Float>(N_("Max")).default_value(1.0f).min(-10000.0f).max(10000.0f);
- b.add_input<decl::Int>(N_("Seed")).min(-10000).max(10000);
- b.add_output<decl::Float>(N_("Value"));
-}
-
-class RandomFloatFunction : public blender::fn::MultiFunction {
- public:
- RandomFloatFunction()
- {
- static blender::fn::MFSignature signature = create_signature();
- this->set_signature(&signature);
- }
-
- static blender::fn::MFSignature create_signature()
- {
- blender::fn::MFSignatureBuilder signature{"Random float"};
- signature.single_input<float>("Min");
- signature.single_input<float>("Max");
- signature.single_input<int>("Seed");
- signature.single_output<float>("Value");
- return signature.build();
- }
-
- void call(blender::IndexMask mask,
- blender::fn::MFParams params,
- blender::fn::MFContext UNUSED(context)) const override
- {
- const blender::VArray<float> &min_values = params.readonly_single_input<float>(0, "Min");
- const blender::VArray<float> &max_values = params.readonly_single_input<float>(1, "Max");
- const blender::VArray<int> &seeds = params.readonly_single_input<int>(2, "Seed");
- blender::MutableSpan<float> values = params.uninitialized_single_output<float>(3, "Value");
-
- for (int64_t i : mask) {
- const float min_value = min_values[i];
- const float max_value = max_values[i];
- const int seed = seeds[i];
- const float value = BLI_hash_int_01(static_cast<uint32_t>(seed));
- values[i] = value * (max_value - min_value) + min_value;
- }
- }
-};
-
-static void fn_node_legacy_random_float_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
-{
- static RandomFloatFunction fn;
- builder.set_matching_fn(fn);
-}
-
-} // namespace blender::nodes::node_fn_random_float_cc
-
-void register_node_type_fn_legacy_random_float()
-{
- namespace file_ns = blender::nodes::node_fn_random_float_cc;
-
- static bNodeType ntype;
-
- fn_node_type_base(&ntype, FN_NODE_LEGACY_RANDOM_FLOAT, "Random Float", 0);
- ntype.declare = file_ns::fn_node_legacy_random_float_declare;
- ntype.build_multi_function = file_ns::fn_node_legacy_random_float_build_multi_function;
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
index 3718ce6f359..a4fc1a6bfd1 100644
--- a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
+++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
@@ -15,11 +15,20 @@ namespace blender::nodes::node_fn_rotate_euler_cc {
static void fn_node_rotate_euler_declare(NodeDeclarationBuilder &b)
{
+ auto enable_axis_angle = [](bNode &node) {
+ node.custom1 = FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE;
+ };
+
b.is_function_node();
b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).hide_value();
- b.add_input<decl::Vector>(N_("Rotate By")).subtype(PROP_EULER);
- b.add_input<decl::Vector>(N_("Axis")).default_value({0.0, 0.0, 1.0}).subtype(PROP_XYZ);
- b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE);
+ b.add_input<decl::Vector>(N_("Rotate By")).subtype(PROP_EULER).make_available([](bNode &node) {
+ node.custom1 = FN_NODE_ROTATE_EULER_TYPE_EULER;
+ });
+ b.add_input<decl::Vector>(N_("Axis"))
+ .default_value({0.0, 0.0, 1.0})
+ .subtype(PROP_XYZ)
+ .make_available(enable_axis_angle);
+ b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE).make_available(enable_axis_angle);
b.add_output<decl::Vector>(N_("Rotation"));
}
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index 0e99d8ad646..84280c0889a 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -25,48 +25,6 @@ set(INC
set(SRC
- 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_remove.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_accumulate_field.cc
nodes/node_geo_attribute_capture.cc
nodes/node_geo_attribute_domain_size.cc
@@ -100,9 +58,9 @@ set(SRC
nodes/node_geo_curve_to_points.cc
nodes/node_geo_curve_trim.cc
nodes/node_geo_delete_geometry.cc
- nodes/node_geo_duplicate_elements.cc
nodes/node_geo_distribute_points_on_faces.cc
nodes/node_geo_dual_mesh.cc
+ nodes/node_geo_duplicate_elements.cc
nodes/node_geo_edge_split.cc
nodes/node_geo_extrude_mesh.cc
nodes/node_geo_field_at_index.cc
@@ -197,6 +155,7 @@ set(LIB
bf_bmesh
bf_functions
bf_geometry
+ bf_nodes
)
if(WITH_BULLET)
diff --git a/source/blender/nodes/geometry/node_geometry_exec.cc b/source/blender/nodes/geometry/node_geometry_exec.cc
index 474bfaa214a..58ded7aadd2 100644
--- a/source/blender/nodes/geometry/node_geometry_exec.cc
+++ b/source/blender/nodes/geometry/node_geometry_exec.cc
@@ -1,10 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "FN_cpp_type_make.hh"
+#include "BLI_cpp_type_make.hh"
#include "NOD_geometry_exec.hh"
-MAKE_CPP_TYPE(GeometrySet, GeometrySet, CPPTypeFlags::Printable);
-
-namespace blender::nodes {
-
-}
+BLI_CPP_TYPE_MAKE(GeometrySet, GeometrySet, CPPTypeFlags::Printable);
diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc
index fc1c73d2851..7f9ec329efd 100644
--- a/source/blender/nodes/geometry/node_geometry_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -14,29 +14,6 @@
namespace blender::nodes {
-using bke::GeometryInstanceGroup;
-
-void update_attribute_input_socket_availabilities(bNodeTree &ntree,
- bNode &node,
- const StringRef name,
- const GeometryNodeAttributeInputMode mode,
- const bool name_is_available)
-{
- const GeometryNodeAttributeInputMode mode_ = (GeometryNodeAttributeInputMode)mode;
- LISTBASE_FOREACH (bNodeSocket *, socket, &node.inputs) {
- if (name == socket->name) {
- const bool socket_is_available =
- name_is_available &&
- ((socket->type == SOCK_STRING && mode_ == GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE) ||
- (socket->type == SOCK_FLOAT && mode_ == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) ||
- (socket->type == SOCK_INT && mode_ == GEO_NODE_ATTRIBUTE_INPUT_INTEGER) ||
- (socket->type == SOCK_VECTOR && mode_ == GEO_NODE_ATTRIBUTE_INPUT_VECTOR) ||
- (socket->type == SOCK_RGBA && mode_ == GEO_NODE_ATTRIBUTE_INPUT_COLOR));
- nodeSetSocketAvailability(&ntree, socket, socket_is_available);
- }
- }
-}
-
std::optional<CustomDataType> node_data_type_to_custom_data_type(const eNodeSocketDatatype type)
{
switch (type) {
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 101613acc21..5b7211e44b4 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -28,21 +28,6 @@ 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,
- GeometryNodeAttributeInputMode mode,
- bool name_is_available = true);
-
-Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component,
- AttributeDomain domain);
void transform_mesh(Mesh &mesh,
const float3 translation,
@@ -93,28 +78,6 @@ void separate_geometry(GeometrySet &geometry_set,
bool invert,
bool &r_is_error);
-struct CurveToPointsResults {
- int result_size;
- MutableSpan<float3> positions;
- MutableSpan<float> radii;
- MutableSpan<float> tilts;
-
- Map<AttributeIDRef, GMutableSpan> point_attributes;
-
- MutableSpan<float3> tangents;
- MutableSpan<float3> normals;
- MutableSpan<float3> rotations;
-};
-/**
- * Create references for all result point cloud attributes to simplify accessing them later on.
- */
-CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points,
- const CurveEval &curve);
-
-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);
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
deleted file mode 100644
index eefcfcb2880..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc
+++ /dev/null
@@ -1,228 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_math_rotation.h"
-#include "BLI_task.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_align_rotation_to_vector_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Factor"));
- b.add_input<decl::Float>(N_("Factor"), "Factor_001")
- .default_value(1.0f)
- .min(0.0f)
- .max(1.0f)
- .subtype(PROP_FACTOR);
- b.add_input<decl::String>(N_("Vector"));
- b.add_input<decl::Vector>(N_("Vector"), "Vector_001")
- .default_value({0.0, 0.0, 1.0})
- .subtype(PROP_ANGLE);
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-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);
- uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "pivot_axis", 0, IFACE_("Pivot"), ICON_NONE);
- uiLayout *col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "input_type_factor", 0, IFACE_("Factor"), ICON_NONE);
- uiItemR(col, ptr, "input_type_vector", 0, IFACE_("Vector"), ICON_NONE);
-}
-
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeGeometryAlignRotationToVector *node_storage = MEM_cnew<NodeGeometryAlignRotationToVector>(
- __func__);
-
- node_storage->axis = GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_X;
- node_storage->input_type_factor = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
- node_storage->input_type_vector = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
-
- node->storage = node_storage;
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *)
- node->storage;
- update_attribute_input_socket_availabilities(
- *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor);
- update_attribute_input_socket_availabilities(
- *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector);
-}
-
-static void align_rotations_auto_pivot(const VArray<float3> &vectors,
- const VArray<float> &factors,
- const float3 local_main_axis,
- const MutableSpan<float3> rotations)
-{
- threading::parallel_for(IndexRange(vectors.size()), 128, [&](IndexRange range) {
- for (const int i : range) {
- const float3 vector = vectors[i];
- if (is_zero_v3(vector)) {
- continue;
- }
-
- float old_rotation[3][3];
- eul_to_mat3(old_rotation, rotations[i]);
- float3 old_axis;
- mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
-
- const float3 new_axis = math::normalize(vector);
- float3 rotation_axis = math::cross_high_precision(old_axis, new_axis);
- if (is_zero_v3(rotation_axis)) {
- /* The vectors are linearly dependent, so we fall back to another axis. */
- rotation_axis = math::cross_high_precision(old_axis, float3(1, 0, 0));
- if (is_zero_v3(rotation_axis)) {
- /* This is now guaranteed to not be zero. */
- rotation_axis = math::cross_high_precision(old_axis, float3(0, 1, 0));
- }
- }
-
- const float full_angle = angle_normalized_v3v3(old_axis, new_axis);
- const float angle = factors[i] * full_angle;
-
- float rotation[3][3];
- axis_angle_to_mat3(rotation, rotation_axis, angle);
-
- float new_rotation_matrix[3][3];
- mul_m3_m3m3(new_rotation_matrix, rotation, old_rotation);
-
- float3 new_rotation;
- mat3_to_eul(new_rotation, new_rotation_matrix);
-
- rotations[i] = new_rotation;
- }
- });
-}
-
-static void align_rotations_fixed_pivot(const VArray<float3> &vectors,
- const VArray<float> &factors,
- const float3 local_main_axis,
- const float3 local_pivot_axis,
- const MutableSpan<float3> rotations)
-{
- if (local_main_axis == local_pivot_axis) {
- /* Can't compute any meaningful rotation angle in this case. */
- return;
- }
-
- threading::parallel_for(IndexRange(vectors.size()), 128, [&](IndexRange range) {
- for (const int i : range) {
- const float3 vector = vectors[i];
- if (is_zero_v3(vector)) {
- continue;
- }
-
- float old_rotation[3][3];
- eul_to_mat3(old_rotation, rotations[i]);
- float3 old_axis;
- mul_v3_m3v3(old_axis, old_rotation, local_main_axis);
- float3 pivot_axis;
- mul_v3_m3v3(pivot_axis, old_rotation, local_pivot_axis);
-
- float full_angle = angle_signed_on_axis_v3v3_v3(vector, old_axis, pivot_axis);
- if (full_angle > M_PI) {
- /* Make sure the point is rotated as little as possible. */
- full_angle -= 2.0f * M_PI;
- }
- const float angle = factors[i] * full_angle;
-
- float rotation[3][3];
- axis_angle_to_mat3(rotation, pivot_axis, angle);
-
- float new_rotation_matrix[3][3];
- mul_m3_m3m3(new_rotation_matrix, rotation, old_rotation);
-
- float3 new_rotation;
- mat3_to_eul(new_rotation, new_rotation_matrix);
-
- rotations[i] = new_rotation;
- }
- });
-}
-
-static void align_rotations_on_component(GeometryComponent &component,
- const GeoNodeExecParams &params)
-{
- const bNode &node = params.node();
- const NodeGeometryAlignRotationToVector &storage = *(const NodeGeometryAlignRotationToVector *)
- node.storage;
-
- OutputAttribute_Typed<float3> rotations = component.attribute_try_get_for_output<float3>(
- "rotation", ATTR_DOMAIN_POINT, {0, 0, 0});
- if (!rotations) {
- return;
- }
-
- VArray<float> factors = params.get_input_attribute<float>(
- "Factor", component, ATTR_DOMAIN_POINT, 1.0f);
- VArray<float3> vectors = params.get_input_attribute<float3>(
- "Vector", component, ATTR_DOMAIN_POINT, {0, 0, 1});
-
- float3 local_main_axis{0, 0, 0};
- local_main_axis[storage.axis] = 1;
- if (storage.pivot_axis == GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_AUTO) {
- align_rotations_auto_pivot(vectors, factors, local_main_axis, rotations.as_span());
- }
- else {
- float3 local_pivot_axis{0, 0, 0};
- local_pivot_axis[storage.pivot_axis - 1] = 1;
- align_rotations_fixed_pivot(
- vectors, factors, local_main_axis, local_pivot_axis, rotations.as_span());
- }
-
- rotations.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- 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);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- align_rotations_on_component(geometry_set.get_component_for_write<PointCloudComponent>(),
- params);
- }
- if (geometry_set.has<CurveComponent>()) {
- align_rotations_on_component(geometry_set.get_component_for_write<CurveComponent>(), params);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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,
- GEO_NODE_LEGACY_ALIGN_ROTATION_TO_VECTOR,
- "Align Rotation to Vector",
- NODE_CLASS_GEOMETRY);
- 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 = 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_legacy_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc
deleted file mode 100644
index 71cc2332c78..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc
+++ /dev/null
@@ -1,267 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_clamp_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Attribute"));
- b.add_input<decl::String>(N_("Result"));
- b.add_input<decl::Vector>(N_("Min"));
- b.add_input<decl::Vector>(N_("Max")).default_value({1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>(N_("Min"), "Min_001");
- b.add_input<decl::Float>(N_("Max"), "Max_001").default_value(1.0f);
- b.add_input<decl::Int>(N_("Min"), "Min_002").min(-100000).max(100000);
- b.add_input<decl::Int>(N_("Max"), "Max_002").default_value(100).min(-100000).max(100000);
- b.add_input<decl::Color>(N_("Min"), "Min_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_input<decl::Color>(N_("Max"), "Max_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-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 node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeAttributeClamp *data = MEM_cnew<NodeAttributeClamp>(__func__);
- data->data_type = CD_PROP_FLOAT;
- data->operation = NODE_CLAMP_MINMAX;
- node->storage = data;
-}
-
-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;
- bNodeSocket *sock_min_float = sock_max_vector->next;
- bNodeSocket *sock_max_float = sock_min_float->next;
- bNodeSocket *sock_min_int = sock_max_float->next;
- bNodeSocket *sock_max_int = sock_min_int->next;
- bNodeSocket *sock_min_color = sock_max_int->next;
- bNodeSocket *sock_max_color = sock_min_color->next;
-
- const NodeAttributeClamp &storage = *(const NodeAttributeClamp *)node->storage;
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
- nodeSetSocketAvailability(ntree, sock_min_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(ntree, sock_max_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(ntree, sock_min_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(ntree, sock_max_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(ntree, sock_min_int, data_type == CD_PROP_INT32);
- nodeSetSocketAvailability(ntree, sock_max_int, data_type == CD_PROP_INT32);
- nodeSetSocketAvailability(ntree, sock_min_color, data_type == CD_PROP_COLOR);
- nodeSetSocketAvailability(ntree, sock_max_color, data_type == CD_PROP_COLOR);
-}
-
-template<typename T> T clamp_value(const T val, const T min, const T max);
-
-template<> inline float clamp_value(const float val, const float min, const float max)
-{
- return std::min(std::max(val, min), max);
-}
-
-template<> inline int clamp_value(const int val, const int min, const int max)
-{
- return std::min(std::max(val, min), max);
-}
-
-template<> inline float3 clamp_value(const float3 val, const float3 min, const float3 max)
-{
- float3 tmp;
- tmp.x = std::min(std::max(val.x, min.x), max.x);
- tmp.y = std::min(std::max(val.y, min.y), max.y);
- tmp.z = std::min(std::max(val.z, min.z), max.z);
- return tmp;
-}
-
-template<>
-inline ColorGeometry4f clamp_value(const ColorGeometry4f val,
- const ColorGeometry4f min,
- const ColorGeometry4f max)
-{
- ColorGeometry4f tmp;
- tmp.r = std::min(std::max(val.r, min.r), max.r);
- tmp.g = std::min(std::max(val.g, min.g), max.g);
- tmp.b = std::min(std::max(val.b, min.b), max.b);
- tmp.a = std::min(std::max(val.a, min.a), max.a);
- return tmp;
-}
-
-template<typename T>
-static void clamp_attribute(const VArray<T> &inputs,
- const MutableSpan<T> outputs,
- const T min,
- const T max)
-{
- for (const int i : IndexRange(outputs.size())) {
- outputs[i] = clamp_value<T>(inputs[i], min, max);
- }
-}
-
-static AttributeDomain get_result_domain(const GeometryComponent &component,
- StringRef source_name,
- StringRef result_name)
-{
- std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
- if (result_info) {
- return result_info->domain;
- }
- std::optional<AttributeMetaData> source_info = component.attribute_get_meta_data(source_name);
- if (source_info) {
- return source_info->domain;
- }
- return ATTR_DOMAIN_POINT;
-}
-
-static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParams &params)
-{
- const std::string attribute_name = params.get_input<std::string>("Attribute");
- const std::string result_name = params.get_input<std::string>("Result");
-
- if (attribute_name.empty() || result_name.empty()) {
- return;
- }
-
- if (!component.attribute_exists(attribute_name)) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("No attribute with name \"") + attribute_name + "\"");
- return;
- }
-
- const NodeAttributeClamp &storage = *(const NodeAttributeClamp *)params.node().storage;
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
- const AttributeDomain domain = get_result_domain(component, attribute_name, result_name);
- const int operation = static_cast<int>(storage.operation);
-
- GVArray attribute_input = component.attribute_try_get_for_read(
- attribute_name, domain, data_type);
-
- OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
- result_name, domain, data_type);
-
- if (!attribute_result) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("Could not find or create attribute with name \"") +
- result_name + "\"");
- return;
- }
-
- switch (data_type) {
- case CD_PROP_FLOAT3: {
- float3 min = params.get_input<float3>("Min");
- float3 max = params.get_input<float3>("Max");
- if (operation == NODE_CLAMP_RANGE) {
- if (min.x > max.x) {
- std::swap(min.x, max.x);
- }
- if (min.y > max.y) {
- std::swap(min.y, max.y);
- }
- if (min.z > max.z) {
- std::swap(min.z, max.z);
- }
- }
- MutableSpan<float3> results = attribute_result.as_span<float3>();
- clamp_attribute<float3>(attribute_input.typed<float3>(), results, min, max);
- break;
- }
- case CD_PROP_FLOAT: {
- const float min = params.get_input<float>("Min_001");
- const float max = params.get_input<float>("Max_001");
- MutableSpan<float> results = attribute_result.as_span<float>();
- if (operation == NODE_CLAMP_RANGE && min > max) {
- clamp_attribute<float>(attribute_input.typed<float>(), results, max, min);
- }
- else {
- clamp_attribute<float>(attribute_input.typed<float>(), results, min, max);
- }
- break;
- }
- case CD_PROP_INT32: {
- const int min = params.get_input<int>("Min_002");
- const int max = params.get_input<int>("Max_002");
- MutableSpan<int> results = attribute_result.as_span<int>();
- if (operation == NODE_CLAMP_RANGE && min > max) {
- clamp_attribute<int>(attribute_input.typed<int>(), results, max, min);
- }
- else {
- clamp_attribute<int>(attribute_input.typed<int>(), results, min, max);
- }
- break;
- }
- case CD_PROP_COLOR: {
- ColorGeometry4f min = params.get_input<ColorGeometry4f>("Min_003");
- ColorGeometry4f max = params.get_input<ColorGeometry4f>("Max_003");
- if (operation == NODE_CLAMP_RANGE) {
- if (min.r > max.r) {
- std::swap(min.r, max.r);
- }
- if (min.g > max.g) {
- std::swap(min.g, max.g);
- }
- if (min.b > max.b) {
- std::swap(min.b, max.b);
- }
- if (min.a > max.a) {
- std::swap(min.a, max.a);
- }
- }
- MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>();
- clamp_attribute<ColorGeometry4f>(
- attribute_input.typed<ColorGeometry4f>(), results, min, max);
- break;
- }
- default: {
- BLI_assert(false);
- break;
- }
- }
-
- attribute_result.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- clamp_attribute(geometry_set.get_component_for_write<MeshComponent>(), params);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- clamp_attribute(geometry_set.get_component_for_write<PointCloudComponent>(), params);
- }
- if (geometry_set.has<CurveComponent>()) {
- clamp_attribute(geometry_set.get_component_for_write<CurveComponent>(), params);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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);
- 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_legacy_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
deleted file mode 100644
index 5a5cadaea12..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_task.hh"
-
-#include "BKE_colorband.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_color_ramp_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Attribute"));
- b.add_input<decl::String>(N_("Result"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiTemplateColorRamp(layout, ptr, "color_ramp", false);
-}
-
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeAttributeColorRamp *node_storage = MEM_cnew<NodeAttributeColorRamp>(__func__);
- BKE_colorband_init(&node_storage->color_ramp, true);
- node->storage = node_storage;
-}
-
-static AttributeDomain get_result_domain(const GeometryComponent &component,
- StringRef input_name,
- StringRef result_name)
-{
- /* Use the domain of the result attribute if it already exists. */
- std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
- if (result_info) {
- return result_info->domain;
- }
-
- /* Otherwise use the input attribute's domain if it exists. */
- std::optional<AttributeMetaData> source_info = component.attribute_get_meta_data(input_name);
- if (source_info) {
- return source_info->domain;
- }
-
- return ATTR_DOMAIN_POINT;
-}
-
-static void execute_on_component(const GeoNodeExecParams &params, GeometryComponent &component)
-{
- const bNode &bnode = params.node();
- NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)bnode.storage;
- const std::string result_name = params.get_input<std::string>("Result");
- const std::string input_name = params.get_input<std::string>("Attribute");
-
- /* Always output a color attribute for now. We might want to allow users to customize.
- * Using the type of an existing attribute could work, but does not have a real benefit
- * currently. */
- const AttributeDomain result_domain = get_result_domain(component, input_name, result_name);
-
- OutputAttribute_Typed<ColorGeometry4f> attribute_result =
- component.attribute_try_get_for_output_only<ColorGeometry4f>(result_name, result_domain);
- if (!attribute_result) {
- return;
- }
-
- VArray<float> attribute_in = component.attribute_get_for_read<float>(
- input_name, result_domain, 0.0f);
-
- MutableSpan<ColorGeometry4f> results = attribute_result.as_span();
-
- ColorBand *color_ramp = &node_storage->color_ramp;
- threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
- for (const int i : range) {
- BKE_colorband_evaluate(color_ramp, attribute_in[i], results[i]);
- }
- });
-
- attribute_result.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
- }
- if (geometry_set.has<PointCloudComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<PointCloudComponent>());
- }
- if (geometry_set.has<CurveComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<CurveComponent>());
- }
-
- params.set_output("Geometry", std::move(geometry_set));
-}
-
-} // namespace blender::nodes::node_geo_legacy_attribute_color_ramp_cc
-
-void register_node_type_geo_attribute_color_ramp()
-{
- namespace file_ns = blender::nodes::node_geo_legacy_attribute_color_ramp_cc;
-
- static bNodeType ntype;
-
- geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP, "Attribute Color Ramp", NODE_CLASS_ATTRIBUTE);
- node_type_storage(
- &ntype, "NodeAttributeColorRamp", node_free_standard_storage, node_copy_standard_storage);
- node_type_init(&ntype, file_ns::node_init);
- node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- 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_legacy_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
deleted file mode 100644
index ec6c65aa8bc..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_combine_xyz_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("X"));
- b.add_input<decl::Float>(N_("X"), "X_001");
- b.add_input<decl::String>(N_("Y"));
- b.add_input<decl::Float>(N_("Y"), "Y_001");
- b.add_input<decl::String>(N_("Z"));
- b.add_input<decl::Float>(N_("Z"), "Z_001");
- b.add_input<decl::String>(N_("Result"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiLayout *col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "input_type_x", 0, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "input_type_y", 0, IFACE_("Y"), ICON_NONE);
- uiItemR(col, ptr, "input_type_z", 0, IFACE_("Z"), ICON_NONE);
-}
-
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeAttributeCombineXYZ *data = MEM_cnew<NodeAttributeCombineXYZ>(__func__);
-
- data->input_type_x = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
- data->input_type_y = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
- data->input_type_z = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
- node->storage = data;
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeAttributeCombineXYZ *node_storage = (NodeAttributeCombineXYZ *)node->storage;
- update_attribute_input_socket_availabilities(
- *ntree, *node, "X", (GeometryNodeAttributeInputMode)node_storage->input_type_x);
- update_attribute_input_socket_availabilities(
- *ntree, *node, "Y", (GeometryNodeAttributeInputMode)node_storage->input_type_y);
- update_attribute_input_socket_availabilities(
- *ntree, *node, "Z", (GeometryNodeAttributeInputMode)node_storage->input_type_z);
-}
-
-static AttributeDomain get_result_domain(const GeometryComponent &component,
- const GeoNodeExecParams &params,
- StringRef result_name)
-{
- /* Use the domain of the result attribute if it already exists. */
- std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
- if (result_info) {
- return result_info->domain;
- }
-
- /* Otherwise use the highest priority domain from existing input attributes, or the default. */
- return params.get_highest_priority_input_domain({"X", "Y", "Z"}, component, ATTR_DOMAIN_POINT);
-}
-
-static void combine_attributes(GeometryComponent &component, const GeoNodeExecParams &params)
-{
- const std::string result_name = params.get_input<std::string>("Result");
- if (result_name.empty()) {
- return;
- }
- const AttributeDomain result_domain = get_result_domain(component, params, result_name);
-
- OutputAttribute_Typed<float3> attribute_result =
- component.attribute_try_get_for_output_only<float3>(result_name, result_domain);
- if (!attribute_result) {
- return;
- }
- VArray<float> attribute_x = params.get_input_attribute<float>(
- "X", component, result_domain, 0.0f);
- VArray<float> attribute_y = params.get_input_attribute<float>(
- "Y", component, result_domain, 0.0f);
- VArray<float> attribute_z = params.get_input_attribute<float>(
- "Z", component, result_domain, 0.0f);
-
- for (const int i : IndexRange(attribute_result->size())) {
- const float x = attribute_x[i];
- const float y = attribute_y[i];
- const float z = attribute_z[i];
- attribute_result->set(i, {x, y, z});
- }
- attribute_result.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- combine_attributes(geometry_set.get_component_for_write<MeshComponent>(), params);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- combine_attributes(geometry_set.get_component_for_write<PointCloudComponent>(), params);
- }
- if (geometry_set.has<CurveComponent>()) {
- combine_attributes(geometry_set.get_component_for_write<CurveComponent>(), params);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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,
- GEO_NODE_LEGACY_ATTRIBUTE_COMBINE_XYZ,
- "Attribute Combine XYZ",
- NODE_CLASS_ATTRIBUTE);
- 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 = 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_legacy_attribute_compare.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc
deleted file mode 100644
index 2136a07e58e..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc
+++ /dev/null
@@ -1,345 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "NOD_math_functions.hh"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_compare_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("A"));
- b.add_input<decl::Float>(N_("A"), "A_001");
- b.add_input<decl::Vector>(N_("A"), "A_002");
- b.add_input<decl::Color>(N_("A"), "A_003").default_value({0.5, 0.5, 0.5, 1.0});
- b.add_input<decl::String>(N_("B"));
- b.add_input<decl::Float>(N_("B"), "B_001");
- b.add_input<decl::Vector>(N_("B"), "B_002");
- b.add_input<decl::Color>(N_("B"), "B_003").default_value({0.5, 0.5, 0.5, 1.0});
- b.add_input<decl::Float>(N_("Threshold")).default_value(0.01f).min(0.0f);
- b.add_input<decl::String>(N_("Result"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "input_type_a", 0, IFACE_("A"), ICON_NONE);
- uiItemR(layout, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE);
-}
-
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeAttributeCompare *data = MEM_cnew<NodeAttributeCompare>(__func__);
- 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;
-}
-
-static bool operation_tests_equality(const NodeAttributeCompare &node_storage)
-{
- return ELEM(node_storage.operation, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL);
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node->storage;
- update_attribute_input_socket_availabilities(
- *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
- update_attribute_input_socket_availabilities(
- *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b);
-
- bNodeSocket *socket_threshold = (bNodeSocket *)BLI_findlink(&node->inputs, 9);
- nodeSetSocketAvailability(ntree, socket_threshold, operation_tests_equality(*node_storage));
-}
-
-static void do_math_operation(const VArray<float> &input_a,
- const VArray<float> &input_b,
- const NodeCompareOperation operation,
- MutableSpan<bool> span_result)
-{
- const int size = input_a.size();
-
- if (try_dispatch_float_math_fl_fl_to_bool(
- operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- for (const int i : IndexRange(size)) {
- const float a = input_a[i];
- const float b = input_b[i];
- const bool out = math_function(a, b);
- span_result[i] = out;
- }
- })) {
- return;
- }
-
- /* The operation is not supported by this node currently. */
- BLI_assert(false);
-}
-
-static void do_equal_operation_float(const VArray<float> &input_a,
- const VArray<float> &input_b,
- const float threshold,
- MutableSpan<bool> span_result)
-{
- const int size = input_a.size();
- for (const int i : IndexRange(size)) {
- const float a = input_a[i];
- const float b = input_b[i];
- span_result[i] = compare_ff(a, b, threshold);
- }
-}
-
-static void do_equal_operation_float3(const VArray<float3> &input_a,
- const VArray<float3> &input_b,
- const float threshold,
- MutableSpan<bool> span_result)
-{
- const float threshold_squared = pow2f(threshold);
- const int size = input_a.size();
- for (const int i : IndexRange(size)) {
- const float3 a = input_a[i];
- const float3 b = input_b[i];
- span_result[i] = len_squared_v3v3(a, b) < threshold_squared;
- }
-}
-
-static void do_equal_operation_color4f(const VArray<ColorGeometry4f> &input_a,
- const VArray<ColorGeometry4f> &input_b,
- const float threshold,
- MutableSpan<bool> span_result)
-{
- const float threshold_squared = pow2f(threshold);
- const int size = input_a.size();
- for (const int i : IndexRange(size)) {
- const ColorGeometry4f a = input_a[i];
- const ColorGeometry4f b = input_b[i];
- span_result[i] = len_squared_v4v4(a, b) < threshold_squared;
- }
-}
-
-static void do_equal_operation_bool(const VArray<bool> &input_a,
- const VArray<bool> &input_b,
- const float UNUSED(threshold),
- MutableSpan<bool> span_result)
-{
- const int size = input_a.size();
- for (const int i : IndexRange(size)) {
- const bool a = input_a[i];
- const bool b = input_b[i];
- span_result[i] = a == b;
- }
-}
-
-static void do_not_equal_operation_float(const VArray<float> &input_a,
- const VArray<float> &input_b,
- const float threshold,
- MutableSpan<bool> span_result)
-{
- const int size = input_a.size();
- for (const int i : IndexRange(size)) {
- const float a = input_a[i];
- const float b = input_b[i];
- span_result[i] = !compare_ff(a, b, threshold);
- }
-}
-
-static void do_not_equal_operation_float3(const VArray<float3> &input_a,
- const VArray<float3> &input_b,
- const float threshold,
- MutableSpan<bool> span_result)
-{
- const float threshold_squared = pow2f(threshold);
- const int size = input_a.size();
- for (const int i : IndexRange(size)) {
- const float3 a = input_a[i];
- const float3 b = input_b[i];
- span_result[i] = len_squared_v3v3(a, b) >= threshold_squared;
- }
-}
-
-static void do_not_equal_operation_color4f(const VArray<ColorGeometry4f> &input_a,
- const VArray<ColorGeometry4f> &input_b,
- const float threshold,
- MutableSpan<bool> span_result)
-{
- const float threshold_squared = pow2f(threshold);
- const int size = input_a.size();
- for (const int i : IndexRange(size)) {
- const ColorGeometry4f a = input_a[i];
- const ColorGeometry4f b = input_b[i];
- span_result[i] = len_squared_v4v4(a, b) >= threshold_squared;
- }
-}
-
-static void do_not_equal_operation_bool(const VArray<bool> &input_a,
- const VArray<bool> &input_b,
- const float UNUSED(threshold),
- MutableSpan<bool> span_result)
-{
- const int size = input_a.size();
- for (const int i : IndexRange(size)) {
- const bool a = input_a[i];
- const bool b = input_b[i];
- span_result[i] = a != b;
- }
-}
-
-static CustomDataType get_data_type(GeometryComponent &component,
- const GeoNodeExecParams &params,
- const NodeAttributeCompare &node_storage)
-{
- if (operation_tests_equality(node_storage)) {
- /* Convert the input attributes to the same data type for the equality tests. Use the higher
- * complexity attribute type, otherwise information necessary to the comparison may be lost. */
- return bke::attribute_data_type_highest_complexity({
- params.get_input_attribute_data_type("A", component, CD_PROP_FLOAT),
- params.get_input_attribute_data_type("B", component, CD_PROP_FLOAT),
- });
- }
-
- /* Use float compare for every operation besides equality. */
- return CD_PROP_FLOAT;
-}
-
-static AttributeDomain get_result_domain(const GeometryComponent &component,
- const GeoNodeExecParams &params,
- StringRef result_name)
-{
- /* Use the domain of the result attribute if it already exists. */
- std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
- if (result_info) {
- return result_info->domain;
- }
-
- /* Otherwise use the highest priority domain from existing input attributes, or the default. */
- return params.get_highest_priority_input_domain({"A", "B"}, component, ATTR_DOMAIN_POINT);
-}
-
-static void attribute_compare_calc(GeometryComponent &component, const GeoNodeExecParams &params)
-{
- const bNode &node = params.node();
- NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node.storage;
- const NodeCompareOperation operation = static_cast<NodeCompareOperation>(
- node_storage->operation);
- const std::string result_name = params.get_input<std::string>("Result");
-
- const AttributeDomain result_domain = get_result_domain(component, params, result_name);
-
- OutputAttribute_Typed<bool> attribute_result = component.attribute_try_get_for_output_only<bool>(
- result_name, result_domain);
- if (!attribute_result) {
- return;
- }
-
- const CustomDataType input_data_type = get_data_type(component, params, *node_storage);
-
- GVArray attribute_a = params.get_input_attribute(
- "A", component, result_domain, input_data_type, nullptr);
- GVArray attribute_b = params.get_input_attribute(
- "B", component, result_domain, input_data_type, nullptr);
-
- if (!attribute_a || !attribute_b) {
- /* Attribute wasn't found. */
- return;
- }
-
- MutableSpan<bool> result_span = attribute_result.as_span();
-
- /* Use specific types for correct equality operations, but for other operations we use implicit
- * 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_COMPARE_EQUAL) {
- if (input_data_type == CD_PROP_FLOAT) {
- do_equal_operation_float(
- attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span);
- }
- else if (input_data_type == CD_PROP_FLOAT3) {
- do_equal_operation_float3(
- attribute_a.typed<float3>(), attribute_b.typed<float3>(), threshold, result_span);
- }
- else if (input_data_type == CD_PROP_COLOR) {
- do_equal_operation_color4f(attribute_a.typed<ColorGeometry4f>(),
- attribute_b.typed<ColorGeometry4f>(),
- threshold,
- result_span);
- }
- else if (input_data_type == CD_PROP_BOOL) {
- do_equal_operation_bool(
- attribute_a.typed<bool>(), attribute_b.typed<bool>(), threshold, result_span);
- }
- }
- 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);
- }
- else if (input_data_type == CD_PROP_FLOAT3) {
- do_not_equal_operation_float3(
- attribute_a.typed<float3>(), attribute_b.typed<float3>(), threshold, result_span);
- }
- else if (input_data_type == CD_PROP_COLOR) {
- do_not_equal_operation_color4f(attribute_a.typed<ColorGeometry4f>(),
- attribute_b.typed<ColorGeometry4f>(),
- threshold,
- result_span);
- }
- else if (input_data_type == CD_PROP_BOOL) {
- do_not_equal_operation_bool(
- attribute_a.typed<bool>(), attribute_b.typed<bool>(), threshold, result_span);
- }
- }
- }
- else {
- do_math_operation(
- attribute_a.typed<float>(), attribute_b.typed<float>(), operation, result_span);
- }
-
- attribute_result.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- attribute_compare_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- attribute_compare_calc(geometry_set.get_component_for_write<PointCloudComponent>(), params);
- }
- if (geometry_set.has<CurveComponent>()) {
- attribute_compare_calc(geometry_set.get_component_for_write<CurveComponent>(), params);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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);
- 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, file_ns::node_init);
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc
deleted file mode 100644
index 5ded4efd4f7..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc
+++ /dev/null
@@ -1,179 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_convert_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Attribute"));
- b.add_input<decl::String>(N_("Result"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "domain", 0, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "data_type", 0, IFACE_("Type"), ICON_NONE);
-}
-
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeAttributeConvert *data = MEM_cnew<NodeAttributeConvert>(__func__);
-
- data->data_type = CD_AUTO_FROM_NAME;
- data->domain = ATTR_DOMAIN_AUTO;
- node->storage = data;
-}
-
-static AttributeMetaData get_result_domain_and_type(const GeometryComponent &component,
- const StringRef source_name,
- const StringRef result_name)
-{
- std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
- if (result_info) {
- return *result_info;
- }
- std::optional<AttributeMetaData> source_info = component.attribute_get_meta_data(source_name);
- if (source_info) {
- return *source_info;
- }
- /* The node won't do anything in this case, but we still have to return a value. */
- return AttributeMetaData{ATTR_DOMAIN_POINT, CD_PROP_BOOL};
-}
-
-static bool conversion_can_be_skipped(const GeometryComponent &component,
- const StringRef source_name,
- const StringRef result_name,
- const AttributeDomain result_domain,
- const CustomDataType result_type)
-{
- if (source_name != result_name) {
- return false;
- }
- std::optional<AttributeMetaData> info = component.attribute_get_meta_data(result_name);
- if (!info) {
- return false;
- }
- if (info->domain != result_domain) {
- return false;
- }
- if (info->data_type != result_type) {
- return false;
- }
- return true;
-}
-
-static void attribute_convert_calc(GeometryComponent &component,
- const GeoNodeExecParams &params,
- const StringRef source_name,
- const StringRef result_name,
- const CustomDataType data_type,
- const AttributeDomain domain)
-{
- const AttributeMetaData auto_info = get_result_domain_and_type(
- component, source_name, result_name);
- const AttributeDomain result_domain = (domain == ATTR_DOMAIN_AUTO) ? auto_info.domain : domain;
- const CustomDataType result_type = (data_type == CD_AUTO_FROM_NAME) ? auto_info.data_type :
- data_type;
-
- if (conversion_can_be_skipped(component, source_name, result_name, result_domain, result_type)) {
- return;
- }
-
- GVArray source_attribute = component.attribute_try_get_for_read(
- source_name, result_domain, result_type);
- if (!source_attribute) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("No attribute with name \"") + source_name + "\"");
- return;
- }
-
- OutputAttribute result_attribute = component.attribute_try_get_for_output_only(
- result_name, result_domain, result_type);
- if (!result_attribute) {
- return;
- }
-
- GVArray_GSpan source_span{source_attribute};
- GMutableSpan result_span = result_attribute.as_span();
-
- BLI_assert(source_span.size() == result_span.size());
-
- const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(result_type);
- BLI_assert(cpp_type != nullptr);
-
- cpp_type->copy_assign_n(source_span.data(), result_span.data(), result_span.size());
- result_attribute.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- 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");
- const NodeAttributeConvert &node_storage = *(const NodeAttributeConvert *)params.node().storage;
- const CustomDataType data_type = static_cast<CustomDataType>(node_storage.data_type);
- const AttributeDomain domain = static_cast<AttributeDomain>(node_storage.domain);
-
- if (result_name.empty()) {
- params.set_default_remaining_outputs();
- return;
- }
-
- if (geometry_set.has<MeshComponent>()) {
- attribute_convert_calc(geometry_set.get_component_for_write<MeshComponent>(),
- params,
- source_name,
- result_name,
- data_type,
- domain);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- attribute_convert_calc(geometry_set.get_component_for_write<PointCloudComponent>(),
- params,
- source_name,
- result_name,
- data_type,
- domain);
- }
- if (geometry_set.has<CurveComponent>()) {
- attribute_convert_calc(geometry_set.get_component_for_write<CurveComponent>(),
- params,
- source_name,
- result_name,
- data_type,
- domain);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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);
- 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);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc
deleted file mode 100644
index 800587e2157..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc
+++ /dev/null
@@ -1,208 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_blenlib.h"
-#include "BLI_task.hh"
-
-#include "BKE_colortools.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_curve_map_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Attribute"));
- b.add_input<decl::String>(N_("Result"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
- bNode *node = (bNode *)ptr->data;
- NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage;
- switch (data->data_type) {
- case CD_PROP_FLOAT:
- uiTemplateCurveMapping(layout, ptr, "curve_vec", 0, false, false, false, false);
- break;
- case CD_PROP_FLOAT3:
- uiTemplateCurveMapping(layout, ptr, "curve_vec", 'v', false, false, false, false);
- break;
- case CD_PROP_COLOR:
- uiTemplateCurveMapping(layout, ptr, "curve_rgb", 'c', false, false, false, false);
- break;
- }
-}
-
-static void node_free_storage(bNode *node)
-{
- if (node->storage) {
- NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage;
- BKE_curvemapping_free(data->curve_vec);
- BKE_curvemapping_free(data->curve_rgb);
- MEM_freeN(node->storage);
- }
-}
-
-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;
- NodeAttributeCurveMap *dest_data = (NodeAttributeCurveMap *)dest_node->storage;
- dest_data->curve_vec = BKE_curvemapping_copy(src_data->curve_vec);
- dest_data->curve_rgb = BKE_curvemapping_copy(src_data->curve_rgb);
-}
-
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeAttributeCurveMap *data = MEM_cnew<NodeAttributeCurveMap>(__func__);
-
- data->data_type = CD_PROP_FLOAT;
- data->curve_vec = BKE_curvemapping_add(4, -1.0f, -1.0f, 1.0f, 1.0f);
- data->curve_vec->cur = 3;
- data->curve_rgb = BKE_curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f);
- node->storage = data;
-}
-
-static void node_update(bNodeTree *UNUSED(ntree), bNode *node)
-{
- /* Set the active curve when data type is changed. */
- NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage;
- if (data->data_type == CD_PROP_FLOAT) {
- data->curve_vec->cur = 3;
- }
- else if (data->data_type == CD_PROP_FLOAT3) {
- data->curve_vec->cur = 0;
- }
-}
-
-static AttributeDomain get_result_domain(const GeometryComponent &component,
- StringRef input_name,
- StringRef result_name)
-{
- /* Use the domain of the result attribute if it already exists. */
- std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
- if (result_info) {
- return result_info->domain;
- }
- /* Otherwise use the input attribute's domain if it exists. */
- std::optional<AttributeMetaData> input_info = component.attribute_get_meta_data(input_name);
- if (input_info) {
- return input_info->domain;
- }
-
- return ATTR_DOMAIN_POINT;
-}
-
-static void execute_on_component(const GeoNodeExecParams &params, GeometryComponent &component)
-{
- const bNode &bnode = params.node();
- NodeAttributeCurveMap &node_storage = *(NodeAttributeCurveMap *)bnode.storage;
- const std::string result_name = params.get_input<std::string>("Result");
- const std::string input_name = params.get_input<std::string>("Attribute");
-
- const CustomDataType result_type = (CustomDataType)node_storage.data_type;
- const AttributeDomain result_domain = get_result_domain(component, input_name, result_name);
-
- OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
- result_name, result_domain, result_type);
- if (!attribute_result) {
- return;
- }
-
- switch (result_type) {
- case CD_PROP_FLOAT: {
- const CurveMapping *cumap = (CurveMapping *)node_storage.curve_vec;
- VArray<float> attribute_in = component.attribute_get_for_read<float>(
- input_name, result_domain, float(0.0f));
- MutableSpan<float> results = attribute_result.as_span<float>();
- threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- results[i] = BKE_curvemapping_evaluateF(cumap, 3, attribute_in[i]);
- }
- });
- break;
- }
- case CD_PROP_FLOAT3: {
- const CurveMapping *cumap = (CurveMapping *)node_storage.curve_vec;
- VArray<float3> attribute_in = component.attribute_get_for_read<float3>(
- input_name, result_domain, float3(0.0f));
- MutableSpan<float3> results = attribute_result.as_span<float3>();
- threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- BKE_curvemapping_evaluate3F(cumap, results[i], attribute_in[i]);
- }
- });
- break;
- }
- case CD_PROP_COLOR: {
- const CurveMapping *cumap = (CurveMapping *)node_storage.curve_rgb;
- VArray<ColorGeometry4f> attribute_in = component.attribute_get_for_read<ColorGeometry4f>(
- input_name, result_domain, ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f));
- MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>();
- threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- BKE_curvemapping_evaluateRGBF(cumap, results[i], attribute_in[i]);
- }
- });
- break;
- }
- default: {
- BLI_assert_unreachable();
- break;
- }
- }
-
- attribute_result.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- const bNode &bnode = params.node();
- NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)bnode.storage;
- BKE_curvemapping_init(data->curve_vec);
- BKE_curvemapping_init(data->curve_rgb);
-
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
- }
- if (geometry_set.has<PointCloudComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<PointCloudComponent>());
- }
- if (geometry_set.has<CurveComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<CurveComponent>());
- }
-
- params.set_output("Geometry", std::move(geometry_set));
-}
-
-} // 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);
- 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", 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_legacy_attribute_fill.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc
deleted file mode 100644
index 21fe8e12e65..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc
+++ /dev/null
@@ -1,151 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_fill_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Attribute")).is_attribute_name();
- b.add_input<decl::Vector>(N_("Value"), "Value");
- b.add_input<decl::Float>(N_("Value"), "Value_001");
- b.add_input<decl::Color>(N_("Value"), "Value_002");
- b.add_input<decl::Bool>(N_("Value"), "Value_003");
- b.add_input<decl::Int>(N_("Value"), "Value_004");
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
-}
-
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- node->custom1 = CD_PROP_FLOAT;
- node->custom2 = ATTR_DOMAIN_AUTO;
-}
-
-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;
- bNodeSocket *socket_value_color4f = socket_value_float->next;
- bNodeSocket *socket_value_boolean = socket_value_color4f->next;
- bNodeSocket *socket_value_int32 = socket_value_boolean->next;
-
- const CustomDataType data_type = static_cast<CustomDataType>(node->custom1);
-
- nodeSetSocketAvailability(ntree, socket_value_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(ntree, socket_value_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(ntree, socket_value_color4f, data_type == CD_PROP_COLOR);
- nodeSetSocketAvailability(ntree, socket_value_boolean, data_type == CD_PROP_BOOL);
- nodeSetSocketAvailability(ntree, socket_value_int32, data_type == CD_PROP_INT32);
-}
-
-static AttributeDomain get_result_domain(const GeometryComponent &component, const StringRef name)
-{
- /* Use the domain of the result attribute if it already exists. */
- std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(name);
- if (result_info) {
- return result_info->domain;
- }
- return ATTR_DOMAIN_POINT;
-}
-
-static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams &params)
-{
- const std::string attribute_name = params.get_input<std::string>("Attribute");
- if (attribute_name.empty()) {
- return;
- }
-
- const bNode &node = params.node();
- const CustomDataType data_type = static_cast<CustomDataType>(node.custom1);
- const AttributeDomain domain = static_cast<AttributeDomain>(node.custom2);
- const AttributeDomain result_domain = (domain == ATTR_DOMAIN_AUTO) ?
- get_result_domain(component, attribute_name) :
- domain;
-
- OutputAttribute attribute = component.attribute_try_get_for_output_only(
- attribute_name, result_domain, data_type);
- if (!attribute) {
- return;
- }
-
- switch (data_type) {
- case CD_PROP_FLOAT: {
- const float value = params.get_input<float>("Value_001");
- attribute->fill(&value);
- break;
- }
- case CD_PROP_FLOAT3: {
- const float3 value = params.get_input<float3>("Value");
- attribute->fill(&value);
- break;
- }
- case CD_PROP_COLOR: {
- const ColorGeometry4f value = params.get_input<ColorGeometry4f>("Value_002");
- attribute->fill(&value);
- break;
- }
- case CD_PROP_BOOL: {
- const bool value = params.get_input<bool>("Value_003");
- attribute->fill(&value);
- break;
- }
- case CD_PROP_INT32: {
- const int value = params.get_input<int>("Value_004");
- attribute->fill(&value);
- break;
- }
- default:
- break;
- }
-
- attribute.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- fill_attribute(geometry_set.get_component_for_write<MeshComponent>(), params);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- fill_attribute(geometry_set.get_component_for_write<PointCloudComponent>(), params);
- }
- if (geometry_set.has<CurveComponent>()) {
- fill_attribute(geometry_set.get_component_for_write<CurveComponent>(), params);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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);
- 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_legacy_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc
deleted file mode 100644
index 05440b09442..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc
+++ /dev/null
@@ -1,422 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_math_base_safe.h"
-#include "BLI_task.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_map_range_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Attribute"));
- b.add_input<decl::String>(N_("Result"));
- b.add_input<decl::Float>(N_("From Min"));
- b.add_input<decl::Float>(N_("From Max")).default_value(1.0f);
- b.add_input<decl::Float>(N_("To Min"));
- b.add_input<decl::Float>(N_("To Max")).default_value(1.0f);
- b.add_input<decl::Float>(N_("Steps")).default_value(4.0f);
- b.add_input<decl::Vector>(N_("From Min"), "From Min_001");
- b.add_input<decl::Vector>(N_("From Max"), "From Max_001").default_value({1.0f, 1.0f, 1.0f});
- b.add_input<decl::Vector>(N_("To Min"), "To Min_001");
- b.add_input<decl::Vector>(N_("To Max"), "To Max_001").default_value({1.0f, 1.0f, 1.0f});
- b.add_input<decl::Vector>(N_("Steps"), "Steps_001").default_value({4.0f, 4.0f, 4.0f});
- b.add_input<decl::Bool>(N_("Clamp"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE);
-}
-
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeAttributeMapRange *data = MEM_cnew<NodeAttributeMapRange>(__func__);
- data->data_type = CD_PROP_FLOAT;
- data->interpolation_type = NODE_MAP_RANGE_LINEAR;
-
- node->storage = data;
-}
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node->storage;
-
- bNodeSocket *sock_from_min_float = (bNodeSocket *)BLI_findlink(&node->inputs, 3);
- bNodeSocket *sock_from_max_float = sock_from_min_float->next;
- bNodeSocket *sock_to_min_float = sock_from_max_float->next;
- bNodeSocket *sock_to_max_float = sock_to_min_float->next;
- bNodeSocket *sock_steps_float = sock_to_max_float->next;
-
- bNodeSocket *sock_from_min_vector = sock_steps_float->next;
- bNodeSocket *sock_from_max_vector = sock_from_min_vector->next;
- bNodeSocket *sock_to_min_vector = sock_from_max_vector->next;
- bNodeSocket *sock_to_max_vector = sock_to_min_vector->next;
- bNodeSocket *sock_steps_vector = sock_to_max_vector->next;
-
- bNodeSocket *sock_clamp = sock_steps_vector->next;
-
- const CustomDataType data_type = static_cast<CustomDataType>(node_storage.data_type);
-
- nodeSetSocketAvailability(ntree,
- sock_clamp,
- node_storage.interpolation_type == NODE_MAP_RANGE_LINEAR ||
- node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED);
-
- nodeSetSocketAvailability(ntree, sock_from_min_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(ntree, sock_from_max_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(ntree, sock_to_min_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(ntree, sock_to_max_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(ntree,
- sock_steps_float,
- data_type == CD_PROP_FLOAT &&
- node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED);
-
- nodeSetSocketAvailability(ntree, sock_from_min_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(ntree, sock_from_max_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(ntree, sock_to_min_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(ntree, sock_to_max_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(ntree,
- sock_steps_vector,
- data_type == CD_PROP_FLOAT3 &&
- node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED);
-}
-
-static float map_linear(const float value,
- const float min_from,
- const float max_from,
- const float min_to,
- const float max_to)
-{
- /* First we calculate a fraction that measures how far along
- * the [min_from, max_from] interval the value lies.
- *
- * value
- * min_from [------>|------------------------] max_from
- * factor (e.g. 0.25)
- *
- * Then to find where the value is mapped, we add the same fraction
- * of the [min_to, max_to] interval to min_to.
- *
- * min_to [--->|-----------] max_to
- * v
- * min_to + (max_to - min_to) * factor
- */
- const float factor = safe_divide(value - min_from, max_from - min_from);
- return min_to + factor * (max_to - min_to);
-}
-
-static float map_stepped(const float value,
- const float min_from,
- const float max_from,
- const float min_to,
- const float max_to,
- const float steps)
-{
- /* First the factor is calculated here in the same way as for the linear mapping.
- *
- * Then the factor is mapped to multiples of 1.0 / steps.
- * This is best understood with a few examples. Assume steps == 3.
- * ____________________________________
- * | factor | * 4.0 | floor() | / 3.0 |
- * |--------|-------|---------|-------|
- * | 0.0 | 0.0 | 0.0 | 0.0 |
- * | 0.1 | 0.4 | 0.0 | 0.0 |
- * | 0.25 | 1.0 | 1.0 | 0.333 |
- * | 0.45 | 1.8 | 1.0 | 0.333 |
- * | 0.5 | 2.0 | 2.0 | 0.666 |
- * | 0.55 | 2.2 | 2.0 | 0.666 |
- * | 0.999 | 3.999 | 3.0 | 1.0 |
- * | 1.0 | 4.0 | 4.0 | 1.333 |
- * ------------------------------------
- * Note that the factor is not always mapped the closest multiple of 1.0 /steps.
- */
- const float factor = safe_divide(value - min_from, max_from - min_from);
- const float factor_mapped = safe_divide(floorf(factor * (steps + 1.0f)), steps);
- return min_to + factor_mapped * (max_to - min_to);
-}
-
-static float smoothstep_polynomial(float x)
-{
- /* This polynomial is only meant to be used for the [0, 1] range. */
- return (3.0f - 2.0f * x) * (x * x);
-}
-
-static float map_smoothstep(const float value,
- const float min_from,
- const float max_from,
- const float min_to,
- const float max_to)
-{
- const float factor = safe_divide(value - min_from, max_from - min_from);
- const float factor_clamped = std::clamp(factor, 0.0f, 1.0f);
- const float factor_mapped = smoothstep_polynomial(factor_clamped);
- return min_to + factor_mapped * (max_to - min_to);
-}
-
-static float smootherstep_polynomial(float x)
-{
- /* This polynomial is only meant to be used for the [0, 1] range. */
- return x * x * x * (x * (x * 6.0f - 15.0f) + 10.0f);
-}
-
-static float map_smootherstep(const float value,
- const float min_from,
- const float max_from,
- const float min_to,
- const float max_to)
-{
- const float factor = safe_divide(value - min_from, max_from - min_from);
- const float factor_clamped = std::clamp(factor, 0.0f, 1.0f);
- const float factor_mapped = smootherstep_polynomial(factor_clamped);
- return min_to + factor_mapped * (max_to - min_to);
-}
-
-static void map_range_float(const VArray<float> &attribute_input,
- MutableSpan<float> results,
- const GeoNodeExecParams &params)
-{
- const bNode &node = params.node();
- NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node.storage;
- const int interpolation_type = node_storage.interpolation_type;
- const float min_from = params.get_input<float>("From Min");
- const float max_from = params.get_input<float>("From Max");
- const float min_to = params.get_input<float>("To Min");
- const float max_to = params.get_input<float>("To Max");
-
- VArray_Span<float> span{attribute_input};
-
- switch (interpolation_type) {
- case NODE_MAP_RANGE_LINEAR: {
- threading::parallel_for(span.index_range(), 2048, [&](IndexRange range) {
- for (const int i : range) {
- results[i] = map_linear(span[i], min_from, max_from, min_to, max_to);
- }
- });
- break;
- }
- case NODE_MAP_RANGE_STEPPED: {
- const float steps = params.get_input<float>("Steps");
- threading::parallel_for(span.index_range(), 1024, [&](IndexRange range) {
- for (const int i : range) {
- results[i] = map_stepped(span[i], min_from, max_from, min_to, max_to, steps);
- }
- });
- break;
- }
- case NODE_MAP_RANGE_SMOOTHSTEP: {
- threading::parallel_for(span.index_range(), 1024, [&](IndexRange range) {
- for (const int i : range) {
- results[i] = map_smoothstep(span[i], min_from, max_from, min_to, max_to);
- }
- });
- break;
- }
- case NODE_MAP_RANGE_SMOOTHERSTEP: {
- threading::parallel_for(span.index_range(), 1024, [&](IndexRange range) {
- for (const int i : range) {
- results[i] = map_smootherstep(span[i], min_from, max_from, min_to, max_to);
- }
- });
- break;
- }
- }
-
- if (ELEM(interpolation_type, NODE_MAP_RANGE_LINEAR, NODE_MAP_RANGE_STEPPED) &&
- params.get_input<bool>("Clamp")) {
- /* Users can specify min_to > max_to, but clamping expects min < max. */
- const float clamp_min = min_to < max_to ? min_to : max_to;
- const float clamp_max = min_to < max_to ? max_to : min_to;
-
- threading::parallel_for(results.index_range(), 2048, [&](IndexRange range) {
- for (const int i : range) {
- results[i] = std::clamp(results[i], clamp_min, clamp_max);
- }
- });
- }
-}
-
-static void map_range_float3(const VArray<float3> &attribute_input,
- const MutableSpan<float3> results,
- const GeoNodeExecParams &params)
-{
- const bNode &node = params.node();
- NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node.storage;
- const int interpolation_type = node_storage.interpolation_type;
- const float3 min_from = params.get_input<float3>("From Min_001");
- const float3 max_from = params.get_input<float3>("From Max_001");
- const float3 min_to = params.get_input<float3>("To Min_001");
- const float3 max_to = params.get_input<float3>("To Max_001");
-
- VArray_Span<float3> span{attribute_input};
-
- switch (interpolation_type) {
- case NODE_MAP_RANGE_LINEAR: {
- threading::parallel_for(span.index_range(), 1024, [&](IndexRange range) {
- for (const int i : range) {
- results[i].x = map_linear(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
- results[i].y = map_linear(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
- results[i].z = map_linear(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
- }
- });
- break;
- }
- case NODE_MAP_RANGE_STEPPED: {
- const float3 steps = params.get_input<float3>("Steps_001");
- threading::parallel_for(span.index_range(), 1024, [&](IndexRange range) {
- for (const int i : range) {
- results[i].x = map_stepped(
- span[i].x, min_from.x, max_from.x, min_to.x, max_to.x, steps.x);
- results[i].y = map_stepped(
- span[i].y, min_from.y, max_from.y, min_to.y, max_to.y, steps.y);
- results[i].z = map_stepped(
- span[i].z, min_from.z, max_from.z, min_to.z, max_to.z, steps.z);
- }
- });
- break;
- }
- case NODE_MAP_RANGE_SMOOTHSTEP: {
- threading::parallel_for(span.index_range(), 1024, [&](IndexRange range) {
- for (const int i : range) {
- results[i].x = map_smoothstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
- results[i].y = map_smoothstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
- results[i].z = map_smoothstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
- }
- });
- break;
- }
- case NODE_MAP_RANGE_SMOOTHERSTEP: {
- threading::parallel_for(span.index_range(), 1024, [&](IndexRange range) {
- for (const int i : range) {
- results[i].x = map_smootherstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
- results[i].y = map_smootherstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
- results[i].z = map_smootherstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
- }
- });
- break;
- }
- }
-
- if (ELEM(interpolation_type, NODE_MAP_RANGE_LINEAR, NODE_MAP_RANGE_STEPPED) &&
- params.get_input<bool>("Clamp")) {
- /* Users can specify min_to > max_to, but clamping expects min < max. */
- float3 clamp_min;
- float3 clamp_max;
- clamp_min.x = min_to.x < max_to.x ? min_to.x : max_to.x;
- clamp_max.x = min_to.x < max_to.x ? max_to.x : min_to.x;
- clamp_min.y = min_to.y < max_to.y ? min_to.y : max_to.y;
- clamp_max.y = min_to.y < max_to.y ? max_to.y : min_to.y;
- clamp_min.z = min_to.z < max_to.z ? min_to.z : max_to.z;
- clamp_max.z = min_to.z < max_to.z ? max_to.z : min_to.z;
-
- for (int i : results.index_range()) {
- clamp_v3_v3v3(results[i], clamp_min, clamp_max);
- }
- }
-}
-
-static AttributeDomain get_result_domain(const GeometryComponent &component,
- StringRef source_name,
- StringRef result_name)
-{
- std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
- if (result_info) {
- return result_info->domain;
- }
- std::optional<AttributeMetaData> source_info = component.attribute_get_meta_data(source_name);
- if (source_info) {
- return source_info->domain;
- }
- return ATTR_DOMAIN_POINT;
-}
-
-static void map_range_attribute(GeometryComponent &component, const GeoNodeExecParams &params)
-{
- const std::string input_name = params.get_input<std::string>("Attribute");
- const std::string result_name = params.get_input<std::string>("Result");
-
- if (input_name.empty() || result_name.empty()) {
- return;
- }
-
- const bNode &node = params.node();
- NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node.storage;
- const CustomDataType data_type = static_cast<CustomDataType>(node_storage.data_type);
-
- const AttributeDomain domain = get_result_domain(component, input_name, result_name);
-
- GVArray attribute_input = component.attribute_try_get_for_read(input_name, domain, data_type);
-
- if (!attribute_input) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("No attribute with name \"") + input_name + "\"");
- return;
- }
-
- OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
- result_name, domain, data_type);
- if (!attribute_result) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("Could not find or create attribute with name \"") +
- result_name + "\"");
- return;
- }
-
- switch (data_type) {
- case CD_PROP_FLOAT: {
- map_range_float(attribute_input.typed<float>(), attribute_result.as_span<float>(), params);
- break;
- }
- case CD_PROP_FLOAT3: {
- map_range_float3(
- attribute_input.typed<float3>(), attribute_result.as_span<float3>(), params);
- break;
- }
- default:
- BLI_assert_unreachable();
- }
-
- attribute_result.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- if (geometry_set.has<MeshComponent>()) {
- map_range_attribute(geometry_set.get_component_for_write<MeshComponent>(), params);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- map_range_attribute(geometry_set.get_component_for_write<PointCloudComponent>(), params);
- }
- if (geometry_set.has<CurveComponent>()) {
- map_range_attribute(geometry_set.get_component_for_write<CurveComponent>(), params);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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);
- 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 = 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_legacy_attribute_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc
deleted file mode 100644
index 9e909ec749b..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc
+++ /dev/null
@@ -1,308 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_task.hh"
-
-#include "RNA_enum_types.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "NOD_math_functions.hh"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_math_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("A"));
- b.add_input<decl::Float>(N_("A"), "A_001");
- b.add_input<decl::String>(N_("B"));
- b.add_input<decl::Float>(N_("B"), "B_001");
- b.add_input<decl::String>(N_("C"));
- b.add_input<decl::Float>(N_("C"), "C_001");
- b.add_input<decl::String>(N_("Result"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static bool operation_use_input_c(const NodeMathOperation operation)
-{
- return ELEM(operation,
- NODE_MATH_MULTIPLY_ADD,
- NODE_MATH_SMOOTH_MIN,
- NODE_MATH_SMOOTH_MAX,
- NODE_MATH_WRAP,
- NODE_MATH_COMPARE);
-}
-
-static bool operation_use_input_b(const NodeMathOperation operation)
-{
- switch (operation) {
- case NODE_MATH_ADD:
- case NODE_MATH_SUBTRACT:
- case NODE_MATH_MULTIPLY:
- case NODE_MATH_DIVIDE:
- case NODE_MATH_POWER:
- case NODE_MATH_LOGARITHM:
- case NODE_MATH_MINIMUM:
- case NODE_MATH_MAXIMUM:
- case NODE_MATH_LESS_THAN:
- case NODE_MATH_GREATER_THAN:
- case NODE_MATH_MODULO:
- case NODE_MATH_ARCTAN2:
- case NODE_MATH_SNAP:
- case NODE_MATH_WRAP:
- case NODE_MATH_COMPARE:
- case NODE_MATH_MULTIPLY_ADD:
- case NODE_MATH_PINGPONG:
- case NODE_MATH_SMOOTH_MIN:
- case NODE_MATH_SMOOTH_MAX:
- return true;
- case NODE_MATH_SINE:
- case NODE_MATH_COSINE:
- case NODE_MATH_TANGENT:
- case NODE_MATH_ARCSINE:
- case NODE_MATH_ARCCOSINE:
- case NODE_MATH_ARCTANGENT:
- case NODE_MATH_ROUND:
- case NODE_MATH_ABSOLUTE:
- case NODE_MATH_FLOOR:
- case NODE_MATH_CEIL:
- case NODE_MATH_FRACTION:
- case NODE_MATH_SQRT:
- case NODE_MATH_INV_SQRT:
- case NODE_MATH_SIGN:
- case NODE_MATH_EXPONENT:
- case NODE_MATH_RADIANS:
- case NODE_MATH_DEGREES:
- case NODE_MATH_SINH:
- case NODE_MATH_COSH:
- case NODE_MATH_TANH:
- case NODE_MATH_TRUNC:
- return false;
- }
- BLI_assert(false);
- return false;
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage;
- NodeMathOperation operation = (NodeMathOperation)node_storage->operation;
-
- uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
-
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "input_type_a", 0, IFACE_("A"), ICON_NONE);
- if (operation_use_input_b(operation)) {
- uiItemR(layout, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE);
- }
- if (operation_use_input_c(operation)) {
- uiItemR(layout, ptr, "input_type_c", 0, IFACE_("C"), ICON_NONE);
- }
-}
-
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeAttributeMath *data = MEM_cnew<NodeAttributeMath>(__func__);
-
- data->operation = NODE_MATH_ADD;
- data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
- data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
- data->input_type_c = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
- node->storage = data;
-}
-
-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;
- bool enum_label = RNA_enum_name(rna_enum_node_math_items, node_storage.operation, &name);
- if (!enum_label) {
- name = "Unknown";
- }
- BLI_strncpy(label, IFACE_(name), maxlen);
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage;
- NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage.operation);
-
- update_attribute_input_socket_availabilities(
- *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage.input_type_a);
- update_attribute_input_socket_availabilities(
- *ntree,
- *node,
- "B",
- (GeometryNodeAttributeInputMode)node_storage.input_type_b,
- operation_use_input_b(operation));
- update_attribute_input_socket_availabilities(
- *ntree,
- *node,
- "C",
- (GeometryNodeAttributeInputMode)node_storage.input_type_c,
- operation_use_input_c(operation));
-}
-
-static void do_math_operation(const VArray<float> &span_a,
- const VArray<float> &span_b,
- const VArray<float> &span_c,
- MutableSpan<float> span_result,
- const NodeMathOperation operation)
-{
- bool success = try_dispatch_float_math_fl_fl_fl_to_fl(
- operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- threading::parallel_for(IndexRange(span_result.size()), 512, [&](IndexRange range) {
- for (const int i : range) {
- span_result[i] = math_function(span_a[i], span_b[i], span_c[i]);
- }
- });
- });
- BLI_assert(success);
- UNUSED_VARS_NDEBUG(success);
-}
-
-static void do_math_operation(const VArray<float> &span_a,
- const VArray<float> &span_b,
- MutableSpan<float> span_result,
- const NodeMathOperation operation)
-{
- bool success = try_dispatch_float_math_fl_fl_to_fl(
- operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- threading::parallel_for(IndexRange(span_result.size()), 1024, [&](IndexRange range) {
- for (const int i : range) {
- span_result[i] = math_function(span_a[i], span_b[i]);
- }
- });
- });
- BLI_assert(success);
- UNUSED_VARS_NDEBUG(success);
-}
-
-static void do_math_operation(const VArray<float> &span_input,
- MutableSpan<float> span_result,
- const NodeMathOperation operation)
-{
- bool success = try_dispatch_float_math_fl_to_fl(
- operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- threading::parallel_for(IndexRange(span_result.size()), 1024, [&](IndexRange range) {
- for (const int i : range) {
- span_result[i] = math_function(span_input[i]);
- }
- });
- });
- BLI_assert(success);
- UNUSED_VARS_NDEBUG(success);
-}
-
-static AttributeDomain get_result_domain(const GeometryComponent &component,
- const GeoNodeExecParams &params,
- const NodeMathOperation operation,
- StringRef result_name)
-{
- /* Use the domain of the result attribute if it already exists. */
- std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
- if (result_info) {
- return result_info->domain;
- }
-
- /* Otherwise use the highest priority domain from existing input attributes, or the default. */
- const AttributeDomain default_domain = ATTR_DOMAIN_POINT;
- if (operation_use_input_b(operation)) {
- if (operation_use_input_c(operation)) {
- return params.get_highest_priority_input_domain({"A", "B", "C"}, component, default_domain);
- }
- return params.get_highest_priority_input_domain({"A", "B"}, component, default_domain);
- }
- return params.get_highest_priority_input_domain({"A"}, component, default_domain);
-}
-
-static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecParams &params)
-{
- const bNode &node = params.node();
- const NodeAttributeMath *node_storage = (const NodeAttributeMath *)node.storage;
- const NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage->operation);
- const std::string result_name = params.get_input<std::string>("Result");
-
- /* The result type of this node is always float. */
- const AttributeDomain result_domain = get_result_domain(
- component, params, operation, result_name);
-
- OutputAttribute_Typed<float> attribute_result =
- component.attribute_try_get_for_output_only<float>(result_name, result_domain);
- if (!attribute_result) {
- return;
- }
-
- VArray<float> attribute_a = params.get_input_attribute<float>(
- "A", component, result_domain, 0.0f);
-
- MutableSpan<float> result_span = attribute_result.as_span();
-
- /* Note that passing the data with `get_internal_span<float>()` works
- * because the attributes were accessed with #CD_PROP_FLOAT. */
- if (operation_use_input_b(operation)) {
- VArray<float> attribute_b = params.get_input_attribute<float>(
- "B", component, result_domain, 0.0f);
- if (operation_use_input_c(operation)) {
- VArray<float> attribute_c = params.get_input_attribute<float>(
- "C", component, result_domain, 0.0f);
- do_math_operation(attribute_a, attribute_b, attribute_c, result_span, operation);
- }
- else {
- do_math_operation(attribute_a, attribute_b, result_span, operation);
- }
- }
- else {
- do_math_operation(attribute_a, result_span, operation);
- }
-
- attribute_result.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- attribute_math_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- attribute_math_calc(geometry_set.get_component_for_write<PointCloudComponent>(), params);
- }
- if (geometry_set.has<CurveComponent>()) {
- attribute_math_calc(geometry_set.get_component_for_write<CurveComponent>(), params);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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);
- 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_legacy_attribute_mix.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc
deleted file mode 100644
index aab33e1ef01..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc
+++ /dev/null
@@ -1,245 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_task.hh"
-
-#include "BKE_material.h"
-
-#include "DNA_material_types.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_mix_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Factor"));
- b.add_input<decl::Float>(N_("Factor"), "Factor_001")
- .default_value(0.5f)
- .min(0.0f)
- .max(1.0f)
- .subtype(PROP_FACTOR);
- b.add_input<decl::String>(N_("A"));
- b.add_input<decl::Float>(N_("A"), "A_001");
- b.add_input<decl::Vector>(N_("A"), "A_002");
- b.add_input<decl::Color>(N_("A"), "A_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_input<decl::String>(N_("B"));
- b.add_input<decl::Float>(N_("B"), "B_001");
- b.add_input<decl::Vector>(N_("B"), "B_002");
- b.add_input<decl::Color>(N_("B"), "B_003").default_value({0.5f, 0.5f, 0.5f, 1.0f});
- b.add_input<decl::String>(N_("Result"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "blend_type", 0, "", ICON_NONE);
- uiLayout *col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "input_type_factor", 0, IFACE_("Factor"), ICON_NONE);
- uiItemR(col, ptr, "input_type_a", 0, IFACE_("A"), ICON_NONE);
- uiItemR(col, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE);
-}
-
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeAttributeMix *data = MEM_cnew<NodeAttributeMix>("attribute mix node");
- data->blend_type = MA_RAMP_BLEND;
- data->input_type_factor = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
- data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
- data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
- node->storage = data;
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeAttributeMix *node_storage = (NodeAttributeMix *)node->storage;
- update_attribute_input_socket_availabilities(
- *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor);
- update_attribute_input_socket_availabilities(
- *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
- update_attribute_input_socket_availabilities(
- *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b);
-}
-
-static void do_mix_operation_float(const int blend_mode,
- const VArray<float> &factors,
- const VArray<float> &inputs_a,
- const VArray<float> &inputs_b,
- VMutableArray<float> &results)
-{
- const int size = results.size();
- threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
- for (const int i : range) {
- const float factor = factors[i];
- float3 a{inputs_a[i]};
- const float3 b{inputs_b[i]};
- ramp_blend(blend_mode, a, factor, b);
- const float result = a.x;
- results.set(i, result);
- }
- });
-}
-
-static void do_mix_operation_float3(const int blend_mode,
- const VArray<float> &factors,
- const VArray<float3> &inputs_a,
- const VArray<float3> &inputs_b,
- VMutableArray<float3> &results)
-{
- const int size = results.size();
- threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
- for (const int i : range) {
- const float factor = factors[i];
- float3 a = inputs_a[i];
- const float3 b = inputs_b[i];
- ramp_blend(blend_mode, a, factor, b);
- results.set(i, a);
- }
- });
-}
-
-static void do_mix_operation_color4f(const int blend_mode,
- const VArray<float> &factors,
- const VArray<ColorGeometry4f> &inputs_a,
- const VArray<ColorGeometry4f> &inputs_b,
- VMutableArray<ColorGeometry4f> &results)
-{
- const int size = results.size();
- threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
- for (const int i : range) {
- const float factor = factors[i];
- ColorGeometry4f a = inputs_a[i];
- const ColorGeometry4f b = inputs_b[i];
- ramp_blend(blend_mode, a, factor, b);
- results.set(i, a);
- }
- });
-}
-
-static void do_mix_operation(const CustomDataType result_type,
- int blend_mode,
- const VArray<float> &attribute_factor,
- const GVArray &attribute_a,
- const GVArray &attribute_b,
- GVMutableArray &attribute_result)
-{
- if (result_type == CD_PROP_FLOAT) {
- VMutableArray<float> result = attribute_result.typed<float>();
- do_mix_operation_float(blend_mode,
- attribute_factor,
- attribute_a.typed<float>(),
- attribute_b.typed<float>(),
- result);
- }
- else if (result_type == CD_PROP_FLOAT3) {
- VMutableArray<float3> result = attribute_result.typed<float3>();
- do_mix_operation_float3(blend_mode,
- attribute_factor,
- attribute_a.typed<float3>(),
- attribute_b.typed<float3>(),
- result);
- }
- else if (result_type == CD_PROP_COLOR) {
- VMutableArray<ColorGeometry4f> result = attribute_result.typed<ColorGeometry4f>();
- do_mix_operation_color4f(blend_mode,
- attribute_factor,
- attribute_a.typed<ColorGeometry4f>(),
- attribute_b.typed<ColorGeometry4f>(),
- result);
- }
-}
-
-static AttributeDomain get_result_domain(const GeometryComponent &component,
- const GeoNodeExecParams &params,
- StringRef result_name)
-{
- /* Use the domain of the result attribute if it already exists. */
- std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
- if (result_info) {
- return result_info->domain;
- }
-
- /* Otherwise use the highest priority domain from existing input attributes, or the default. */
- return params.get_highest_priority_input_domain({"A", "B"}, component, ATTR_DOMAIN_POINT);
-}
-
-static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecParams &params)
-{
- const bNode &node = params.node();
- const NodeAttributeMix *node_storage = (const NodeAttributeMix *)node.storage;
- const std::string result_name = params.get_input<std::string>("Result");
-
- /* Use the highest complexity data type among the inputs and outputs, that way the node will
- * never "remove information". Use CD_PROP_BOOL as the lowest complexity data type, but in any
- * real situation it won't be returned. */
- const CustomDataType result_type = bke::attribute_data_type_highest_complexity({
- params.get_input_attribute_data_type("A", component, CD_PROP_BOOL),
- params.get_input_attribute_data_type("B", component, CD_PROP_BOOL),
- params.get_input_attribute_data_type("Result", component, CD_PROP_BOOL),
- });
-
- const AttributeDomain result_domain = get_result_domain(component, params, result_name);
-
- OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
- result_name, result_domain, result_type);
- if (!attribute_result) {
- return;
- }
-
- VArray<float> attribute_factor = params.get_input_attribute<float>(
- "Factor", component, result_domain, 0.5f);
- GVArray attribute_a = params.get_input_attribute(
- "A", component, result_domain, result_type, nullptr);
- GVArray attribute_b = params.get_input_attribute(
- "B", component, result_domain, result_type, nullptr);
-
- do_mix_operation(result_type,
- node_storage->blend_type,
- attribute_factor,
- attribute_a,
- attribute_b,
- attribute_result.varray());
- attribute_result.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- attribute_mix_calc(geometry_set.get_component_for_write<MeshComponent>(), params);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- attribute_mix_calc(geometry_set.get_component_for_write<PointCloudComponent>(), params);
- }
- if (geometry_set.has<CurveComponent>()) {
- attribute_mix_calc(geometry_set.get_component_for_write<CurveComponent>(), params);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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);
- 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 = file_ns::node_geo_exec;
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc
deleted file mode 100644
index a3af6200ab8..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc
+++ /dev/null
@@ -1,237 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_task.hh"
-#include "BLI_timeit.hh"
-
-#include "DNA_mesh_types.h"
-
-#include "BKE_bvhutils.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_proximity_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::Geometry>(N_("Target"));
- b.add_input<decl::String>(N_("Distance"));
- b.add_input<decl::String>(N_("Position"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "target_geometry_element", 0, "", ICON_NONE);
-}
-
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeGeometryAttributeProximity *node_storage = MEM_cnew<NodeGeometryAttributeProximity>(
- __func__);
-
- node_storage->target_geometry_element = GEO_NODE_PROXIMITY_TARGET_FACES;
- node->storage = node_storage;
-}
-
-static void calculate_mesh_proximity(const VArray<float3> &positions,
- const Mesh &mesh,
- const GeometryNodeAttributeProximityTargetType type,
- MutableSpan<float> r_distances,
- MutableSpan<float3> r_locations)
-{
- BVHTreeFromMesh bvh_data;
- switch (type) {
- case GEO_NODE_PROXIMITY_TARGET_POINTS:
- BKE_bvhtree_from_mesh_get(&bvh_data, &mesh, BVHTREE_FROM_VERTS, 2);
- break;
- case GEO_NODE_PROXIMITY_TARGET_EDGES:
- BKE_bvhtree_from_mesh_get(&bvh_data, &mesh, BVHTREE_FROM_EDGES, 2);
- break;
- case GEO_NODE_PROXIMITY_TARGET_FACES:
- BKE_bvhtree_from_mesh_get(&bvh_data, &mesh, BVHTREE_FROM_LOOPTRI, 2);
- break;
- }
-
- if (bvh_data.tree == nullptr) {
- return;
- }
-
- threading::parallel_for(positions.index_range(), 512, [&](IndexRange range) {
- BVHTreeNearest nearest;
- copy_v3_fl(nearest.co, FLT_MAX);
- nearest.index = -1;
-
- for (int i : range) {
- /* Use the distance to the last found point as upper bound to speedup the bvh lookup. */
- nearest.dist_sq = math::distance_squared(float3(nearest.co), positions[i]);
-
- BLI_bvhtree_find_nearest(
- bvh_data.tree, positions[i], &nearest, bvh_data.nearest_callback, &bvh_data);
-
- if (nearest.dist_sq < r_distances[i]) {
- r_distances[i] = nearest.dist_sq;
- if (!r_locations.is_empty()) {
- r_locations[i] = nearest.co;
- }
- }
- }
- });
-
- free_bvhtree_from_mesh(&bvh_data);
-}
-
-static void calculate_pointcloud_proximity(const VArray<float3> &positions,
- const PointCloud &pointcloud,
- MutableSpan<float> r_distances,
- MutableSpan<float3> r_locations)
-{
- BVHTreeFromPointCloud bvh_data;
- BKE_bvhtree_from_pointcloud_get(&bvh_data, &pointcloud, 2);
- if (bvh_data.tree == nullptr) {
- return;
- }
-
- threading::parallel_for(positions.index_range(), 512, [&](IndexRange range) {
- BVHTreeNearest nearest;
- copy_v3_fl(nearest.co, FLT_MAX);
- nearest.index = -1;
-
- for (int i : range) {
- /* Use the distance to the closest point in the mesh to speedup the pointcloud bvh lookup.
- * This is ok because we only need to find the closest point in the pointcloud if it's
- * closer than the mesh. */
- nearest.dist_sq = r_distances[i];
-
- BLI_bvhtree_find_nearest(
- bvh_data.tree, positions[i], &nearest, bvh_data.nearest_callback, &bvh_data);
-
- if (nearest.dist_sq < r_distances[i]) {
- r_distances[i] = nearest.dist_sq;
- if (!r_locations.is_empty()) {
- r_locations[i] = nearest.co;
- }
- }
- }
- });
-
- free_bvhtree_from_pointcloud(&bvh_data);
-}
-
-static void attribute_calc_proximity(GeometryComponent &component,
- GeometrySet &target,
- GeoNodeExecParams &params)
-{
- const std::string distance_name = params.get_input<std::string>("Distance");
- OutputAttribute_Typed<float> distance_attribute =
- component.attribute_try_get_for_output_only<float>(distance_name, ATTR_DOMAIN_POINT);
-
- const std::string location_name = params.get_input<std::string>("Position");
- OutputAttribute_Typed<float3> location_attribute =
- component.attribute_try_get_for_output_only<float3>(location_name, ATTR_DOMAIN_POINT);
-
- ReadAttributeLookup position_attribute = component.attribute_try_get_for_read("position");
- if (!position_attribute || (!distance_attribute && !location_attribute)) {
- return;
- }
- VArray<float3> positions = position_attribute.varray.typed<float3>();
- const NodeGeometryAttributeProximity &storage =
- *(const NodeGeometryAttributeProximity *)params.node().storage;
-
- Array<float> distances_internal;
- MutableSpan<float> distances;
- if (distance_attribute) {
- distances = distance_attribute.as_span();
- }
- else {
- /* Theoretically it would be possible to avoid using the distance array when it's not required
- * and there is only one component. However, this only adds an allocation and a single float
- * comparison per vertex, so it's likely not worth it. */
- distances_internal.reinitialize(positions.size());
- distances = distances_internal;
- }
- distances.fill(FLT_MAX);
- MutableSpan<float3> locations = location_attribute ? location_attribute.as_span() :
- MutableSpan<float3>();
-
- if (target.has_mesh()) {
- calculate_mesh_proximity(
- positions,
- *target.get_mesh_for_read(),
- static_cast<GeometryNodeAttributeProximityTargetType>(storage.target_geometry_element),
- distances,
- locations);
- }
-
- if (target.has_pointcloud() &&
- storage.target_geometry_element == GEO_NODE_PROXIMITY_TARGET_POINTS) {
- calculate_pointcloud_proximity(
- positions, *target.get_pointcloud_for_read(), distances, locations);
- }
-
- if (distance_attribute) {
- /* Squared distances are used above to speed up comparisons,
- * so do the square roots now if necessary for the output attribute. */
- threading::parallel_for(distances.index_range(), 2048, [&](IndexRange range) {
- for (const int i : range) {
- distances[i] = std::sqrt(distances[i]);
- }
- });
- distance_attribute.save();
- }
- if (location_attribute) {
- location_attribute.save();
- }
-}
-
-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::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::realize_instances_legacy(geometry_set_target);
-
- if (geometry_set.has<MeshComponent>()) {
- attribute_calc_proximity(
- geometry_set.get_component_for_write<MeshComponent>(), geometry_set_target, params);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- attribute_calc_proximity(
- geometry_set.get_component_for_write<PointCloudComponent>(), geometry_set_target, params);
- }
- if (geometry_set.has<CurveComponent>()) {
- attribute_calc_proximity(
- geometry_set.get_component_for_write<CurveComponent>(), geometry_set_target, params);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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);
- node_type_init(&ntype, file_ns::node_init);
- node_type_storage(&ntype,
- "NodeGeometryAttributeProximity",
- node_free_standard_storage,
- node_copy_standard_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_legacy_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc
deleted file mode 100644
index 6a306229b8c..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc
+++ /dev/null
@@ -1,333 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_hash.h"
-#include "BLI_rand.hh"
-#include "BLI_task.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes {
-
-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"));
- b.add_input<decl::Vector>(N_("Min"));
- b.add_input<decl::Vector>(N_("Max")).default_value({1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>(N_("Min"), "Min_001");
- b.add_input<decl::Float>(N_("Max"), "Max_001").default_value(1.0f);
- b.add_input<decl::Int>(N_("Min"), "Min_002").min(-100000).max(100000);
- b.add_input<decl::Int>(N_("Max"), "Max_002").default_value(100).min(-100000).max(100000);
- b.add_input<decl::Int>(N_("Seed")).min(-10000).max(10000);
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-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 node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeAttributeRandomize *data = MEM_cnew<NodeAttributeRandomize>(__func__);
- data->data_type = CD_PROP_FLOAT;
- data->domain = ATTR_DOMAIN_POINT;
- data->operation = GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE;
- node->storage = data;
-}
-
-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;
- bNodeSocket *sock_min_float = sock_max_vector->next;
- bNodeSocket *sock_max_float = sock_min_float->next;
- bNodeSocket *sock_min_int = sock_max_float->next;
- bNodeSocket *sock_max_int = sock_min_int->next;
-
- const NodeAttributeRandomize &storage = *(const NodeAttributeRandomize *)node->storage;
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
- nodeSetSocketAvailability(ntree, sock_min_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(ntree, sock_max_vector, data_type == CD_PROP_FLOAT3);
- nodeSetSocketAvailability(ntree, sock_min_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(ntree, sock_max_float, data_type == CD_PROP_FLOAT);
- nodeSetSocketAvailability(ntree, sock_min_int, data_type == CD_PROP_INT32);
- nodeSetSocketAvailability(ntree, sock_max_int, data_type == CD_PROP_INT32);
-}
-
-template<typename T>
-T random_value_in_range(const uint32_t id, const uint32_t seed, const T min, const T max);
-
-template<>
-inline float random_value_in_range(const uint32_t id,
- const uint32_t seed,
- const float min,
- const float max)
-{
- return BLI_hash_int_2d_to_float(id, seed) * (max - min) + min;
-}
-
-template<>
-inline int random_value_in_range(const uint32_t id,
- const uint32_t seed,
- const int min,
- const int max)
-{
- return round_fl_to_int(
- random_value_in_range<float>(id, seed, static_cast<float>(min), static_cast<float>(max)));
-}
-
-template<>
-inline float3 random_value_in_range(const uint32_t id,
- const uint32_t seed,
- const float3 min,
- const float3 max)
-{
- const float x = BLI_hash_int_3d_to_float(seed, id, 435109);
- const float y = BLI_hash_int_3d_to_float(seed, id, 380867);
- const float z = BLI_hash_int_3d_to_float(seed, id, 1059217);
-
- return float3(x, y, z) * (max - min) + min;
-}
-
-template<typename T>
-static void randomize_attribute(MutableSpan<T> span,
- const T min,
- const T max,
- Span<uint32_t> ids,
- const uint32_t seed,
- const GeometryNodeAttributeRandomizeMode operation)
-{
- /* The operations could be templated too, but it doesn't make the code much shorter. */
- switch (operation) {
- case GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE:
- threading::parallel_for(span.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- const T random_value = random_value_in_range<T>(ids[i], seed, min, max);
- span[i] = random_value;
- }
- });
- break;
- case GEO_NODE_ATTRIBUTE_RANDOMIZE_ADD:
- threading::parallel_for(span.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- const T random_value = random_value_in_range<T>(ids[i], seed, min, max);
- span[i] = span[i] + random_value;
- }
- });
- break;
- case GEO_NODE_ATTRIBUTE_RANDOMIZE_SUBTRACT:
- threading::parallel_for(span.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- const T random_value = random_value_in_range<T>(ids[i], seed, min, max);
- span[i] = span[i] - random_value;
- }
- });
- break;
- case GEO_NODE_ATTRIBUTE_RANDOMIZE_MULTIPLY:
- threading::parallel_for(span.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- const T random_value = random_value_in_range<T>(ids[i], seed, min, max);
- span[i] = span[i] * random_value;
- }
- });
- break;
- default:
- BLI_assert(false);
- break;
- }
-}
-
-static void randomize_attribute_bool(MutableSpan<bool> span,
- Span<uint32_t> ids,
- const uint32_t seed,
- const GeometryNodeAttributeRandomizeMode operation)
-{
- BLI_assert(operation == GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE);
- UNUSED_VARS_NDEBUG(operation);
- threading::parallel_for(span.index_range(), 512, [&](IndexRange range) {
- for (const int i : range) {
- const bool random_value = BLI_hash_int_2d_to_float(ids[i], seed) > 0.5f;
- span[i] = random_value;
- }
- });
-}
-
-static AttributeDomain get_result_domain(const GeometryComponent &component,
- const GeoNodeExecParams &params,
- const StringRef name)
-{
- /* Use the domain of the result attribute if it already exists. */
- std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(name);
- if (result_info) {
- return result_info->domain;
- }
-
- /* Otherwise use the input domain chosen in the interface. */
- const bNode &node = params.node();
- return static_cast<AttributeDomain>(node.custom2);
-}
-
-static void randomize_attribute_on_component(GeometryComponent &component,
- const GeoNodeExecParams &params,
- StringRef attribute_name,
- const CustomDataType data_type,
- const GeometryNodeAttributeRandomizeMode operation,
- const int seed)
-{
- /* If the node is not in "replace / create" mode and the attribute
- * doesn't already exist, don't do the operation. */
- if (operation != GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE) {
- if (!component.attribute_exists(attribute_name)) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("No attribute with name \"") + attribute_name + "\"");
- return;
- }
- }
-
- const AttributeDomain domain = get_result_domain(component, params, attribute_name);
-
- OutputAttribute attribute = component.attribute_try_get_for_output(
- attribute_name, domain, data_type);
- if (!attribute) {
- return;
- }
-
- GMutableSpan span = attribute.as_span();
-
- Array<uint32_t> hashes = get_geometry_element_ids_as_uints(component, domain);
-
- switch (data_type) {
- case CD_PROP_FLOAT3: {
- const float3 min = params.get_input<float3>("Min");
- const float3 max = params.get_input<float3>("Max");
- randomize_attribute<float3>(span.typed<float3>(), min, max, hashes, seed, operation);
- break;
- }
- case CD_PROP_FLOAT: {
- const float min = params.get_input<float>("Min_001");
- const float max = params.get_input<float>("Max_001");
- randomize_attribute<float>(span.typed<float>(), min, max, hashes, seed, operation);
- break;
- }
- case CD_PROP_BOOL: {
- randomize_attribute_bool(span.typed<bool>(), hashes, seed, operation);
- break;
- }
- case CD_PROP_INT32: {
- const int min = params.get_input<int>("Min_002");
- const int max = params.get_input<int>("Max_002");
- randomize_attribute<int>(span.typed<int>(), min, max, hashes, seed, operation);
- break;
- }
- default: {
- BLI_assert(false);
- break;
- }
- }
-
- attribute.save();
-}
-
-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_default_remaining_outputs();
- return;
- }
- const int seed = params.get_input<int>("Seed");
- const NodeAttributeRandomize &storage = *(const NodeAttributeRandomize *)params.node().storage;
- const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
- const GeometryNodeAttributeRandomizeMode operation =
- static_cast<GeometryNodeAttributeRandomizeMode>(storage.operation);
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- randomize_attribute_on_component(geometry_set.get_component_for_write<MeshComponent>(),
- params,
- attribute_name,
- data_type,
- operation,
- seed);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- randomize_attribute_on_component(geometry_set.get_component_for_write<PointCloudComponent>(),
- params,
- attribute_name,
- data_type,
- operation,
- seed);
- }
- if (geometry_set.has<CurveComponent>()) {
- randomize_attribute_on_component(geometry_set.get_component_for_write<CurveComponent>(),
- params,
- attribute_name,
- data_type,
- operation,
- seed);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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);
- 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, "NodeAttributeRandomize", node_free_standard_storage, node_copy_standard_storage);
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_remove.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_remove.cc
deleted file mode 100644
index cc7118fd305..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_remove.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_remove_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Attribute")).multi_input();
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void remove_attribute(GeometryComponent &component,
- GeoNodeExecParams &params,
- Span<std::string> attribute_names)
-{
- for (std::string attribute_name : attribute_names) {
- if (attribute_name.empty()) {
- continue;
- }
-
- if (!component.attribute_try_delete(attribute_name)) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("Cannot delete attribute with name \"") + attribute_name +
- "\"");
- }
- }
-}
-
-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");
-
- for (const GeometryComponentType type : {GEO_COMPONENT_TYPE_MESH,
- GEO_COMPONENT_TYPE_POINT_CLOUD,
- GEO_COMPONENT_TYPE_CURVE,
- GEO_COMPONENT_TYPE_INSTANCES}) {
- if (geometry_set.has(type)) {
- remove_attribute(geometry_set.get_component_for_write(type), params, attribute_names);
- }
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // namespace blender::nodes::node_geo_legacy_attribute_remove_cc
-
-void register_node_type_geo_legacy_attribute_remove()
-{
- namespace file_ns = blender::nodes::node_geo_legacy_attribute_remove_cc;
-
- static bNodeType ntype;
-
- geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE);
- 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_legacy_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc
deleted file mode 100644
index 42719d4bf1a..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc
+++ /dev/null
@@ -1,124 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_compiler_attrs.h"
-#include "BLI_task.hh"
-
-#include "DNA_texture_types.h"
-
-#include "BKE_texture.h"
-
-#include "RE_texture.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_sample_texture_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::Texture>(N_("Texture")).hide_label();
- b.add_input<decl::String>(N_("Mapping"));
- b.add_input<decl::String>(N_("Result"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static AttributeDomain get_result_domain(const GeometryComponent &component,
- const StringRef result_name,
- const StringRef map_name)
-{
- /* Use the domain of the result attribute if it already exists. */
- std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
- if (result_info) {
- return result_info->domain;
- }
-
- /* Otherwise use the name of the map attribute. */
- std::optional<AttributeMetaData> map_info = component.attribute_get_meta_data(map_name);
- if (map_info) {
- return map_info->domain;
- }
-
- /* The node won't execute in this case, but we still have to return a value. */
- return ATTR_DOMAIN_POINT;
-}
-
-static void execute_on_component(GeometryComponent &component, const GeoNodeExecParams &params)
-{
- Tex *texture = params.get_input<Tex *>("Texture");
- if (texture == nullptr) {
- return;
- }
-
- const std::string result_attribute_name = params.get_input<std::string>("Result");
- const std::string mapping_name = params.get_input<std::string>("Mapping");
- if (!component.attribute_exists(mapping_name)) {
- return;
- }
-
- const AttributeDomain result_domain = get_result_domain(
- component, result_attribute_name, mapping_name);
-
- OutputAttribute_Typed<ColorGeometry4f> attribute_out =
- component.attribute_try_get_for_output_only<ColorGeometry4f>(result_attribute_name,
- result_domain);
- if (!attribute_out) {
- return;
- }
-
- VArray<float3> mapping_attribute = component.attribute_get_for_read<float3>(
- mapping_name, result_domain, {0, 0, 0});
-
- MutableSpan<ColorGeometry4f> colors = attribute_out.as_span();
- threading::parallel_for(IndexRange(mapping_attribute.size()), 128, [&](IndexRange range) {
- for (const int i : range) {
- TexResult texture_result = {0};
- const float3 position = mapping_attribute[i];
- /* For legacy reasons we have to map [0, 1] to [-1, 1] to support uv mappings. */
- const float3 remapped_position = position * 2.0f - float3(1.0f);
- BKE_texture_get_value(nullptr, texture, remapped_position, &texture_result, false);
- copy_v4_v4(colors[i], texture_result.trgba);
- }
- });
-
- attribute_out.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- execute_on_component(geometry_set.get_component_for_write<MeshComponent>(), params);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- execute_on_component(geometry_set.get_component_for_write<PointCloudComponent>(), params);
- }
- if (geometry_set.has<CurveComponent>()) {
- execute_on_component(geometry_set.get_component_for_write<CurveComponent>(), params);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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,
- GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE,
- "Attribute Sample Texture",
- NODE_CLASS_ATTRIBUTE);
- node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- 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_legacy_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
deleted file mode 100644
index 85ffbf6679b..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc
+++ /dev/null
@@ -1,157 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_separate_xyz_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Vector"));
- b.add_input<decl::Vector>(N_("Vector"), "Vector_001");
- b.add_input<decl::String>(N_("Result X"));
- b.add_input<decl::String>(N_("Result Y"));
- b.add_input<decl::String>(N_("Result Z"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-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 node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeAttributeSeparateXYZ *data = MEM_cnew<NodeAttributeSeparateXYZ>(__func__);
- data->input_type = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
- node->storage = data;
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeAttributeSeparateXYZ *node_storage = (NodeAttributeSeparateXYZ *)node->storage;
- update_attribute_input_socket_availabilities(
- *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type);
-}
-
-static void extract_input(const int index, const Span<float3> &input, MutableSpan<float> result)
-{
- for (const int i : result.index_range()) {
- /* Get the component of the float3. (0: X, 1: Y, 2: Z). */
- const float component = input[i][index];
- result[i] = component;
- }
-}
-
-static AttributeDomain get_result_domain(const GeometryComponent &component,
- const GeoNodeExecParams &params,
- const StringRef name_x,
- const StringRef name_y,
- const StringRef name_z)
-{
- /* Use the highest priority domain from any existing attribute outputs. */
- Vector<AttributeDomain, 3> output_domains;
- std::optional<AttributeMetaData> info_x = component.attribute_get_meta_data(name_x);
- std::optional<AttributeMetaData> info_y = component.attribute_get_meta_data(name_y);
- std::optional<AttributeMetaData> info_z = component.attribute_get_meta_data(name_z);
- if (info_x) {
- output_domains.append(info_x->domain);
- }
- if (info_y) {
- output_domains.append(info_y->domain);
- }
- if (info_z) {
- output_domains.append(info_z->domain);
- }
- if (output_domains.size() > 0) {
- return bke::attribute_domain_highest_priority(output_domains);
- }
-
- /* Otherwise use the domain of the input attribute, or the default. */
- return params.get_highest_priority_input_domain({"Vector"}, component, ATTR_DOMAIN_POINT);
-}
-
-static void separate_attribute(GeometryComponent &component, const GeoNodeExecParams &params)
-{
- const std::string result_name_x = params.get_input<std::string>("Result X");
- const std::string result_name_y = params.get_input<std::string>("Result Y");
- const std::string result_name_z = params.get_input<std::string>("Result Z");
- if (result_name_x.empty() && result_name_y.empty() && result_name_z.empty()) {
- return;
- }
-
- /* The node is only for float3 to float conversions. */
- const AttributeDomain result_domain = get_result_domain(
- component, params, result_name_x, result_name_y, result_name_z);
-
- VArray<float3> attribute_input = params.get_input_attribute<float3>(
- "Vector", component, result_domain, {0, 0, 0});
- VArray_Span<float3> input_span{attribute_input};
-
- OutputAttribute_Typed<float> attribute_result_x =
- component.attribute_try_get_for_output_only<float>(result_name_x, result_domain);
- OutputAttribute_Typed<float> attribute_result_y =
- component.attribute_try_get_for_output_only<float>(result_name_y, result_domain);
- OutputAttribute_Typed<float> attribute_result_z =
- component.attribute_try_get_for_output_only<float>(result_name_z, result_domain);
-
- /* Only extract the components for the outputs with a given attribute. */
- if (attribute_result_x) {
- extract_input(0, input_span, attribute_result_x.as_span());
- attribute_result_x.save();
- }
- if (attribute_result_y) {
- extract_input(1, input_span, attribute_result_y.as_span());
- attribute_result_y.save();
- }
- if (attribute_result_z) {
- extract_input(2, input_span, attribute_result_z.as_span());
- attribute_result_z.save();
- }
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- separate_attribute(geometry_set.get_component_for_write<MeshComponent>(), params);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- separate_attribute(geometry_set.get_component_for_write<PointCloudComponent>(), params);
- }
- if (geometry_set.has<CurveComponent>()) {
- separate_attribute(geometry_set.get_component_for_write<CurveComponent>(), params);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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,
- GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ,
- "Attribute Separate XYZ",
- NODE_CLASS_ATTRIBUTE);
- 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 = 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_legacy_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc
deleted file mode 100644
index 802feb88ce2..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc
+++ /dev/null
@@ -1,515 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_kdopbvh.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_pointcloud_types.h"
-
-#include "BKE_bvhutils.h"
-#include "BKE_mesh_runtime.h"
-#include "BKE_mesh_sample.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_transfer_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::Geometry>(N_("Source Geometry"));
- b.add_input<decl::String>(N_("Source"));
- b.add_input<decl::String>(N_("Destination"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "domain", 0, IFACE_("Domain"), ICON_NONE);
- uiItemR(layout, ptr, "mapping", 0, IFACE_("Mapping"), ICON_NONE);
-}
-
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeGeometryAttributeTransfer *data = MEM_cnew<NodeGeometryAttributeTransfer>(__func__);
- data->domain = ATTR_DOMAIN_AUTO;
- node->storage = data;
-}
-
-static void get_result_domain_and_data_type(const GeometrySet &src_geometry,
- const GeometryComponent &dst_component,
- const StringRef attribute_name,
- CustomDataType *r_data_type,
- AttributeDomain *r_domain)
-{
- Vector<CustomDataType> data_types;
- Vector<AttributeDomain> domains;
-
- const PointCloudComponent *pointcloud_component =
- src_geometry.get_component_for_read<PointCloudComponent>();
- if (pointcloud_component != nullptr) {
- std::optional<AttributeMetaData> meta_data = pointcloud_component->attribute_get_meta_data(
- attribute_name);
- if (meta_data.has_value()) {
- data_types.append(meta_data->data_type);
- domains.append(meta_data->domain);
- }
- }
-
- const MeshComponent *mesh_component = src_geometry.get_component_for_read<MeshComponent>();
- if (mesh_component != nullptr) {
- std::optional<AttributeMetaData> meta_data = mesh_component->attribute_get_meta_data(
- attribute_name);
- if (meta_data.has_value()) {
- data_types.append(meta_data->data_type);
- domains.append(meta_data->domain);
- }
- }
-
- *r_data_type = bke::attribute_data_type_highest_complexity(data_types);
-
- if (dst_component.type() == GEO_COMPONENT_TYPE_POINT_CLOUD) {
- *r_domain = ATTR_DOMAIN_POINT;
- }
- else {
- *r_domain = bke::attribute_domain_highest_priority(domains);
- }
-}
-
-static void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data,
- const VArray<float3> &positions,
- const MutableSpan<int> r_indices,
- 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());
-
- for (const int i : positions.index_range()) {
- BVHTreeNearest nearest;
- nearest.dist_sq = FLT_MAX;
- const float3 position = positions[i];
- BLI_bvhtree_find_nearest(
- tree_data.tree, position, &nearest, tree_data.nearest_callback, &tree_data);
- if (!r_indices.is_empty()) {
- r_indices[i] = nearest.index;
- }
- if (!r_distances_sq.is_empty()) {
- r_distances_sq[i] = nearest.dist_sq;
- }
- if (!r_positions.is_empty()) {
- r_positions[i] = nearest.co;
- }
- }
-}
-
-static void get_closest_pointcloud_points(const PointCloud &pointcloud,
- const VArray<float3> &positions,
- const MutableSpan<int> r_indices,
- const MutableSpan<float> r_distances_sq)
-{
- BLI_assert(positions.size() == r_indices.size());
- BLI_assert(pointcloud.totpoint > 0);
-
- BVHTreeFromPointCloud tree_data;
- BKE_bvhtree_from_pointcloud_get(&tree_data, &pointcloud, 2);
-
- for (const int i : positions.index_range()) {
- BVHTreeNearest nearest;
- nearest.dist_sq = FLT_MAX;
- const float3 position = positions[i];
- BLI_bvhtree_find_nearest(
- tree_data.tree, position, &nearest, tree_data.nearest_callback, &tree_data);
- r_indices[i] = nearest.index;
- r_distances_sq[i] = nearest.dist_sq;
- }
-
- free_bvhtree_from_pointcloud(&tree_data);
-}
-
-static void get_closest_mesh_points(const Mesh &mesh,
- const VArray<float3> &positions,
- const MutableSpan<int> r_point_indices,
- const MutableSpan<float> r_distances_sq,
- const MutableSpan<float3> r_positions)
-{
- BLI_assert(mesh.totvert > 0);
- BVHTreeFromMesh tree_data;
- BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_VERTS, 2);
- get_closest_in_bvhtree(tree_data, positions, r_point_indices, r_distances_sq, r_positions);
- free_bvhtree_from_mesh(&tree_data);
-}
-
-static void get_closest_mesh_edges(const Mesh &mesh,
- const VArray<float3> &positions,
- const MutableSpan<int> r_edge_indices,
- const MutableSpan<float> r_distances_sq,
- const MutableSpan<float3> r_positions)
-{
- BLI_assert(mesh.totedge > 0);
- BVHTreeFromMesh tree_data;
- BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_EDGES, 2);
- get_closest_in_bvhtree(tree_data, positions, r_edge_indices, r_distances_sq, r_positions);
- free_bvhtree_from_mesh(&tree_data);
-}
-
-static void get_closest_mesh_looptris(const Mesh &mesh,
- const VArray<float3> &positions,
- const MutableSpan<int> r_looptri_indices,
- const MutableSpan<float> r_distances_sq,
- const MutableSpan<float3> r_positions)
-{
- BLI_assert(mesh.totpoly > 0);
- BVHTreeFromMesh tree_data;
- BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_LOOPTRI, 2);
- get_closest_in_bvhtree(tree_data, positions, r_looptri_indices, r_distances_sq, r_positions);
- free_bvhtree_from_mesh(&tree_data);
-}
-
-static void get_closest_mesh_polygons(const Mesh &mesh,
- const VArray<float3> &positions,
- const MutableSpan<int> r_poly_indices,
- const MutableSpan<float> r_distances_sq,
- const MutableSpan<float3> r_positions)
-{
- BLI_assert(mesh.totpoly > 0);
-
- Array<int> looptri_indices(positions.size());
- get_closest_mesh_looptris(mesh, positions, looptri_indices, r_distances_sq, r_positions);
-
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
- BKE_mesh_runtime_looptri_len(&mesh)};
- for (const int i : positions.index_range()) {
- const MLoopTri &looptri = looptris[looptri_indices[i]];
- r_poly_indices[i] = looptri.poly;
- }
-}
-
-/* The closest corner is defined to be the closest corner on the closest face. */
-static void get_closest_mesh_corners(const Mesh &mesh,
- const VArray<float3> &positions,
- const MutableSpan<int> r_corner_indices,
- const MutableSpan<float> r_distances_sq,
- const MutableSpan<float3> r_positions)
-{
- BLI_assert(mesh.totloop > 0);
- Array<int> poly_indices(positions.size());
- get_closest_mesh_polygons(mesh, positions, poly_indices, {}, {});
-
- for (const int i : positions.index_range()) {
- const float3 position = positions[i];
- const int poly_index = poly_indices[i];
- const MPoly &poly = mesh.mpoly[poly_index];
-
- /* Find the closest vertex in the polygon. */
- float min_distance_sq = FLT_MAX;
- const MVert *closest_mvert;
- int closest_loop_index = 0;
- for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) {
- const MLoop &loop = mesh.mloop[loop_index];
- const int vertex_index = loop.v;
- const MVert &mvert = mesh.mvert[vertex_index];
- const float distance_sq = math::distance_squared(position, float3(mvert.co));
- if (distance_sq < min_distance_sq) {
- min_distance_sq = distance_sq;
- closest_loop_index = loop_index;
- closest_mvert = &mvert;
- }
- }
- if (!r_corner_indices.is_empty()) {
- r_corner_indices[i] = closest_loop_index;
- }
- if (!r_positions.is_empty()) {
- r_positions[i] = closest_mvert->co;
- }
- if (!r_distances_sq.is_empty()) {
- r_distances_sq[i] = min_distance_sq;
- }
- }
-}
-
-static void transfer_attribute_nearest_face_interpolated(const GeometrySet &src_geometry,
- GeometryComponent &dst_component,
- const VArray<float3> &dst_positions,
- const AttributeDomain dst_domain,
- const CustomDataType data_type,
- const StringRef src_name,
- const StringRef dst_name)
-{
- const int tot_samples = dst_positions.size();
- const MeshComponent *component = src_geometry.get_component_for_read<MeshComponent>();
- if (component == nullptr) {
- return;
- }
- const Mesh *mesh = component->get_for_read();
- if (mesh == nullptr) {
- return;
- }
- if (mesh->totpoly == 0) {
- return;
- }
-
- ReadAttributeLookup src_attribute = component->attribute_try_get_for_read(src_name, data_type);
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- dst_name, dst_domain, data_type);
- if (!src_attribute || !dst_attribute) {
- return;
- }
-
- /* Find closest points on the mesh surface. */
- Array<int> looptri_indices(tot_samples);
- Array<float3> positions(tot_samples);
- get_closest_mesh_looptris(*mesh, dst_positions, looptri_indices, {}, positions);
-
- bke::mesh_surface_sample::MeshAttributeInterpolator interp(
- mesh, IndexMask(tot_samples), positions, looptri_indices);
- interp.sample_attribute(
- src_attribute, dst_attribute, bke::mesh_surface_sample::eAttributeMapMode::INTERPOLATED);
-
- dst_attribute.save();
-}
-
-static void transfer_attribute_nearest(const GeometrySet &src_geometry,
- GeometryComponent &dst_component,
- const VArray<float3> &dst_positions,
- const AttributeDomain dst_domain,
- const CustomDataType data_type,
- const StringRef src_name,
- const StringRef dst_name)
-{
- const CPPType &type = *bke::custom_data_type_to_cpp_type(data_type);
-
- /* Get pointcloud data from geometry. */
- const PointCloudComponent *pointcloud_component =
- src_geometry.get_component_for_read<PointCloudComponent>();
- const PointCloud *pointcloud = pointcloud_component ? pointcloud_component->get_for_read() :
- nullptr;
-
- /* Get mesh data from geometry. */
- const MeshComponent *mesh_component = src_geometry.get_component_for_read<MeshComponent>();
- const Mesh *mesh = mesh_component ? mesh_component->get_for_read() : nullptr;
-
- const int tot_samples = dst_positions.size();
-
- Array<int> pointcloud_indices;
- Array<float> pointcloud_distances_sq;
- bool use_pointcloud = false;
-
- /* Depending on where what domain the source attribute lives, these indices are either vertex,
- * corner, edge or polygon indices. */
- Array<int> mesh_indices;
- Array<float> mesh_distances_sq;
- bool use_mesh = false;
-
- /* If there is a pointcloud, find the closest points. */
- if (pointcloud != nullptr && pointcloud->totpoint > 0) {
- if (pointcloud_component->attribute_exists(src_name)) {
- use_pointcloud = true;
- pointcloud_indices.reinitialize(tot_samples);
- pointcloud_distances_sq.reinitialize(tot_samples);
- get_closest_pointcloud_points(
- *pointcloud, dst_positions, pointcloud_indices, pointcloud_distances_sq);
- }
- }
-
- /* If there is a mesh, find the closest mesh elements. */
- if (mesh != nullptr) {
- ReadAttributeLookup src_attribute = mesh_component->attribute_try_get_for_read(src_name);
- if (src_attribute) {
- switch (src_attribute.domain) {
- case ATTR_DOMAIN_POINT: {
- if (mesh->totvert > 0) {
- use_mesh = true;
- mesh_indices.reinitialize(tot_samples);
- mesh_distances_sq.reinitialize(tot_samples);
- get_closest_mesh_points(*mesh, dst_positions, mesh_indices, mesh_distances_sq, {});
- }
- break;
- }
- case ATTR_DOMAIN_EDGE: {
- if (mesh->totedge > 0) {
- use_mesh = true;
- mesh_indices.reinitialize(tot_samples);
- mesh_distances_sq.reinitialize(tot_samples);
- get_closest_mesh_edges(*mesh, dst_positions, mesh_indices, mesh_distances_sq, {});
- }
- break;
- }
- case ATTR_DOMAIN_FACE: {
- if (mesh->totpoly > 0) {
- use_mesh = true;
- mesh_indices.reinitialize(tot_samples);
- mesh_distances_sq.reinitialize(tot_samples);
- get_closest_mesh_polygons(*mesh, dst_positions, mesh_indices, mesh_distances_sq, {});
- }
- break;
- }
- case ATTR_DOMAIN_CORNER: {
- if (mesh->totloop > 0) {
- use_mesh = true;
- mesh_indices.reinitialize(tot_samples);
- mesh_distances_sq.reinitialize(tot_samples);
- get_closest_mesh_corners(*mesh, dst_positions, mesh_indices, mesh_distances_sq, {});
- }
- break;
- }
- default: {
- break;
- }
- }
- }
- }
-
- if (!use_pointcloud && !use_mesh) {
- return;
- }
-
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- dst_name, dst_domain, data_type);
- if (!dst_attribute) {
- return;
- }
-
- /* Create a buffer for intermediate values. */
- BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
-
- if (use_mesh && use_pointcloud) {
- /* When there is a mesh and a pointcloud, we still have to check whether a pointcloud point or
- * a mesh element is closer to every point. */
- ReadAttributeLookup pointcloud_src_attribute =
- pointcloud_component->attribute_try_get_for_read(src_name, data_type);
- ReadAttributeLookup mesh_src_attribute = mesh_component->attribute_try_get_for_read(src_name,
- data_type);
- for (const int i : IndexRange(tot_samples)) {
- if (pointcloud_distances_sq[i] < mesh_distances_sq[i]) {
- /* 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);
- }
- else {
- /* Mesh element is closer. */
- const int index = mesh_indices[i];
- mesh_src_attribute.varray.get(index, buffer);
- dst_attribute->set_by_relocate(i, buffer);
- }
- }
- }
- else if (use_pointcloud) {
- /* The source geometry only has a pointcloud. */
- ReadAttributeLookup src_attribute = pointcloud_component->attribute_try_get_for_read(
- src_name, data_type);
- for (const int i : IndexRange(tot_samples)) {
- const int index = pointcloud_indices[i];
- src_attribute.varray.get(index, buffer);
- dst_attribute->set_by_relocate(i, buffer);
- }
- }
- else if (use_mesh) {
- /* The source geometry only has a mesh. */
- ReadAttributeLookup src_attribute = mesh_component->attribute_try_get_for_read(src_name,
- data_type);
- for (const int i : IndexRange(tot_samples)) {
- const int index = mesh_indices[i];
- src_attribute.varray.get(index, buffer);
- dst_attribute->set_by_relocate(i, buffer);
- }
- }
-
- dst_attribute.save();
-}
-
-static void transfer_attribute(const GeoNodeExecParams &params,
- const GeometrySet &src_geometry,
- GeometryComponent &dst_component,
- const StringRef src_name,
- const StringRef dst_name)
-{
- const NodeGeometryAttributeTransfer &storage =
- *(const NodeGeometryAttributeTransfer *)params.node().storage;
- const GeometryNodeAttributeTransferMapMode mapping = (GeometryNodeAttributeTransferMapMode)
- storage.mapping;
- const AttributeDomain input_domain = (AttributeDomain)storage.domain;
-
- CustomDataType data_type;
- AttributeDomain auto_domain;
- get_result_domain_and_data_type(src_geometry, dst_component, src_name, &data_type, &auto_domain);
- const AttributeDomain dst_domain = (input_domain == ATTR_DOMAIN_AUTO) ? auto_domain :
- input_domain;
-
- VArray<float3> dst_positions = dst_component.attribute_get_for_read<float3>(
- "position", dst_domain, {0, 0, 0});
-
- switch (mapping) {
- case GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED: {
- transfer_attribute_nearest_face_interpolated(
- src_geometry, dst_component, dst_positions, dst_domain, data_type, src_name, dst_name);
- break;
- }
- case GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER_NEAREST: {
- transfer_attribute_nearest(
- src_geometry, dst_component, dst_positions, dst_domain, data_type, src_name, dst_name);
- break;
- }
- }
-}
-
-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");
- const std::string src_attribute_name = params.extract_input<std::string>("Source");
- const std::string dst_attribute_name = params.extract_input<std::string>("Destination");
-
- if (src_attribute_name.empty() || dst_attribute_name.empty()) {
- params.set_default_remaining_outputs();
- return;
- }
-
- 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,
- src_geometry_set,
- dst_geometry_set.get_component_for_write<MeshComponent>(),
- src_attribute_name,
- dst_attribute_name);
- }
- if (dst_geometry_set.has<PointCloudComponent>()) {
- transfer_attribute(params,
- src_geometry_set,
- dst_geometry_set.get_component_for_write<PointCloudComponent>(),
- src_attribute_name,
- dst_attribute_name);
- }
-
- params.set_output("Geometry", dst_geometry_set);
-}
-
-} // 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);
- node_type_init(&ntype, file_ns::node_init);
- node_type_storage(&ntype,
- "NodeGeometryAttributeTransfer",
- node_free_standard_storage,
- node_copy_standard_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_legacy_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc
deleted file mode 100644
index 83ece031dd2..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc
+++ /dev/null
@@ -1,559 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_math_base_safe.h"
-#include "BLI_task.hh"
-
-#include "RNA_enum_types.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "NOD_math_functions.hh"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_attribute_vector_math_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("A"));
- b.add_input<decl::Vector>(N_("A"), "A_001");
- b.add_input<decl::String>(N_("B"));
- b.add_input<decl::Vector>(N_("B"), "B_001");
- b.add_input<decl::Float>(N_("B"), "B_002");
- b.add_input<decl::String>(N_("C"));
- b.add_input<decl::Vector>(N_("C"), "C_001");
- b.add_input<decl::Float>(N_("C"), "C_002");
- b.add_input<decl::String>(N_("Result"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static bool operation_use_input_b(const NodeVectorMathOperation operation)
-{
- return !ELEM(operation,
- NODE_VECTOR_MATH_NORMALIZE,
- NODE_VECTOR_MATH_FLOOR,
- NODE_VECTOR_MATH_CEIL,
- NODE_VECTOR_MATH_FRACTION,
- NODE_VECTOR_MATH_ABSOLUTE,
- NODE_VECTOR_MATH_SINE,
- NODE_VECTOR_MATH_COSINE,
- NODE_VECTOR_MATH_TANGENT,
- NODE_VECTOR_MATH_LENGTH);
-}
-
-static bool operation_use_input_c(const NodeVectorMathOperation operation)
-{
- return ELEM(operation,
- NODE_VECTOR_MATH_WRAP,
- NODE_VECTOR_MATH_REFRACT,
- NODE_VECTOR_MATH_FACEFORWARD,
- NODE_VECTOR_MATH_MULTIPLY_ADD);
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- const NodeAttributeVectorMath &node_storage = *(NodeAttributeVectorMath *)node->storage;
- const NodeVectorMathOperation operation = (const NodeVectorMathOperation)node_storage.operation;
-
- uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
-
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "input_type_a", 0, IFACE_("A"), ICON_NONE);
- if (operation_use_input_b(operation)) {
- uiItemR(layout, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE);
- }
- if (operation_use_input_c(operation)) {
- uiItemR(layout, ptr, "input_type_c", 0, IFACE_("C"), ICON_NONE);
- }
-}
-
-static CustomDataType operation_get_read_type_b(const NodeVectorMathOperation operation)
-{
- if (operation == NODE_VECTOR_MATH_SCALE) {
- return CD_PROP_FLOAT;
- }
- return CD_PROP_FLOAT3;
-}
-
-static CustomDataType operation_get_read_type_c(const NodeVectorMathOperation operation)
-{
- if (operation == NODE_VECTOR_MATH_REFRACT) {
- return CD_PROP_FLOAT;
- }
- return CD_PROP_FLOAT3;
-}
-
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeAttributeVectorMath *data = MEM_cnew<NodeAttributeVectorMath>(__func__);
-
- data->operation = NODE_VECTOR_MATH_ADD;
- data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
- data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
- node->storage = data;
-}
-
-static CustomDataType operation_get_result_type(const NodeVectorMathOperation operation)
-{
- switch (operation) {
- case NODE_VECTOR_MATH_ADD:
- case NODE_VECTOR_MATH_SUBTRACT:
- case NODE_VECTOR_MATH_MULTIPLY:
- case NODE_VECTOR_MATH_DIVIDE:
- case NODE_VECTOR_MATH_CROSS_PRODUCT:
- case NODE_VECTOR_MATH_PROJECT:
- case NODE_VECTOR_MATH_REFLECT:
- case NODE_VECTOR_MATH_SCALE:
- case NODE_VECTOR_MATH_NORMALIZE:
- case NODE_VECTOR_MATH_SNAP:
- case NODE_VECTOR_MATH_FLOOR:
- case NODE_VECTOR_MATH_CEIL:
- case NODE_VECTOR_MATH_MODULO:
- case NODE_VECTOR_MATH_FRACTION:
- case NODE_VECTOR_MATH_ABSOLUTE:
- case NODE_VECTOR_MATH_MINIMUM:
- case NODE_VECTOR_MATH_MAXIMUM:
- case NODE_VECTOR_MATH_WRAP:
- case NODE_VECTOR_MATH_SINE:
- case NODE_VECTOR_MATH_COSINE:
- case NODE_VECTOR_MATH_TANGENT:
- case NODE_VECTOR_MATH_REFRACT:
- case NODE_VECTOR_MATH_FACEFORWARD:
- case NODE_VECTOR_MATH_MULTIPLY_ADD:
- return CD_PROP_FLOAT3;
- case NODE_VECTOR_MATH_DOT_PRODUCT:
- case NODE_VECTOR_MATH_DISTANCE:
- case NODE_VECTOR_MATH_LENGTH:
- return CD_PROP_FLOAT;
- }
-
- BLI_assert(false);
- return CD_PROP_FLOAT3;
-}
-
-static void geo_node_vector_math_label(const bNodeTree *UNUSED(ntree),
- const bNode *node,
- char *label,
- int maxlen)
-{
- NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage;
- const char *name;
- bool enum_label = RNA_enum_name(rna_enum_node_vec_math_items, node_storage.operation, &name);
- if (!enum_label) {
- name = "Unknown";
- }
- BLI_snprintf(label, maxlen, IFACE_("Vector %s"), IFACE_(name));
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- const NodeAttributeVectorMath *node_storage = (NodeAttributeVectorMath *)node->storage;
- const NodeVectorMathOperation operation = (const NodeVectorMathOperation)node_storage->operation;
-
- update_attribute_input_socket_availabilities(
- *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
- update_attribute_input_socket_availabilities(
- *ntree,
- *node,
- "B",
- (GeometryNodeAttributeInputMode)node_storage->input_type_b,
- operation_use_input_b(operation));
- update_attribute_input_socket_availabilities(
- *ntree,
- *node,
- "C",
- (GeometryNodeAttributeInputMode)node_storage->input_type_c,
- operation_use_input_c(operation));
-}
-
-static void do_math_operation_fl3_fl3_to_fl3(const VArray<float3> &input_a,
- const VArray<float3> &input_b,
- const VMutableArray<float3> &result,
- const NodeVectorMathOperation operation)
-{
- const int size = input_a.size();
-
- VArray_Span<float3> span_a{input_a};
- VArray_Span<float3> span_b{input_b};
- VMutableArray_Span<float3> span_result{result, false};
-
- bool success = try_dispatch_float_math_fl3_fl3_to_fl3(
- operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
- for (const int i : range) {
- const float3 a = span_a[i];
- const float3 b = span_b[i];
- const float3 out = math_function(a, b);
- span_result[i] = out;
- }
- });
- });
-
- span_result.save();
-
- /* The operation is not supported by this node currently. */
- BLI_assert(success);
- UNUSED_VARS_NDEBUG(success);
-}
-
-static void do_math_operation_fl3_fl3_fl3_to_fl3(const VArray<float3> &input_a,
- const VArray<float3> &input_b,
- const VArray<float3> &input_c,
- const VMutableArray<float3> &result,
- const NodeVectorMathOperation operation)
-{
- const int size = input_a.size();
-
- VArray_Span<float3> span_a{input_a};
- VArray_Span<float3> span_b{input_b};
- VArray_Span<float3> span_c{input_c};
- VMutableArray_Span<float3> span_result{result};
-
- bool success = try_dispatch_float_math_fl3_fl3_fl3_to_fl3(
- operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
- for (const int i : range) {
- const float3 a = span_a[i];
- const float3 b = span_b[i];
- const float3 c = span_c[i];
- const float3 out = math_function(a, b, c);
- span_result[i] = out;
- }
- });
- });
-
- span_result.save();
-
- /* The operation is not supported by this node currently. */
- BLI_assert(success);
- UNUSED_VARS_NDEBUG(success);
-}
-
-static void do_math_operation_fl3_fl3_fl_to_fl3(const VArray<float3> &input_a,
- const VArray<float3> &input_b,
- const VArray<float> &input_c,
- const VMutableArray<float3> &result,
- const NodeVectorMathOperation operation)
-{
- const int size = input_a.size();
-
- VArray_Span<float3> span_a{input_a};
- VArray_Span<float3> span_b{input_b};
- VArray_Span<float> span_c{input_c};
- VMutableArray_Span<float3> span_result{result, false};
-
- bool success = try_dispatch_float_math_fl3_fl3_fl_to_fl3(
- operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
- for (const int i : range) {
- const float3 a = span_a[i];
- const float3 b = span_b[i];
- const float c = span_c[i];
- const float3 out = math_function(a, b, c);
- span_result[i] = out;
- }
- });
- });
-
- span_result.save();
-
- /* The operation is not supported by this node currently. */
- BLI_assert(success);
- UNUSED_VARS_NDEBUG(success);
-}
-
-static void do_math_operation_fl3_fl3_to_fl(const VArray<float3> &input_a,
- const VArray<float3> &input_b,
- const VMutableArray<float> &result,
- const NodeVectorMathOperation operation)
-{
- const int size = input_a.size();
-
- VArray_Span<float3> span_a{input_a};
- VArray_Span<float3> span_b{input_b};
- VMutableArray_Span<float> span_result{result, false};
-
- bool success = try_dispatch_float_math_fl3_fl3_to_fl(
- operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
- for (const int i : range) {
- const float3 a = span_a[i];
- const float3 b = span_b[i];
- const float out = math_function(a, b);
- span_result[i] = out;
- }
- });
- });
-
- span_result.save();
-
- /* The operation is not supported by this node currently. */
- BLI_assert(success);
- UNUSED_VARS_NDEBUG(success);
-}
-
-static void do_math_operation_fl3_fl_to_fl3(const VArray<float3> &input_a,
- const VArray<float> &input_b,
- const VMutableArray<float3> &result,
- const NodeVectorMathOperation operation)
-{
- const int size = input_a.size();
-
- VArray_Span<float3> span_a{input_a};
- VArray_Span<float> span_b{input_b};
- VMutableArray_Span<float3> span_result{result, false};
-
- bool success = try_dispatch_float_math_fl3_fl_to_fl3(
- operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
- for (const int i : range) {
- const float3 a = span_a[i];
- const float b = span_b[i];
- const float3 out = math_function(a, b);
- span_result[i] = out;
- }
- });
- });
-
- span_result.save();
-
- /* The operation is not supported by this node currently. */
- BLI_assert(success);
- UNUSED_VARS_NDEBUG(success);
-}
-
-static void do_math_operation_fl3_to_fl3(const VArray<float3> &input_a,
- const VMutableArray<float3> &result,
- const NodeVectorMathOperation operation)
-{
- const int size = input_a.size();
-
- VArray_Span<float3> span_a{input_a};
- VMutableArray_Span<float3> span_result{result, false};
-
- bool success = try_dispatch_float_math_fl3_to_fl3(
- operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
- for (const int i : range) {
- const float3 in = span_a[i];
- const float3 out = math_function(in);
- span_result[i] = out;
- }
- });
- });
-
- span_result.save();
-
- /* The operation is not supported by this node currently. */
- BLI_assert(success);
- UNUSED_VARS_NDEBUG(success);
-}
-
-static void do_math_operation_fl3_to_fl(const VArray<float3> &input_a,
- const VMutableArray<float> &result,
- const NodeVectorMathOperation operation)
-{
- const int size = input_a.size();
-
- VArray_Span<float3> span_a{input_a};
- VMutableArray_Span<float> span_result{result, false};
-
- bool success = try_dispatch_float_math_fl3_to_fl(
- operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- threading::parallel_for(IndexRange(size), 512, [&](IndexRange range) {
- for (const int i : range) {
- const float3 in = span_a[i];
- const float out = math_function(in);
- span_result[i] = out;
- }
- });
- });
-
- span_result.save();
-
- /* The operation is not supported by this node currently. */
- BLI_assert(success);
- UNUSED_VARS_NDEBUG(success);
-}
-
-static AttributeDomain get_result_domain(const GeometryComponent &component,
- const GeoNodeExecParams &params,
- const NodeVectorMathOperation operation,
- StringRef result_name)
-{
- /* Use the domain of the result attribute if it already exists. */
- std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
- if (result_info) {
- return result_info->domain;
- }
-
- /* Otherwise use the highest priority domain from existing input attributes, or the default. */
- const AttributeDomain default_domain = ATTR_DOMAIN_POINT;
- if (operation_use_input_b(operation)) {
- if (operation_use_input_c(operation)) {
- return params.get_highest_priority_input_domain({"A", "B", "C"}, component, default_domain);
- }
- return params.get_highest_priority_input_domain({"A", "B"}, component, default_domain);
- }
- return params.get_highest_priority_input_domain({"A"}, component, default_domain);
-}
-
-static void attribute_vector_math_calc(GeometryComponent &component,
- const GeoNodeExecParams &params)
-{
- const bNode &node = params.node();
- const NodeAttributeVectorMath *node_storage = (const NodeAttributeVectorMath *)node.storage;
- const NodeVectorMathOperation operation = (NodeVectorMathOperation)node_storage->operation;
- const std::string result_name = params.get_input<std::string>("Result");
-
- /* The number and type of the input attribute depend on the operation. */
- const CustomDataType read_type_a = CD_PROP_FLOAT3;
- const bool use_input_b = operation_use_input_b(operation);
- const CustomDataType read_type_b = operation_get_read_type_b(operation);
- const bool use_input_c = operation_use_input_c(operation);
- const CustomDataType read_type_c = operation_get_read_type_c(operation);
-
- /* The result domain is always point for now. */
- const CustomDataType result_type = operation_get_result_type(operation);
- const AttributeDomain result_domain = get_result_domain(
- component, params, operation, result_name);
-
- GVArray attribute_a = params.get_input_attribute(
- "A", component, result_domain, read_type_a, nullptr);
- if (!attribute_a) {
- return;
- }
- GVArray attribute_b;
- GVArray attribute_c;
- if (use_input_b) {
- attribute_b = params.get_input_attribute("B", component, result_domain, read_type_b, nullptr);
- if (!attribute_b) {
- return;
- }
- }
- if (use_input_c) {
- attribute_c = params.get_input_attribute("C", component, result_domain, read_type_c, nullptr);
- if (!attribute_c) {
- return;
- }
- }
-
- /* Get result attribute first, in case it has to overwrite one of the existing attributes. */
- OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
- result_name, result_domain, result_type);
- if (!attribute_result) {
- return;
- }
-
- switch (operation) {
- case NODE_VECTOR_MATH_ADD:
- case NODE_VECTOR_MATH_SUBTRACT:
- case NODE_VECTOR_MATH_MULTIPLY:
- case NODE_VECTOR_MATH_DIVIDE:
- case NODE_VECTOR_MATH_CROSS_PRODUCT:
- case NODE_VECTOR_MATH_PROJECT:
- case NODE_VECTOR_MATH_REFLECT:
- case NODE_VECTOR_MATH_SNAP:
- case NODE_VECTOR_MATH_MODULO:
- case NODE_VECTOR_MATH_MINIMUM:
- case NODE_VECTOR_MATH_MAXIMUM:
- do_math_operation_fl3_fl3_to_fl3(attribute_a.typed<float3>(),
- attribute_b.typed<float3>(),
- attribute_result.varray().typed<float3>(),
- operation);
- break;
- case NODE_VECTOR_MATH_DOT_PRODUCT:
- case NODE_VECTOR_MATH_DISTANCE:
- do_math_operation_fl3_fl3_to_fl(attribute_a.typed<float3>(),
- attribute_b.typed<float3>(),
- attribute_result.varray().typed<float>(),
- operation);
- break;
- case NODE_VECTOR_MATH_LENGTH:
- do_math_operation_fl3_to_fl(
- attribute_a.typed<float3>(), attribute_result.varray().typed<float>(), operation);
- break;
- case NODE_VECTOR_MATH_SCALE:
- do_math_operation_fl3_fl_to_fl3(attribute_a.typed<float3>(),
- attribute_b.typed<float>(),
- attribute_result.varray().typed<float3>(),
- operation);
- break;
- case NODE_VECTOR_MATH_NORMALIZE:
- case NODE_VECTOR_MATH_FLOOR:
- case NODE_VECTOR_MATH_CEIL:
- case NODE_VECTOR_MATH_FRACTION:
- case NODE_VECTOR_MATH_ABSOLUTE:
- case NODE_VECTOR_MATH_SINE:
- case NODE_VECTOR_MATH_COSINE:
- case NODE_VECTOR_MATH_TANGENT:
- do_math_operation_fl3_to_fl3(
- attribute_a.typed<float3>(), attribute_result.varray().typed<float3>(), operation);
- break;
- case NODE_VECTOR_MATH_WRAP:
- case NODE_VECTOR_MATH_FACEFORWARD:
- case NODE_VECTOR_MATH_MULTIPLY_ADD:
- do_math_operation_fl3_fl3_fl3_to_fl3(attribute_a.typed<float3>(),
- attribute_b.typed<float3>(),
- attribute_c.typed<float3>(),
- attribute_result.varray().typed<float3>(),
- operation);
- break;
- case NODE_VECTOR_MATH_REFRACT:
- do_math_operation_fl3_fl3_fl_to_fl3(attribute_a.typed<float3>(),
- attribute_b.typed<float3>(),
- attribute_c.typed<float>(),
- attribute_result.varray().typed<float3>(),
- operation);
- break;
- }
- attribute_result.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- 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);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- attribute_vector_math_calc(geometry_set.get_component_for_write<PointCloudComponent>(),
- params);
- }
- if (geometry_set.has<CurveComponent>()) {
- attribute_vector_math_calc(geometry_set.get_component_for_write<CurveComponent>(), params);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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,
- GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_MATH,
- "Attribute Vector Math",
- NODE_CLASS_ATTRIBUTE);
- 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);
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
deleted file mode 100644
index ccf1bdb0a19..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc
+++ /dev/null
@@ -1,335 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "node_geometry_util.hh"
-
-#include "BLI_task.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-namespace blender::nodes::node_geo_legacy_attribute_vector_rotate_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Vector"));
- b.add_input<decl::Vector>(N_("Vector"), "Vector_001").min(0.0f).max(1.0f).hide_value();
- b.add_input<decl::String>(N_("Center"));
- b.add_input<decl::Vector>(N_("Center"), "Center_001").subtype(PROP_XYZ);
- b.add_input<decl::String>(N_("Axis"));
- b.add_input<decl::Vector>(N_("Axis"), "Axis_001").min(-1.0f).max(1.0f).subtype(PROP_XYZ);
- b.add_input<decl::String>(N_("Angle"));
- b.add_input<decl::Float>(N_("Angle"), "Angle_001").subtype(PROP_ANGLE);
- b.add_input<decl::String>(N_("Rotation"));
- b.add_input<decl::Vector>(N_("Rotation"), "Rotation_001").subtype(PROP_EULER);
- b.add_input<decl::Bool>(N_("Invert"));
- b.add_input<decl::String>(N_("Result"));
-
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- bNode *node = (bNode *)ptr->data;
- const NodeAttributeVectorRotate &node_storage = *(NodeAttributeVectorRotate *)node->storage;
- const GeometryNodeAttributeVectorRotateMode mode = (const GeometryNodeAttributeVectorRotateMode)
- node_storage.mode;
-
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiLayout *column = uiLayoutColumn(layout, false);
-
- uiItemR(column, ptr, "rotation_mode", 0, "", ICON_NONE);
-
- uiItemR(column, ptr, "input_type_vector", 0, IFACE_("Vector"), ICON_NONE);
- uiItemR(column, ptr, "input_type_center", 0, IFACE_("Center"), ICON_NONE);
- if (mode == GEO_NODE_VECTOR_ROTATE_TYPE_AXIS) {
- uiItemR(column, ptr, "input_type_axis", 0, IFACE_("Axis"), ICON_NONE);
- }
- if (mode != GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) {
- uiItemR(column, ptr, "input_type_angle", 0, IFACE_("Angle"), ICON_NONE);
- }
- if (mode == GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) {
- uiItemR(column, ptr, "input_type_rotation", 0, IFACE_("Rotation"), ICON_NONE);
- }
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- const NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)node->storage;
- const GeometryNodeAttributeVectorRotateMode mode = (const GeometryNodeAttributeVectorRotateMode)
- node_storage->mode;
-
- update_attribute_input_socket_availabilities(
- *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector);
- update_attribute_input_socket_availabilities(
- *ntree, *node, "Center", (GeometryNodeAttributeInputMode)node_storage->input_type_center);
- update_attribute_input_socket_availabilities(
- *ntree,
- *node,
- "Axis",
- (GeometryNodeAttributeInputMode)node_storage->input_type_axis,
- (mode == GEO_NODE_VECTOR_ROTATE_TYPE_AXIS));
- update_attribute_input_socket_availabilities(
- *ntree,
- *node,
- "Angle",
- (GeometryNodeAttributeInputMode)node_storage->input_type_angle,
- (mode != GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
- update_attribute_input_socket_availabilities(
- *ntree,
- *node,
- "Rotation",
- (GeometryNodeAttributeInputMode)node_storage->input_type_rotation,
- (mode == GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
-}
-
-static float3 vector_rotate_around_axis(const float3 vector,
- const float3 center,
- const float3 axis,
- const float angle)
-{
- float3 result = vector - center;
- float mat[3][3];
- axis_angle_to_mat3(mat, axis, angle);
- mul_m3_v3(mat, result);
- return result + center;
-}
-
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeAttributeVectorRotate *node_storage = MEM_cnew<NodeAttributeVectorRotate>(__func__);
-
- node_storage->mode = GEO_NODE_VECTOR_ROTATE_TYPE_AXIS;
- node_storage->input_type_vector = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
- node_storage->input_type_center = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
- node_storage->input_type_axis = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
- node_storage->input_type_angle = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
- node_storage->input_type_rotation = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
-
- node->storage = node_storage;
-}
-
-static float3 vector_rotate_euler(const float3 vector,
- const float3 center,
- const float3 rotation,
- const bool invert)
-{
- float mat[3][3];
- float3 result = vector - center;
- eul_to_mat3(mat, rotation);
- if (invert) {
- invert_m3(mat);
- }
- mul_m3_v3(mat, result);
- return result + center;
-}
-
-static void do_vector_rotate_around_axis(const VArray<float3> &vector,
- const VArray<float3> &center,
- const VArray<float3> &axis,
- const VArray<float> &angle,
- MutableSpan<float3> results,
- const bool invert)
-{
- VArray_Span<float3> span_vector{vector};
- VArray_Span<float3> span_center{center};
- VArray_Span<float3> span_axis{axis};
- VArray_Span<float> span_angle{angle};
-
- threading::parallel_for(IndexRange(results.size()), 1024, [&](IndexRange range) {
- for (const int i : range) {
- float angle = (invert) ? -span_angle[i] : span_angle[i];
- results[i] = vector_rotate_around_axis(span_vector[i], span_center[i], span_axis[i], angle);
- }
- });
-}
-
-static void do_vector_rotate_around_fixed_axis(const VArray<float3> &vector,
- const VArray<float3> &center,
- const float3 axis,
- const VArray<float> &angle,
- MutableSpan<float3> results,
- const bool invert)
-{
- VArray_Span<float3> span_vector{vector};
- VArray_Span<float3> span_center{center};
- VArray_Span<float> span_angle{angle};
-
- threading::parallel_for(IndexRange(results.size()), 1024, [&](IndexRange range) {
- for (const int i : range) {
- float angle = (invert) ? -span_angle[i] : span_angle[i];
- results[i] = vector_rotate_around_axis(span_vector[i], span_center[i], axis, angle);
- }
- });
-}
-
-static void do_vector_rotate_euler(const VArray<float3> &vector,
- const VArray<float3> &center,
- const VArray<float3> &rotation,
- MutableSpan<float3> results,
- const bool invert)
-{
- VArray_Span<float3> span_vector{vector};
- VArray_Span<float3> span_center{center};
- VArray_Span<float3> span_rotation{rotation};
-
- threading::parallel_for(IndexRange(results.size()), 1024, [&](IndexRange range) {
- for (const int i : range) {
- results[i] = vector_rotate_euler(span_vector[i], span_center[i], span_rotation[i], invert);
- }
- });
-}
-
-static AttributeDomain get_result_domain(const GeometryComponent &component,
- const GeoNodeExecParams &params,
- StringRef result_name)
-{
- /* Use the domain of the result attribute if it already exists. */
- std::optional<AttributeMetaData> meta_data = component.attribute_get_meta_data(result_name);
- if (meta_data) {
- return meta_data->domain;
- }
-
- /* Otherwise use the highest priority domain from existing input attributes, or the default. */
- const AttributeDomain default_domain = ATTR_DOMAIN_POINT;
- return params.get_highest_priority_input_domain({"Vector", "Center"}, component, default_domain);
-}
-
-static void execute_on_component(const GeoNodeExecParams &params, GeometryComponent &component)
-{
- const bNode &node = params.node();
- const NodeAttributeVectorRotate *node_storage = (const NodeAttributeVectorRotate *)node.storage;
- const GeometryNodeAttributeVectorRotateMode mode = (GeometryNodeAttributeVectorRotateMode)
- node_storage->mode;
- const std::string result_name = params.get_input<std::string>("Result");
- const AttributeDomain result_domain = get_result_domain(component, params, result_name);
- const bool invert = params.get_input<bool>("Invert");
-
- GVArray attribute_vector = params.get_input_attribute(
- "Vector", component, result_domain, CD_PROP_FLOAT3, nullptr);
- if (!attribute_vector) {
- return;
- }
- GVArray attribute_center = params.get_input_attribute(
- "Center", component, result_domain, CD_PROP_FLOAT3, nullptr);
- if (!attribute_center) {
- return;
- }
-
- OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
- result_name, result_domain, CD_PROP_FLOAT3);
- if (!attribute_result) {
- return;
- }
-
- if (mode == GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) {
- GVArray attribute_rotation = params.get_input_attribute(
- "Rotation", component, result_domain, CD_PROP_FLOAT3, nullptr);
- if (!attribute_rotation) {
- return;
- }
- do_vector_rotate_euler(attribute_vector.typed<float3>(),
- attribute_center.typed<float3>(),
- attribute_rotation.typed<float3>(),
- attribute_result.as_span<float3>(),
- invert);
- attribute_result.save();
- return;
- }
-
- GVArray attribute_angle = params.get_input_attribute(
- "Angle", component, result_domain, CD_PROP_FLOAT, nullptr);
- if (!attribute_angle) {
- return;
- }
-
- switch (mode) {
- case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS: {
- GVArray attribute_axis = params.get_input_attribute(
- "Axis", component, result_domain, CD_PROP_FLOAT3, nullptr);
- if (!attribute_axis) {
- return;
- }
- do_vector_rotate_around_axis(attribute_vector.typed<float3>(),
- attribute_center.typed<float3>(),
- attribute_axis.typed<float3>(),
- attribute_angle.typed<float>(),
- attribute_result.as_span<float3>(),
- invert);
- } break;
- case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_X:
- do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(),
- attribute_center.typed<float3>(),
- float3(1.0f, 0.0f, 0.0f),
- attribute_angle.typed<float>(),
- attribute_result.as_span<float3>(),
- invert);
- break;
- case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Y:
- do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(),
- attribute_center.typed<float3>(),
- float3(0.0f, 1.0f, 0.0f),
- attribute_angle.typed<float>(),
- attribute_result.as_span<float3>(),
- invert);
-
- break;
- case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Z:
- do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(),
- attribute_center.typed<float3>(),
- float3(0.0f, 0.0f, 1.0f),
- attribute_angle.typed<float>(),
- attribute_result.as_span<float3>(),
- invert);
-
- break;
- case GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ:
- /* Euler is handled before other modes to avoid processing the unavailable angle socket. */
- BLI_assert_unreachable();
- break;
- }
- attribute_result.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
- }
- if (geometry_set.has<PointCloudComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<PointCloudComponent>());
- }
- if (geometry_set.has<CurveComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<CurveComponent>());
- }
-
- params.set_output("Geometry", std::move(geometry_set));
-}
-
-} // 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,
- GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_ROTATE,
- "Attribute Vector Rotate",
- NODE_CLASS_ATTRIBUTE);
- 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 = 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_legacy_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
deleted file mode 100644
index 0980c2d6e72..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc
+++ /dev/null
@@ -1,207 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_task.hh"
-#include "BLI_timeit.hh"
-
-#include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_curve_endpoints_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_output<decl::Geometry>(N_("Start Points"));
- b.add_output<decl::Geometry>(N_("End Points"));
-}
-
-/**
- * Evaluate splines in parallel to speed up the rest of the node's execution.
- */
-static void evaluate_splines(Span<SplinePtr> splines)
-{
- threading::parallel_for_each(splines, [](const SplinePtr &spline) {
- /* These functions fill the corresponding caches on each spline. */
- spline->evaluated_positions();
- spline->evaluated_tangents();
- spline->evaluated_normals();
- spline->evaluated_lengths();
- });
-}
-
-/**
- * \note Use attributes from the curve component rather than the attribute data directly on the
- * attribute storage to allow reading the virtual spline attributes like "cyclic" and "resolution".
- */
-static void copy_spline_domain_attributes(const CurveComponent &curve_component,
- Span<int> offsets,
- PointCloudComponent &points)
-{
- curve_component.attribute_foreach(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- if (meta_data.domain != ATTR_DOMAIN_CURVE) {
- return true;
- }
- GVArray spline_attribute = curve_component.attribute_get_for_read(
- attribute_id, ATTR_DOMAIN_CURVE, meta_data.data_type);
-
- OutputAttribute result_attribute = points.attribute_try_get_for_output_only(
- attribute_id, ATTR_DOMAIN_POINT, meta_data.data_type);
- GMutableSpan result = result_attribute.as_span();
-
- /* Only copy the attributes of splines in the offsets. */
- for (const int i : offsets.index_range()) {
- spline_attribute.get(offsets[i], result[i]);
- }
-
- result_attribute.save();
- return true;
- });
-}
-
-/**
- * Get the offsets for the splines whose endpoints we want to output.
- * Filter those which are cyclic, or that evaluate to empty.
- * Could be easily adapted to include a selection argument to support attribute selection.
- */
-static blender::Vector<int> get_endpoint_spline_offsets(Span<SplinePtr> splines)
-{
- blender::Vector<int> spline_offsets;
- spline_offsets.reserve(splines.size());
-
- for (const int i : splines.index_range()) {
- if (!(splines[i]->is_cyclic() || splines[i]->evaluated_points_size() == 0)) {
- spline_offsets.append(i);
- }
- }
-
- return spline_offsets;
-}
-
-/**
- * Copy the endpoint attributes from the correct positions at the splines at the offsets to
- * the start and end attributes.
- */
-static void copy_endpoint_attributes(Span<SplinePtr> splines,
- Span<int> offsets,
- CurveToPointsResults &start_data,
- CurveToPointsResults &end_data)
-{
- threading::parallel_for(offsets.index_range(), 64, [&](IndexRange range) {
- for (const int i : range) {
- const Spline &spline = *splines[offsets[i]];
-
- /* Copy the start and end point data over. */
- start_data.positions[i] = spline.evaluated_positions().first();
- start_data.tangents[i] = spline.evaluated_tangents().first();
- start_data.normals[i] = spline.evaluated_normals().first();
- start_data.radii[i] = spline.radii().first();
- start_data.tilts[i] = spline.tilts().first();
-
- end_data.positions[i] = spline.evaluated_positions().last();
- end_data.tangents[i] = spline.evaluated_tangents().last();
- end_data.normals[i] = spline.evaluated_normals().last();
- end_data.radii[i] = spline.radii().last();
- end_data.tilts[i] = spline.tilts().last();
-
- /* Copy the point attribute data over. */
- for (const auto item : start_data.point_attributes.items()) {
- const AttributeIDRef attribute_id = item.key;
- GMutableSpan point_span = item.value;
-
- BLI_assert(spline.attributes.get_for_read(attribute_id));
- GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
- spline_span.type().copy_assign(spline_span[0], point_span[i]);
- }
-
- for (const auto item : end_data.point_attributes.items()) {
- const AttributeIDRef attribute_id = item.key;
- GMutableSpan point_span = item.value;
-
- BLI_assert(spline.attributes.get_for_read(attribute_id));
- GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
- spline_span.type().copy_assign(spline_span[spline.size() - 1], point_span[i]);
- }
- }
- });
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (!geometry_set.has_curves()) {
- params.set_default_remaining_outputs();
- return;
- }
-
- const CurveComponent &curve_component = *geometry_set.get_component_for_read<CurveComponent>();
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
- const Span<SplinePtr> splines = curve->splines();
- curve->assert_valid_point_attributes();
-
- evaluate_splines(splines);
-
- const Vector<int> offsets = get_endpoint_spline_offsets(splines);
- const int total_size = offsets.size();
-
- if (total_size == 0) {
- params.set_default_remaining_outputs();
- return;
- }
-
- GeometrySet start_result = GeometrySet::create_with_pointcloud(
- BKE_pointcloud_new_nomain(total_size));
- GeometrySet end_result = GeometrySet::create_with_pointcloud(
- BKE_pointcloud_new_nomain(total_size));
- PointCloudComponent &start_point_component =
- start_result.get_component_for_write<PointCloudComponent>();
- PointCloudComponent &end_point_component =
- end_result.get_component_for_write<PointCloudComponent>();
-
- CurveToPointsResults start_attributes = curve_to_points_create_result_attributes(
- start_point_component, *curve);
- CurveToPointsResults end_attributes = curve_to_points_create_result_attributes(
- end_point_component, *curve);
-
- copy_endpoint_attributes(splines, offsets.as_span(), start_attributes, end_attributes);
- copy_spline_domain_attributes(curve_component, offsets.as_span(), start_point_component);
- curve_create_default_rotation_attribute(
- start_attributes.tangents, start_attributes.normals, start_attributes.rotations);
- curve_create_default_rotation_attribute(
- end_attributes.tangents, end_attributes.normals, end_attributes.rotations);
-
- /* The default radius is way too large for points, divide by 10. */
- for (float &radius : start_attributes.radii) {
- radius *= 0.1f;
- }
- for (float &radius : end_attributes.radii) {
- radius *= 0.1f;
- }
-
- params.set_output("Start Points", std::move(start_result));
- params.set_output("End Points", std::move(end_result));
-}
-
-} // 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);
- 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_legacy_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
deleted file mode 100644
index 2c801642bd7..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_task.hh"
-
-#include "BKE_spline.hh"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_curve_reverse_cc {
-
-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 node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- geometry_set = geometry::realize_instances_legacy(geometry_set);
- if (!geometry_set.has_curves()) {
- params.set_output("Curve", geometry_set);
- return;
- }
-
- /* Retrieve data for write access so we can avoid new allocations for the reversed data. */
- CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
- MutableSpan<SplinePtr> splines = curve->splines();
-
- const std::string selection_name = params.extract_input<std::string>("Selection");
- VArray<bool> selection = curve_component.attribute_get_for_read(
- selection_name, ATTR_DOMAIN_CURVE, true);
-
- threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
- for (const int i : range) {
- if (selection[i]) {
- splines[i]->reverse();
- }
- }
- });
-
- geometry_set.replace_curves(curve_eval_to_curves(*curve));
-
- params.set_output("Curve", geometry_set);
-}
-
-} // 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);
- 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_legacy_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
deleted file mode 100644
index 729ccca5f04..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_task.hh"
-
-#include "BKE_spline.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc {
-
-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 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 node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeGeometryCurveSelectHandles *data = MEM_cnew<NodeGeometryCurveSelectHandles>(__func__);
-
- data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
- data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
- node->storage = data;
-}
-
-static HandleType handle_type_from_input_type(const GeometryNodeCurveHandleType type)
-{
- switch (type) {
- case GEO_NODE_CURVE_HANDLE_AUTO:
- return BEZIER_HANDLE_AUTO;
- case GEO_NODE_CURVE_HANDLE_ALIGN:
- return BEZIER_HANDLE_ALIGN;
- case GEO_NODE_CURVE_HANDLE_FREE:
- return BEZIER_HANDLE_FREE;
- case GEO_NODE_CURVE_HANDLE_VECTOR:
- return BEZIER_HANDLE_VECTOR;
- }
- BLI_assert_unreachable();
- return BEZIER_HANDLE_AUTO;
-}
-
-static void select_curve_by_handle_type(const CurveEval &curve,
- const HandleType type,
- const GeometryNodeCurveHandleMode mode,
- const MutableSpan<bool> r_selection)
-{
- const Array<int> offsets = curve.control_point_offsets();
- Span<SplinePtr> splines = curve.splines();
- threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
- for (const int i_spline : range) {
- const Spline &spline = *splines[i_spline];
- if (spline.type() == CURVE_TYPE_BEZIER) {
- const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(spline);
- Span<int8_t> types_left = bezier_spline.handle_types_left();
- Span<int8_t> types_right = bezier_spline.handle_types_right();
- for (const int i_point : IndexRange(bezier_spline.size())) {
- r_selection[offsets[i_spline] + i_point] = (mode & GEO_NODE_CURVE_HANDLE_LEFT &&
- types_left[i_point] == type) ||
- (mode & GEO_NODE_CURVE_HANDLE_RIGHT &&
- types_right[i_point] == type);
- }
- }
- else {
- r_selection.slice(offsets[i_spline], offsets[i_spline + 1]).fill(false);
- }
- }
- });
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- const NodeGeometryCurveSelectHandles *storage =
- (const NodeGeometryCurveSelectHandles *)params.node().storage;
- const HandleType handle_type = handle_type_from_input_type(
- (GeometryNodeCurveHandleType)storage->handle_type);
- const GeometryNodeCurveHandleMode mode = (GeometryNodeCurveHandleMode)storage->mode;
-
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- if (curve_component.has_curves()) {
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
- const std::string selection_name = params.extract_input<std::string>("Selection");
- OutputAttribute_Typed<bool> selection =
- curve_component.attribute_try_get_for_output_only<bool>(selection_name, ATTR_DOMAIN_POINT);
- if (selection) {
- select_curve_by_handle_type(*curve, handle_type, mode, selection.as_span());
- selection.save();
- }
- }
-
- params.set_output("Geometry", std::move(geometry_set));
-}
-
-} // 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, GEO_NODE_LEGACY_CURVE_SELECT_HANDLES, "Select by Handle Type", NODE_CLASS_GEOMETRY);
- 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 = file_ns::node_layout;
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
deleted file mode 100644
index 56e9068882b..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc
+++ /dev/null
@@ -1,131 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BKE_spline.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_curve_set_handles_cc {
-
-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 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 node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeGeometryCurveSetHandles *data = MEM_cnew<NodeGeometryCurveSetHandles>(__func__);
-
- data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
- data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT;
- node->storage = data;
-}
-
-static HandleType handle_type_from_input_type(GeometryNodeCurveHandleType type)
-{
- switch (type) {
- case GEO_NODE_CURVE_HANDLE_AUTO:
- return BEZIER_HANDLE_AUTO;
- case GEO_NODE_CURVE_HANDLE_ALIGN:
- return BEZIER_HANDLE_ALIGN;
- case GEO_NODE_CURVE_HANDLE_FREE:
- return BEZIER_HANDLE_FREE;
- case GEO_NODE_CURVE_HANDLE_VECTOR:
- return BEZIER_HANDLE_VECTOR;
- }
- BLI_assert_unreachable();
- return BEZIER_HANDLE_AUTO;
-}
-
-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;
-
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve");
- geometry_set = geometry::realize_instances_legacy(geometry_set);
- if (!geometry_set.has_curves()) {
- params.set_output("Curve", geometry_set);
- return;
- }
-
- /* Retrieve data for write access so we can avoid new allocations for the handles data. */
- CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
- MutableSpan<SplinePtr> splines = curve->splines();
-
- const std::string selection_name = params.extract_input<std::string>("Selection");
- VArray<bool> selection = curve_component.attribute_get_for_read(
- selection_name, ATTR_DOMAIN_POINT, true);
-
- const HandleType new_handle_type = handle_type_from_input_type(type);
- int point_index = 0;
- bool has_bezier_spline = false;
- for (SplinePtr &spline : splines) {
- if (spline->type() != CURVE_TYPE_BEZIER) {
- point_index += spline->positions().size();
- continue;
- }
-
- BezierSpline &bezier_spline = static_cast<BezierSpline &>(*spline);
- if (ELEM(new_handle_type, BEZIER_HANDLE_FREE, BEZIER_HANDLE_ALIGN)) {
- /* In this case the automatically calculated handle types need to be "baked", because
- * they're possibly changing from a type that is calculated automatically to a type that
- * is positioned manually. */
- bezier_spline.ensure_auto_handles();
- }
- has_bezier_spline = true;
- for (int i_point : IndexRange(bezier_spline.size())) {
- if (selection[point_index]) {
- if (mode & GEO_NODE_CURVE_HANDLE_LEFT) {
- bezier_spline.handle_types_left()[i_point] = new_handle_type;
- }
- if (mode & GEO_NODE_CURVE_HANDLE_RIGHT) {
- bezier_spline.handle_types_right()[i_point] = new_handle_type;
- }
- }
- point_index++;
- }
- bezier_spline.mark_cache_invalid();
- }
-
- geometry_set.replace_curves(curve_eval_to_curves(*curve));
-
- if (!has_bezier_spline) {
- params.error_message_add(NodeWarningType::Info, TIP_("No Bezier splines in input curve"));
- }
-
- params.set_output("Curve", geometry_set);
-}
-} // 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);
- 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 = file_ns::node_layout;
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
deleted file mode 100644
index 002c42c4c82..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc
+++ /dev/null
@@ -1,294 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BKE_spline.hh"
-
-#include "BLI_task.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_curve_spline_type_cc {
-
-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 node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE);
-}
-
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__);
-
- data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
- node->storage = data;
-}
-
-template<class T>
-static void scale_input_assign(const Span<T> input,
- const int scale,
- const int offset,
- const MutableSpan<T> r_output)
-{
- for (const int i : IndexRange(r_output.size())) {
- r_output[i] = input[i * scale + offset];
- }
-}
-
-template<class T>
-static void scale_output_assign(const Span<T> input,
- const int scale,
- const int offset,
- const MutableSpan<T> &r_output)
-{
- for (const int i : IndexRange(input.size())) {
- r_output[i * scale + offset] = input[i];
- }
-}
-
-template<typename CopyFn>
-static void copy_attributes(const Spline &input_spline, Spline &output_spline, CopyFn copy_fn)
-{
- input_spline.attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- std::optional<GSpan> src = input_spline.attributes.get_for_read(attribute_id);
- BLI_assert(src);
- if (!output_spline.attributes.create(attribute_id, meta_data.data_type)) {
- BLI_assert_unreachable();
- return false;
- }
- std::optional<GMutableSpan> dst = output_spline.attributes.get_for_write(attribute_id);
- if (!dst) {
- BLI_assert_unreachable();
- return false;
- }
-
- copy_fn(*src, *dst);
-
- return true;
- },
- ATTR_DOMAIN_POINT);
-}
-
-static SplinePtr convert_to_poly_spline(const Spline &input)
-{
- std::unique_ptr<PolySpline> output = std::make_unique<PolySpline>();
- output->resize(input.positions().size());
- output->positions().copy_from(input.positions());
- output->radii().copy_from(input.radii());
- output->tilts().copy_from(input.tilts());
- Spline::copy_base_settings(input, *output);
- output->attributes = input.attributes;
- return output;
-}
-
-static SplinePtr poly_to_nurbs(const Spline &input)
-{
- std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>();
- output->resize(input.positions().size());
- output->positions().copy_from(input.positions());
- output->radii().copy_from(input.radii());
- output->tilts().copy_from(input.tilts());
- output->weights().fill(1.0f);
- output->set_resolution(12);
- output->set_order(4);
- Spline::copy_base_settings(input, *output);
- output->knots_mode = NURBS_KNOT_MODE_BEZIER;
- output->attributes = input.attributes;
- return output;
-}
-
-static SplinePtr bezier_to_nurbs(const Spline &input)
-{
- const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(input);
- std::unique_ptr<NURBSpline> output = std::make_unique<NURBSpline>();
- output->resize(input.size() * 3);
-
- scale_output_assign(bezier_spline.handle_positions_left(), 3, 0, output->positions());
- scale_output_assign(input.radii(), 3, 0, output->radii());
- scale_output_assign(input.tilts(), 3, 0, output->tilts());
-
- scale_output_assign(bezier_spline.positions(), 3, 1, output->positions());
- scale_output_assign(input.radii(), 3, 1, output->radii());
- scale_output_assign(input.tilts(), 3, 1, output->tilts());
-
- scale_output_assign(bezier_spline.handle_positions_right(), 3, 2, output->positions());
- scale_output_assign(input.radii(), 3, 2, output->radii());
- scale_output_assign(input.tilts(), 3, 2, output->tilts());
-
- Spline::copy_base_settings(input, *output);
- output->weights().fill(1.0f);
- output->set_resolution(12);
- output->set_order(4);
- output->set_cyclic(input.is_cyclic());
- output->knots_mode = NURBS_KNOT_MODE_BEZIER;
- output->attributes.reallocate(output->size());
- copy_attributes(input, *output, [](GSpan src, GMutableSpan dst) {
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- scale_output_assign<T>(src.typed<T>(), 3, 0, dst.typed<T>());
- scale_output_assign<T>(src.typed<T>(), 3, 1, dst.typed<T>());
- scale_output_assign<T>(src.typed<T>(), 3, 2, dst.typed<T>());
- });
- });
- return output;
-}
-
-static SplinePtr poly_to_bezier(const Spline &input)
-{
- std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>();
- output->resize(input.size());
- output->positions().copy_from(input.positions());
- output->radii().copy_from(input.radii());
- output->tilts().copy_from(input.tilts());
- output->handle_types_left().fill(BEZIER_HANDLE_VECTOR);
- output->handle_types_right().fill(BEZIER_HANDLE_VECTOR);
- output->set_resolution(12);
- Spline::copy_base_settings(input, *output);
- output->attributes = input.attributes;
- return output;
-}
-
-static SplinePtr nurbs_to_bezier(const Spline &input)
-{
- const NURBSpline &nurbs_spline = static_cast<const NURBSpline &>(input);
- std::unique_ptr<BezierSpline> output = std::make_unique<BezierSpline>();
- output->resize(input.size() / 3);
- scale_input_assign<float3>(input.positions(), 3, 1, output->positions());
- scale_input_assign<float3>(input.positions(), 3, 0, output->handle_positions_left());
- scale_input_assign<float3>(input.positions(), 3, 2, output->handle_positions_right());
- scale_input_assign<float>(input.radii(), 3, 2, output->radii());
- scale_input_assign<float>(input.tilts(), 3, 2, output->tilts());
- output->handle_types_left().fill(BEZIER_HANDLE_ALIGN);
- output->handle_types_right().fill(BEZIER_HANDLE_ALIGN);
- output->set_resolution(nurbs_spline.resolution());
- Spline::copy_base_settings(input, *output);
- output->attributes.reallocate(output->size());
- copy_attributes(input, *output, [](GSpan src, GMutableSpan dst) {
- attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- scale_input_assign<T>(src.typed<T>(), 3, 1, dst.typed<T>());
- });
- });
- return output;
-}
-
-static SplinePtr convert_to_bezier(const Spline &input, GeoNodeExecParams params)
-{
- switch (input.type()) {
- case CURVE_TYPE_BEZIER:
- return input.copy();
- case CURVE_TYPE_POLY:
- return poly_to_bezier(input);
- case CURVE_TYPE_NURBS:
- if (input.size() < 6) {
- params.error_message_add(
- NodeWarningType::Info,
- TIP_("NURBS must have minimum of 6 points for Bezier Conversion"));
- return input.copy();
- }
- else {
- if (input.size() % 3 != 0) {
- params.error_message_add(NodeWarningType::Info,
- TIP_("NURBS must have multiples of 3 points for full Bezier "
- "conversion, curve truncated"));
- }
- return nurbs_to_bezier(input);
- }
- case CURVE_TYPE_CATMULL_ROM: {
- BLI_assert_unreachable();
- return {};
- }
- }
- BLI_assert_unreachable();
- return {};
-}
-
-static SplinePtr convert_to_nurbs(const Spline &input)
-{
- switch (input.type()) {
- case CURVE_TYPE_NURBS:
- return input.copy();
- case CURVE_TYPE_BEZIER:
- return bezier_to_nurbs(input);
- case CURVE_TYPE_POLY:
- return poly_to_nurbs(input);
- case CURVE_TYPE_CATMULL_ROM:
- BLI_assert_unreachable();
- return {};
- }
- BLI_assert_unreachable();
- return {};
-}
-
-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 = geometry::realize_instances_legacy(geometry_set);
- if (!geometry_set.has_curves()) {
- params.set_output("Curve", geometry_set);
- return;
- }
-
- const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>();
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component->get_for_read());
-
- const std::string selection_name = params.extract_input<std::string>("Selection");
- VArray<bool> selection = curve_component->attribute_get_for_read(
- selection_name, ATTR_DOMAIN_CURVE, true);
-
- 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;
- }
- }
- else {
- new_curve->add_spline(curve->splines()[i]->copy());
- }
- }
-
- new_curve->attributes = curve->attributes;
- params.set_output("Curve", GeometrySet::create_with_curves(curve_eval_to_curves(*new_curve)));
-}
-
-} // 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);
- 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 = file_ns::node_layout;
-
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
deleted file mode 100644
index 03f7aec8838..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc
+++ /dev/null
@@ -1,384 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_task.hh"
-#include "BLI_timeit.hh"
-
-#include "BKE_attribute_math.hh"
-#include "BKE_spline.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_curve_subdivide_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Cuts"));
- b.add_input<decl::Int>(N_("Cuts"), "Cuts_001").default_value(1).min(0).max(1000);
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-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 node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeGeometryCurveSubdivide *data = MEM_cnew<NodeGeometryCurveSubdivide>(__func__);
-
- data->cuts_type = GEO_NODE_ATTRIBUTE_INPUT_INTEGER;
- node->storage = data;
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage;
-
- update_attribute_input_socket_availabilities(
- *ntree, *node, "Cuts", (GeometryNodeAttributeInputMode)node_storage.input_type);
-}
-
-static Array<int> get_subdivided_offsets(const Spline &spline,
- const VArray<int> &cuts,
- const int spline_offset)
-{
- Array<int> offsets(spline.segments_size() + 1);
- int offset = 0;
- for (const int i : IndexRange(spline.segments_size())) {
- offsets[i] = offset;
- offset = offset + std::max(cuts[spline_offset + i], 0) + 1;
- }
- offsets.last() = offset;
- return offsets;
-}
-
-template<typename T>
-static void subdivide_attribute(Span<T> src,
- const Span<int> offsets,
- const bool is_cyclic,
- MutableSpan<T> dst)
-{
- const int src_size = src.size();
- threading::parallel_for(IndexRange(src_size - 1), 1024, [&](IndexRange range) {
- for (const int i : range) {
- const int cuts = offsets[i + 1] - offsets[i];
- dst[offsets[i]] = src[i];
- const float factor_delta = 1.0f / (cuts + 1.0f);
- for (const int cut : IndexRange(cuts)) {
- const float factor = (cut + 1) * factor_delta;
- dst[offsets[i] + cut] = attribute_math::mix2(factor, src[i], src[i + 1]);
- }
- }
- });
-
- if (is_cyclic) {
- const int i = src_size - 1;
- const int cuts = offsets[i + 1] - offsets[i];
- dst[offsets[i]] = src.last();
- const float factor_delta = 1.0f / (cuts + 1.0f);
- for (const int cut : IndexRange(cuts)) {
- const float factor = (cut + 1) * factor_delta;
- dst[offsets[i] + cut] = attribute_math::mix2(factor, src.last(), src.first());
- }
- }
- else {
- dst.last() = src.last();
- }
-}
-
-/**
- * In order to generate a Bezier spline with the same shape as the input spline, apply the
- * De Casteljau algorithm iteratively for the provided number of cuts, constantly updating the
- * previous result point's right handle and the left handle at the end of the segment.
- *
- * \note Non-vector segments in the result spline are given free handles. This could possibly be
- * improved with another pass that sets handles to aligned where possible, but currently that does
- * not provide much benefit for the increased complexity.
- */
-static void subdivide_bezier_segment(const BezierSpline &src,
- const int index,
- const int offset,
- const int result_size,
- Span<float3> src_positions,
- Span<float3> src_handles_left,
- Span<float3> src_handles_right,
- MutableSpan<float3> dst_positions,
- MutableSpan<float3> dst_handles_left,
- MutableSpan<float3> dst_handles_right,
- MutableSpan<int8_t> dst_type_left,
- MutableSpan<int8_t> dst_type_right)
-{
- const bool is_last_cyclic_segment = index == (src.size() - 1);
- const int next_index = is_last_cyclic_segment ? 0 : index + 1;
-
- /* The first point in the segment is always copied. */
- dst_positions[offset] = src_positions[index];
-
- if (src.segment_is_vector(index)) {
- if (is_last_cyclic_segment) {
- dst_type_left.first() = BEZIER_HANDLE_VECTOR;
- }
- dst_type_left.slice(offset + 1, result_size).fill(BEZIER_HANDLE_VECTOR);
- dst_type_right.slice(offset, result_size).fill(BEZIER_HANDLE_VECTOR);
-
- const float factor_delta = 1.0f / result_size;
- for (const int cut : IndexRange(result_size)) {
- const float factor = cut * factor_delta;
- dst_positions[offset + cut] = attribute_math::mix2(
- factor, src_positions[index], src_positions[next_index]);
- }
- }
- else {
- if (is_last_cyclic_segment) {
- dst_type_left.first() = BEZIER_HANDLE_FREE;
- }
- dst_type_left.slice(offset + 1, result_size).fill(BEZIER_HANDLE_FREE);
- dst_type_right.slice(offset, result_size).fill(BEZIER_HANDLE_FREE);
-
- const int i_segment_last = is_last_cyclic_segment ? 0 : offset + result_size;
-
- /* Create a Bezier segment to update iteratively for every subdivision
- * and references to the meaningful values for ease of use. */
- BezierSpline temp;
- temp.resize(2);
- float3 &segment_start = temp.positions().first();
- float3 &segment_end = temp.positions().last();
- float3 &handle_prev = temp.handle_positions_right().first();
- float3 &handle_next = temp.handle_positions_left().last();
- segment_start = src_positions[index];
- segment_end = src_positions[next_index];
- handle_prev = src_handles_right[index];
- handle_next = src_handles_left[next_index];
-
- for (const int cut : IndexRange(result_size - 1)) {
- const float parameter = 1.0f / (result_size - cut);
- const BezierSpline::InsertResult insert = temp.calculate_segment_insertion(0, 1, parameter);
-
- /* Copy relevant temporary data to the result. */
- dst_handles_right[offset + cut] = insert.handle_prev;
- dst_handles_left[offset + cut + 1] = insert.left_handle;
- dst_positions[offset + cut + 1] = insert.position;
-
- /* Update the segment to prepare it for the next subdivision. */
- segment_start = insert.position;
- handle_prev = insert.right_handle;
- handle_next = insert.handle_next;
- }
-
- /* Copy the handles for the last segment from the temporary spline. */
- dst_handles_right[offset + result_size - 1] = handle_prev;
- dst_handles_left[i_segment_last] = handle_next;
- }
-}
-
-static void subdivide_bezier_spline(const BezierSpline &src,
- const Span<int> offsets,
- BezierSpline &dst)
-{
- Span<float3> src_positions = src.positions();
- Span<float3> src_handles_left = src.handle_positions_left();
- Span<float3> src_handles_right = src.handle_positions_right();
- MutableSpan<float3> dst_positions = dst.positions();
- MutableSpan<float3> dst_handles_left = dst.handle_positions_left();
- MutableSpan<float3> dst_handles_right = dst.handle_positions_right();
- MutableSpan<int8_t> dst_type_left = dst.handle_types_left();
- MutableSpan<int8_t> dst_type_right = dst.handle_types_right();
-
- threading::parallel_for(IndexRange(src.size() - 1), 512, [&](IndexRange range) {
- for (const int i : range) {
- subdivide_bezier_segment(src,
- i,
- offsets[i],
- offsets[i + 1] - offsets[i],
- src_positions,
- src_handles_left,
- src_handles_right,
- dst_positions,
- dst_handles_left,
- dst_handles_right,
- dst_type_left,
- dst_type_right);
- }
- });
-
- if (src.is_cyclic()) {
- const int i_last = src.size() - 1;
- subdivide_bezier_segment(src,
- i_last,
- offsets[i_last],
- offsets.last() - offsets[i_last],
- src_positions,
- src_handles_left,
- src_handles_right,
- dst_positions,
- dst_handles_left,
- dst_handles_right,
- dst_type_left,
- dst_type_right);
- }
- else {
- dst_positions.last() = src_positions.last();
- }
-}
-
-static void subdivide_builtin_attributes(const Spline &src_spline,
- const Span<int> offsets,
- Spline &dst_spline)
-{
- const bool is_cyclic = src_spline.is_cyclic();
- subdivide_attribute<float>(src_spline.radii(), offsets, is_cyclic, dst_spline.radii());
- subdivide_attribute<float>(src_spline.tilts(), offsets, is_cyclic, dst_spline.tilts());
- switch (src_spline.type()) {
- case CURVE_TYPE_POLY: {
- const PolySpline &src = static_cast<const PolySpline &>(src_spline);
- PolySpline &dst = static_cast<PolySpline &>(dst_spline);
- subdivide_attribute<float3>(src.positions(), offsets, is_cyclic, dst.positions());
- break;
- }
- case CURVE_TYPE_BEZIER: {
- const BezierSpline &src = static_cast<const BezierSpline &>(src_spline);
- BezierSpline &dst = static_cast<BezierSpline &>(dst_spline);
- subdivide_bezier_spline(src, offsets, dst);
- dst.mark_cache_invalid();
- break;
- }
- case CURVE_TYPE_NURBS: {
- const NURBSpline &src = static_cast<const NURBSpline &>(src_spline);
- NURBSpline &dst = static_cast<NURBSpline &>(dst_spline);
- subdivide_attribute<float3>(src.positions(), offsets, is_cyclic, dst.positions());
- subdivide_attribute<float>(src.weights(), offsets, is_cyclic, dst.weights());
- break;
- }
- case CURVE_TYPE_CATMULL_ROM: {
- BLI_assert_unreachable();
- break;
- }
- }
-}
-
-static void subdivide_dynamic_attributes(const Spline &src_spline,
- const Span<int> offsets,
- Spline &dst_spline)
-{
- const bool is_cyclic = src_spline.is_cyclic();
- src_spline.attributes.foreach_attribute(
- [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- std::optional<GSpan> src = src_spline.attributes.get_for_read(attribute_id);
- BLI_assert(src);
-
- if (!dst_spline.attributes.create(attribute_id, meta_data.data_type)) {
- /* Since the source spline of the same type had the attribute, adding it should work. */
- BLI_assert_unreachable();
- }
-
- std::optional<GMutableSpan> dst = dst_spline.attributes.get_for_write(attribute_id);
- BLI_assert(dst);
-
- attribute_math::convert_to_static_type(dst->type(), [&](auto dummy) {
- using T = decltype(dummy);
- subdivide_attribute<T>(src->typed<T>(), offsets, is_cyclic, dst->typed<T>());
- });
- return true;
- },
- ATTR_DOMAIN_POINT);
-}
-
-static SplinePtr subdivide_spline(const Spline &spline,
- const VArray<int> &cuts,
- const int spline_offset)
-{
- if (spline.size() <= 1) {
- return spline.copy();
- }
-
- /* Since we expect to access each value many times, it should be worth it to make sure count
- * of cuts is a real span (especially considering the note below). Using the offset at each
- * point facilitates subdividing in parallel later. */
- Array<int> offsets = get_subdivided_offsets(spline, cuts, spline_offset);
- const int result_size = offsets.last() + int(!spline.is_cyclic());
- SplinePtr new_spline = spline.copy_only_settings();
- new_spline->resize(result_size);
- subdivide_builtin_attributes(spline, offsets, *new_spline);
- subdivide_dynamic_attributes(spline, offsets, *new_spline);
- return new_spline;
-}
-
-/**
- * \note Passing the virtual array for the entire spline is possibly quite inefficient here when
- * the attribute was on the point domain and stored separately for each spline already, and it
- * prevents some other optimizations like skipping splines with a single attribute value of < 1.
- * However, it allows the node to access builtin attribute easily, so it the makes most sense this
- * way until the attribute API is refactored.
- */
-static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve,
- const VArray<int> &cuts)
-{
- const Array<int> control_point_offsets = input_curve.control_point_offsets();
- const Span<SplinePtr> input_splines = input_curve.splines();
-
- std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
- output_curve->resize(input_splines.size());
- output_curve->attributes = input_curve.attributes;
- MutableSpan<SplinePtr> output_splines = output_curve->splines();
-
- threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) {
- for (const int i : range) {
- output_splines[i] = subdivide_spline(*input_splines[i], cuts, control_point_offsets[i]);
- }
- });
-
- return output_curve;
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (!geometry_set.has_curves()) {
- params.set_output("Geometry", geometry_set);
- return;
- }
-
- const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
- VArray<int> cuts = params.get_input_attribute<int>("Cuts", component, ATTR_DOMAIN_POINT, 0);
- if (cuts.is_single() && cuts.get_internal_single() < 1) {
- params.set_output("Geometry", geometry_set);
- return;
- }
-
- std::unique_ptr<CurveEval> output_curve = subdivide_curve(
- *curves_to_curve_eval(*component.get_for_read()), cuts);
-
- params.set_output("Geometry",
- GeometrySet::create_with_curves(curve_eval_to_curves(*output_curve)));
-}
-
-} // 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);
- 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, 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_legacy_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
deleted file mode 100644
index f8fcc3cc363..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc
+++ /dev/null
@@ -1,351 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_array.hh"
-#include "BLI_task.hh"
-#include "BLI_timeit.hh"
-
-#include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes {
-
-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);
- b.add_input<decl::Float>(N_("Length")).default_value(0.1f).min(0.001f).subtype(PROP_DISTANCE);
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
-}
-
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeGeometryCurveToPoints *data = MEM_cnew<NodeGeometryCurveToPoints>(__func__);
-
- data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT;
- node->storage = data;
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage;
- const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode;
-
- bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next;
- bNodeSocket *length_socket = count_socket->next;
-
- nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT);
- nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH);
-}
-
-/**
- * Evaluate splines in parallel to speed up the rest of the node's execution.
- */
-static void evaluate_splines(Span<SplinePtr> splines)
-{
- threading::parallel_for_each(splines, [](const SplinePtr &spline) {
- /* These functions fill the corresponding caches on each spline. */
- spline->evaluated_positions();
- spline->evaluated_tangents();
- spline->evaluated_normals();
- spline->evaluated_lengths();
- });
-}
-
-static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
- const GeometryNodeCurveResampleMode mode,
- const CurveEval &curve,
- const Span<SplinePtr> splines)
-{
- const int size = curve.splines().size();
- switch (mode) {
- case GEO_NODE_CURVE_RESAMPLE_COUNT: {
- const int count = params.extract_input<int>("Count");
- if (count < 1) {
- return {0};
- }
- Array<int> offsets(size + 1);
- for (const int i : offsets.index_range()) {
- offsets[i] = count * i;
- }
- return offsets;
- }
- case GEO_NODE_CURVE_RESAMPLE_LENGTH: {
- /* Don't allow asymptotic count increase for low resolution values. */
- const float resolution = std::max(params.extract_input<float>("Length"), 0.0001f);
- Array<int> offsets(size + 1);
- int offset = 0;
- for (const int i : IndexRange(size)) {
- offsets[i] = offset;
- offset += splines[i]->length() / resolution + 1;
- }
- offsets.last() = offset;
- return offsets;
- }
- case GEO_NODE_CURVE_RESAMPLE_EVALUATED: {
- return curve.evaluated_point_offsets();
- }
- }
- BLI_assert_unreachable();
- return {0};
-}
-
-/**
- * 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.
- */
-static void copy_evaluated_point_attributes(Span<SplinePtr> splines,
- Span<int> offsets,
- CurveToPointsResults &data)
-{
- threading::parallel_for(splines.index_range(), 64, [&](IndexRange range) {
- for (const int i : range) {
- const Spline &spline = *splines[i];
- const int offset = offsets[i];
- const int size = offsets[i + 1] - offsets[i];
-
- data.positions.slice(offset, size).copy_from(spline.evaluated_positions());
- spline.interpolate_to_evaluated(spline.radii()).materialize(data.radii.slice(offset, size));
- spline.interpolate_to_evaluated(spline.tilts()).materialize(data.tilts.slice(offset, size));
-
- for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) {
- const AttributeIDRef attribute_id = item.key;
- GMutableSpan point_span = item.value;
-
- BLI_assert(spline.attributes.get_for_read(attribute_id));
- GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
-
- spline.interpolate_to_evaluated(spline_span)
- .materialize(point_span.slice(offset, size).data());
- }
-
- data.tangents.slice(offset, size).copy_from(spline.evaluated_tangents());
- data.normals.slice(offset, size).copy_from(spline.evaluated_normals());
- }
- });
-}
-
-static void copy_uniform_sample_point_attributes(Span<SplinePtr> splines,
- Span<int> offsets,
- CurveToPointsResults &data)
-{
- threading::parallel_for(splines.index_range(), 64, [&](IndexRange range) {
- for (const int i : range) {
- const Spline &spline = *splines[i];
- const int offset = offsets[i];
- const int size = offsets[i + 1] - offsets[i];
- if (size == 0) {
- continue;
- }
-
- const Array<float> uniform_samples = spline.sample_uniform_index_factors(size);
-
- spline.sample_with_index_factors<float3>(
- spline.evaluated_positions(), uniform_samples, data.positions.slice(offset, size));
-
- spline.sample_with_index_factors<float>(spline.interpolate_to_evaluated(spline.radii()),
- uniform_samples,
- data.radii.slice(offset, size));
-
- spline.sample_with_index_factors<float>(spline.interpolate_to_evaluated(spline.tilts()),
- uniform_samples,
- data.tilts.slice(offset, size));
-
- for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) {
- const AttributeIDRef attribute_id = item.key;
- GMutableSpan point_span = item.value;
-
- BLI_assert(spline.attributes.get_for_read(attribute_id));
- GSpan spline_span = *spline.attributes.get_for_read(attribute_id);
-
- spline.sample_with_index_factors(spline.interpolate_to_evaluated(spline_span),
- uniform_samples,
- point_span.slice(offset, size));
- }
-
- spline.sample_with_index_factors<float3>(
- spline.evaluated_tangents(), uniform_samples, data.tangents.slice(offset, size));
- for (float3 &tangent : data.tangents) {
- tangent = math::normalize(tangent);
- }
-
- spline.sample_with_index_factors<float3>(
- spline.evaluated_normals(), uniform_samples, data.normals.slice(offset, size));
- for (float3 &normals : data.normals) {
- normals = math::normalize(normals);
- }
- }
- });
-}
-
-/**
- * \note Use attributes from the curve component rather than the attribute data directly on the
- * attribute storage to allow reading the virtual spline attributes like "cyclic" and "resolution".
- */
-static void copy_spline_domain_attributes(const CurveComponent &curve_component,
- Span<int> offsets,
- PointCloudComponent &points)
-{
- curve_component.attribute_foreach(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- if (meta_data.domain != ATTR_DOMAIN_CURVE) {
- return true;
- }
- GVArray spline_attribute = curve_component.attribute_get_for_read(
- attribute_id, ATTR_DOMAIN_CURVE, meta_data.data_type);
- const CPPType &type = spline_attribute.type();
-
- OutputAttribute result_attribute = points.attribute_try_get_for_output_only(
- attribute_id, ATTR_DOMAIN_POINT, meta_data.data_type);
- GMutableSpan result = result_attribute.as_span();
-
- for (const int i : spline_attribute.index_range()) {
- const int offset = offsets[i];
- const int size = offsets[i + 1] - offsets[i];
- if (size != 0) {
- BUFFER_FOR_CPP_TYPE_VALUE(type, buffer);
- spline_attribute.get(i, buffer);
- type.fill_assign_n(buffer, result[offset], size);
- }
- }
-
- result_attribute.save();
- return true;
- });
-}
-
-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 = geometry::realize_instances_legacy(geometry_set);
-
- if (!geometry_set.has_curves()) {
- params.set_output("Geometry", GeometrySet());
- return;
- }
-
- const CurveComponent &curve_component = *geometry_set.get_component_for_read<CurveComponent>();
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curve_component.get_for_read());
- const Span<SplinePtr> splines = curve->splines();
- curve->assert_valid_point_attributes();
-
- evaluate_splines(splines);
-
- const Array<int> offsets = calculate_spline_point_offsets(params, mode, *curve, splines);
- const int total_size = offsets.last();
- if (total_size == 0) {
- params.set_output("Geometry", GeometrySet());
- return;
- }
-
- GeometrySet result = GeometrySet::create_with_pointcloud(BKE_pointcloud_new_nomain(total_size));
- PointCloudComponent &point_component = result.get_component_for_write<PointCloudComponent>();
-
- CurveToPointsResults new_attributes = curve_to_points_create_result_attributes(point_component,
- *curve);
- switch (mode) {
- case GEO_NODE_CURVE_RESAMPLE_COUNT:
- case GEO_NODE_CURVE_RESAMPLE_LENGTH:
- copy_uniform_sample_point_attributes(splines, offsets, new_attributes);
- break;
- case GEO_NODE_CURVE_RESAMPLE_EVALUATED:
- copy_evaluated_point_attributes(splines, offsets, new_attributes);
- break;
- }
-
- copy_spline_domain_attributes(curve_component, offsets, point_component);
- curve_create_default_rotation_attribute(
- new_attributes.tangents, new_attributes.normals, new_attributes.rotations);
-
- /* The default radius is way too large for points, divide by 10. */
- for (float &radius : new_attributes.radii) {
- radius *= 0.1f;
- }
-
- params.set_output("Geometry", std::move(result));
-}
-
-} // 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);
- 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, 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_legacy_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
deleted file mode 100644
index ca98d83c137..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc
+++ /dev/null
@@ -1,726 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_array.hh"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-
-#include "BKE_customdata.h"
-#include "BKE_mesh.h"
-#include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_delete_geometry_cc {
-
-using blender::bke::CustomDataAttributes;
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Selection"));
- b.add_input<decl::Bool>(N_("Invert"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-template<typename T> static void copy_data(Span<T> data, MutableSpan<T> r_data, IndexMask mask)
-{
- for (const int i_out : mask.index_range()) {
- r_data[i_out] = data[mask[i_out]];
- }
-}
-
-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;
- CustomData_copy_data(&src_mesh.vdata, &dst_mesh.vdata, i_src, i_dst, 1);
- }
-}
-
-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 (ELEM(i_dst, -1, -2)) {
- continue;
- }
-
- const MEdge &e_src = src_mesh.medge[i_src];
- MEdge &e_dst = dst_mesh.medge[i_dst];
-
- CustomData_copy_data(&src_mesh.edata, &dst_mesh.edata, i_src, i_dst, 1);
- e_dst = e_src;
- e_dst.v1 = vertex_map[e_src.v1];
- e_dst.v2 = vertex_map[e_src.v2];
- }
-}
-
-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];
-
- CustomData_copy_data(&src_mesh.pdata, &dst_mesh.pdata, i_src, i_dst, 1);
- CustomData_copy_data(&src_mesh.ldata, &dst_mesh.ldata, i_ml_src, i_ml_dst, mp_src.totloop);
-
- 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);
- switch (spline.type()) {
- case CURVE_TYPE_POLY:
- break;
- case CURVE_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);
- break;
- }
- case CURVE_TYPE_NURBS: {
- const NURBSpline &src = static_cast<const NURBSpline &>(spline);
- NURBSpline &dst = static_cast<NURBSpline &>(r_spline);
- copy_data(src.weights(), dst.weights(), mask);
- break;
- }
- case CURVE_TYPE_CATMULL_ROM: {
- BLI_assert_unreachable();
- break;
- }
- }
-}
-
-static void copy_dynamic_attributes(const CustomDataAttributes &src,
- CustomDataAttributes &dst,
- const IndexMask mask)
-{
- src.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- std::optional<GSpan> src_attribute = src.get_for_read(attribute_id);
- BLI_assert(src_attribute);
-
- if (!dst.create(attribute_id, meta_data.data_type)) {
- /* Since the source spline of the same type had the attribute, adding it should work.
- */
- BLI_assert_unreachable();
- }
-
- std::optional<GMutableSpan> new_attribute = dst.get_for_write(attribute_id);
- BLI_assert(new_attribute);
-
- 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);
- });
- return true;
- },
- ATTR_DOMAIN_POINT);
-}
-
-static SplinePtr spline_delete(const Spline &spline, const IndexMask mask)
-{
- SplinePtr new_spline = spline.copy_only_settings();
- new_spline->resize(mask.size());
-
- spline_copy_builtin_attributes(spline, *new_spline, mask);
- copy_dynamic_attributes(spline.attributes, new_spline->attributes, mask);
-
- return new_spline;
-}
-
-static std::unique_ptr<CurveEval> curve_delete(const CurveEval &input_curve,
- const StringRef name,
- const bool invert)
-{
- Span<SplinePtr> input_splines = input_curve.splines();
- std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
-
- /* Keep track of which splines were copied to the result to copy spline domain attributes. */
- Vector<int64_t> copied_splines;
-
- if (input_curve.attributes.get_for_read(name)) {
- VArray<bool> selection = input_curve.attributes.get_for_read<bool>(name, false);
- for (const int i : input_splines.index_range()) {
- if (selection[i] == invert) {
- output_curve->add_spline(input_splines[i]->copy());
- copied_splines.append(i);
- }
- }
- }
- else {
- /* Reuse index vector for each spline. */
- Vector<int64_t> indices_to_copy;
-
- for (const int i : input_splines.index_range()) {
- const Spline &spline = *input_splines[i];
- VArray<bool> selection = spline.attributes.get_for_read<bool>(name, false);
-
- indices_to_copy.clear();
- for (const int i_point : IndexRange(spline.size())) {
- if (selection[i_point] == invert) {
- indices_to_copy.append(i_point);
- }
- }
-
- /* Avoid creating an empty spline. */
- if (indices_to_copy.is_empty()) {
- continue;
- }
-
- SplinePtr new_spline = spline_delete(spline, IndexMask(indices_to_copy));
- output_curve->add_spline(std::move(new_spline));
- copied_splines.append(i);
- }
- }
-
- if (copied_splines.is_empty()) {
- return {};
- }
-
- output_curve->attributes.reallocate(output_curve->splines().size());
- copy_dynamic_attributes(
- input_curve.attributes, output_curve->attributes, IndexMask(copied_splines));
-
- return output_curve;
-}
-
-static void delete_curve_selection(const CurveComponent &in_component,
- CurveComponent &r_component,
- const StringRef selection_name,
- const bool invert)
-{
- std::unique_ptr<CurveEval> r_curve = curve_delete(
- *curves_to_curve_eval(*in_component.get_for_read()), selection_name, invert);
- if (r_curve) {
- r_component.replace(curve_eval_to_curves(*r_curve));
- }
- else {
- r_component.clear();
- }
-}
-
-static void delete_point_cloud_selection(const PointCloudComponent &in_component,
- PointCloudComponent &out_component,
- const StringRef selection_name,
- const bool invert)
-{
- const VArray<bool> selection_attribute = in_component.attribute_get_for_read<bool>(
- selection_name, ATTR_DOMAIN_POINT, false);
- VArray_Span<bool> selection{selection_attribute};
-
- const int total = selection.count(invert);
- if (total == 0) {
- out_component.clear();
- return;
- }
- out_component.replace(BKE_pointcloud_new_nomain(total));
-
- /* Invert the inversion, because this deletes the selected points instead of keeping them. */
- copy_point_attributes_based_on_mask(in_component, out_component, selection, !invert);
-}
-
-static void compute_selected_vertices_from_vertex_selection(const VArray<bool> &vertex_selection,
- const bool invert,
- MutableSpan<int> r_vertex_map,
- uint *r_num_selected_vertices)
-{
- BLI_assert(vertex_selection.size() == r_vertex_map.size());
-
- uint num_selected_vertices = 0;
- for (const int i : r_vertex_map.index_range()) {
- if (vertex_selection[i] != invert) {
- r_vertex_map[i] = num_selected_vertices;
- num_selected_vertices++;
- }
- else {
- r_vertex_map[i] = -1;
- }
- }
-
- *r_num_selected_vertices = num_selected_vertices;
-}
-
-static void compute_selected_edges_from_vertex_selection(const Mesh &mesh,
- const VArray<bool> &vertex_selection,
- const bool invert,
- MutableSpan<int> r_edge_map,
- uint *r_num_selected_edges)
-{
- BLI_assert(mesh.totedge == r_edge_map.size());
-
- uint num_selected_edges = 0;
- for (const int i : IndexRange(mesh.totedge)) {
- const MEdge &edge = mesh.medge[i];
-
- /* Only add the edge if both vertices will be in the new mesh. */
- if (vertex_selection[edge.v1] != invert && vertex_selection[edge.v2] != invert) {
- r_edge_map[i] = num_selected_edges;
- num_selected_edges++;
- }
- else {
- r_edge_map[i] = -1;
- }
- }
-
- *r_num_selected_edges = num_selected_edges;
-}
-
-static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh,
- const VArray<bool> &vertex_selection,
- const bool invert,
- Vector<int> &r_selected_poly_indices,
- Vector<int> &r_loop_starts,
- uint *r_num_selected_polys,
- uint *r_num_selected_loops)
-{
- BLI_assert(mesh.totvert == vertex_selection.size());
-
- r_selected_poly_indices.reserve(mesh.totpoly);
- r_loop_starts.reserve(mesh.totloop);
-
- uint num_selected_loops = 0;
- for (const int i : IndexRange(mesh.totpoly)) {
- const MPoly &poly_src = mesh.mpoly[i];
-
- bool all_verts_in_selection = true;
- Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
- for (const MLoop &loop : loops_src) {
- if (vertex_selection[loop.v] == invert) {
- all_verts_in_selection = false;
- break;
- }
- }
-
- if (all_verts_in_selection) {
- r_selected_poly_indices.append_unchecked(i);
- r_loop_starts.append_unchecked(num_selected_loops);
- num_selected_loops += poly_src.totloop;
- }
- }
-
- *r_num_selected_polys = r_selected_poly_indices.size();
- *r_num_selected_loops = num_selected_loops;
-}
-
-/**
- * Checks for every edge if it is in `edge_selection`. If it is, then the two vertices of the
- * edge are kept along with the edge.
- */
-static void compute_selected_vertices_and_edges_from_edge_selection(
- const Mesh &mesh,
- const VArray<bool> &edge_selection,
- const bool invert,
- MutableSpan<int> r_vertex_map,
- MutableSpan<int> r_edge_map,
- uint *r_num_selected_vertices,
- uint *r_num_selected_edges)
-{
- BLI_assert(mesh.totedge == edge_selection.size());
-
- uint num_selected_edges = 0;
- uint num_selected_vertices = 0;
- for (const int i : IndexRange(mesh.totedge)) {
- const MEdge &edge = mesh.medge[i];
- if (edge_selection[i] != invert) {
- r_edge_map[i] = num_selected_edges;
- num_selected_edges++;
- if (r_vertex_map[edge.v1] == -1) {
- r_vertex_map[edge.v1] = num_selected_vertices;
- num_selected_vertices++;
- }
- if (r_vertex_map[edge.v2] == -1) {
- r_vertex_map[edge.v2] = num_selected_vertices;
- num_selected_vertices++;
- }
- }
- else {
- r_edge_map[i] = -1;
- }
- }
-
- *r_num_selected_vertices = num_selected_vertices;
- *r_num_selected_edges = num_selected_edges;
-}
-
-/**
- * Checks for every polygon if all the edges are in `edge_selection`. If they are, then that
- * polygon is kept.
- */
-static void compute_selected_polygons_from_edge_selection(const Mesh &mesh,
- const VArray<bool> &edge_selection,
- const bool invert,
- Vector<int> &r_selected_poly_indices,
- Vector<int> &r_loop_starts,
- uint *r_num_selected_polys,
- uint *r_num_selected_loops)
-{
- r_selected_poly_indices.reserve(mesh.totpoly);
- r_loop_starts.reserve(mesh.totloop);
-
- uint num_selected_loops = 0;
- for (const int i : IndexRange(mesh.totpoly)) {
- const MPoly &poly_src = mesh.mpoly[i];
-
- bool all_edges_in_selection = true;
- Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
- for (const MLoop &loop : loops_src) {
- if (edge_selection[loop.e] == invert) {
- all_edges_in_selection = false;
- break;
- }
- }
-
- if (all_edges_in_selection) {
- r_selected_poly_indices.append_unchecked(i);
- r_loop_starts.append_unchecked(num_selected_loops);
- num_selected_loops += poly_src.totloop;
- }
- }
-
- *r_num_selected_polys = r_selected_poly_indices.size();
- *r_num_selected_loops = num_selected_loops;
-}
-
-/**
- * Checks for every vertex if it is in `vertex_selection`. The polygons and edges are kept if all
- * vertices of that polygon or edge are in the selection.
- */
-static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh,
- const VArray<bool> &vertex_selection,
- const bool invert,
- MutableSpan<int> r_vertex_map,
- MutableSpan<int> r_edge_map,
- Vector<int> &r_selected_poly_indices,
- Vector<int> &r_loop_starts,
- uint *r_num_selected_vertices,
- uint *r_num_selected_edges,
- uint *r_num_selected_polys,
- uint *r_num_selected_loops)
-{
- compute_selected_vertices_from_vertex_selection(
- vertex_selection, invert, r_vertex_map, r_num_selected_vertices);
-
- compute_selected_edges_from_vertex_selection(
- mesh, vertex_selection, invert, r_edge_map, r_num_selected_edges);
-
- compute_selected_polygons_from_vertex_selection(mesh,
- vertex_selection,
- invert,
- r_selected_poly_indices,
- r_loop_starts,
- r_num_selected_polys,
- r_num_selected_loops);
-}
-
-/**
- * Checks for every edge if it is in `edge_selection`. If it is, the vertices belonging to
- * that edge are kept as well. The polygons are kept if all edges are in the selection.
- */
-static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh,
- const VArray<bool> &edge_selection,
- const bool invert,
- MutableSpan<int> r_vertex_map,
- MutableSpan<int> r_edge_map,
- Vector<int> &r_selected_poly_indices,
- Vector<int> &r_loop_starts,
- uint *r_num_selected_vertices,
- uint *r_num_selected_edges,
- uint *r_num_selected_polys,
- uint *r_num_selected_loops)
-{
- r_vertex_map.fill(-1);
- compute_selected_vertices_and_edges_from_edge_selection(mesh,
- edge_selection,
- invert,
- r_vertex_map,
- r_edge_map,
- r_num_selected_vertices,
- r_num_selected_edges);
- compute_selected_polygons_from_edge_selection(mesh,
- edge_selection,
- invert,
- r_selected_poly_indices,
- r_loop_starts,
- r_num_selected_polys,
- r_num_selected_loops);
-}
-
-/**
- * Checks for every polygon if it is in `poly_selection`. If it is, the edges and vertices
- * belonging to that polygon are kept as well.
- */
-static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
- const VArray<bool> &poly_selection,
- const bool invert,
- MutableSpan<int> r_vertex_map,
- MutableSpan<int> r_edge_map,
- Vector<int> &r_selected_poly_indices,
- Vector<int> &r_loop_starts,
- uint *r_num_selected_vertices,
- uint *r_num_selected_edges,
- uint *r_num_selected_polys,
- uint *r_num_selected_loops)
-{
- BLI_assert(mesh.totpoly == poly_selection.size());
- BLI_assert(mesh.totedge == r_edge_map.size());
- r_vertex_map.fill(-1);
- r_edge_map.fill(-1);
-
- r_selected_poly_indices.reserve(mesh.totpoly);
- r_loop_starts.reserve(mesh.totloop);
-
- uint num_selected_loops = 0;
- uint num_selected_vertices = 0;
- uint num_selected_edges = 0;
- for (const int i : IndexRange(mesh.totpoly)) {
- const MPoly &poly_src = mesh.mpoly[i];
- /* We keep this one. */
- if (poly_selection[i] != invert) {
- r_selected_poly_indices.append_unchecked(i);
- r_loop_starts.append_unchecked(num_selected_loops);
- num_selected_loops += poly_src.totloop;
-
- /* Add the vertices and the edges. */
- Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
- for (const MLoop &loop : loops_src) {
- /* Check first if it has not yet been added. */
- if (r_vertex_map[loop.v] == -1) {
- r_vertex_map[loop.v] = num_selected_vertices;
- num_selected_vertices++;
- }
- if (r_edge_map[loop.e] == -1) {
- r_edge_map[loop.e] = num_selected_edges;
- num_selected_edges++;
- }
- }
- }
- }
- *r_num_selected_vertices = num_selected_vertices;
- *r_num_selected_edges = num_selected_edges;
- *r_num_selected_polys = r_selected_poly_indices.size();
- *r_num_selected_loops = num_selected_loops;
-}
-
-using FillMapsFunction = void (*)(const Mesh &mesh,
- const VArray<bool> &selection,
- const bool invert,
- MutableSpan<int> r_vertex_map,
- MutableSpan<int> r_edge_map,
- Vector<int> &r_selected_poly_indices,
- Vector<int> &r_loop_starts,
- uint *r_num_selected_vertices,
- uint *r_num_selected_edges,
- uint *r_num_selected_polys,
- uint *r_num_selected_loops);
-
-/**
- * Delete the parts of the mesh that are in the selection. The `fill_maps_function`
- * depends on the selection type: vertices, edges or faces.
- */
-static Mesh *delete_mesh_selection(const Mesh &mesh_in,
- const VArray<bool> &selection,
- const bool invert,
- FillMapsFunction fill_maps_function)
-{
- Array<int> vertex_map(mesh_in.totvert);
- uint num_selected_vertices;
-
- Array<int> edge_map(mesh_in.totedge);
- uint num_selected_edges;
-
- Vector<int> selected_poly_indices;
- Vector<int> new_loop_starts;
- uint num_selected_polys;
- uint num_selected_loops;
-
- /* Fill all the maps based on the selection. We delete everything
- * in the selection instead of keeping it, so we need to invert it. */
- fill_maps_function(mesh_in,
- selection,
- !invert,
- vertex_map,
- edge_map,
- selected_poly_indices,
- new_loop_starts,
- &num_selected_vertices,
- &num_selected_edges,
- &num_selected_polys,
- &num_selected_loops);
-
- Mesh *result = BKE_mesh_new_nomain_from_template(&mesh_in,
- num_selected_vertices,
- num_selected_edges,
- 0,
- num_selected_loops,
- num_selected_polys);
-
- /* Copy the selected parts of the mesh over to the new mesh. */
- copy_masked_vertices_to_new_mesh(mesh_in, *result, vertex_map);
- copy_masked_edges_to_new_mesh(mesh_in, *result, vertex_map, edge_map);
- copy_masked_polys_to_new_mesh(
- mesh_in, *result, vertex_map, edge_map, selected_poly_indices, new_loop_starts);
- BKE_mesh_calc_edges_loose(result);
- /* Tag to recalculate normals later. */
- BKE_mesh_normals_tag_dirty(result);
-
- return result;
-}
-
-static AttributeDomain get_mesh_selection_domain(MeshComponent &component, const StringRef name)
-{
- std::optional<AttributeMetaData> selection_attribute = component.attribute_get_meta_data(name);
- if (!selection_attribute) {
- /* The node will not do anything in this case, but this function must return something. */
- return ATTR_DOMAIN_POINT;
- }
-
- /* Corners can't be deleted separately, so interpolate corner attributes
- * to the face domain. Note that this choice is somewhat arbitrary. */
- if (selection_attribute->domain == ATTR_DOMAIN_CORNER) {
- return ATTR_DOMAIN_FACE;
- }
-
- return selection_attribute->domain;
-}
-
-static void delete_mesh_selection(MeshComponent &component,
- const Mesh &mesh_in,
- const StringRef selection_name,
- const bool invert)
-{
- /* Figure out the best domain to use. */
- const AttributeDomain selection_domain = get_mesh_selection_domain(component, selection_name);
-
- /* This already checks if the attribute exists, and displays a warning in that case. */
- VArray<bool> selection = component.attribute_get_for_read<bool>(
- selection_name, selection_domain, false);
-
- /* Check if there is anything to delete. */
- bool delete_nothing = true;
- for (const int i : selection.index_range()) {
- if (selection[i] != invert) {
- delete_nothing = false;
- break;
- }
- }
- if (delete_nothing) {
- return;
- }
-
- Mesh *mesh_out;
- switch (selection_domain) {
- case ATTR_DOMAIN_POINT:
- mesh_out = delete_mesh_selection(
- mesh_in, selection, invert, compute_selected_mesh_data_from_vertex_selection);
- break;
- case ATTR_DOMAIN_EDGE:
- mesh_out = delete_mesh_selection(
- mesh_in, selection, invert, compute_selected_mesh_data_from_edge_selection);
- break;
- case ATTR_DOMAIN_FACE:
- mesh_out = delete_mesh_selection(
- mesh_in, selection, invert, compute_selected_mesh_data_from_poly_selection);
- break;
- default:
- BLI_assert_unreachable();
- mesh_out = nullptr;
- break;
- }
- component.replace(mesh_out);
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
- 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");
- if (selection_name.empty()) {
- params.set_output("Geometry", std::move(geometry_set));
- return;
- }
-
- GeometrySet out_set(geometry_set);
- if (geometry_set.has<PointCloudComponent>()) {
- delete_point_cloud_selection(*geometry_set.get_component_for_read<PointCloudComponent>(),
- out_set.get_component_for_write<PointCloudComponent>(),
- selection_name,
- invert);
- }
- if (geometry_set.has<MeshComponent>()) {
- delete_mesh_selection(out_set.get_component_for_write<MeshComponent>(),
- *geometry_set.get_mesh_for_read(),
- selection_name,
- invert);
- }
- if (geometry_set.has<CurveComponent>()) {
- delete_curve_selection(*geometry_set.get_component_for_read<CurveComponent>(),
- out_set.get_component_for_write<CurveComponent>(),
- selection_name,
- invert);
- }
-
- params.set_output("Geometry", std::move(out_set));
-}
-
-} // 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);
-
- 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_legacy_edge_split.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc
deleted file mode 100644
index 74fea7cef22..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "DNA_modifier_types.h"
-
-#include "node_geometry_util.hh"
-
-extern "C" {
-Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd);
-}
-
-namespace blender::nodes::node_geo_legacy_edge_split_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::Bool>(N_("Edge Angle")).default_value(true);
- b.add_input<decl::Float>(N_("Angle"))
- .default_value(DEG2RADF(30.0f))
- .min(0.0f)
- .max(DEG2RADF(180.0f))
- .subtype(PROP_ANGLE);
- b.add_input<decl::Bool>(N_("Sharp Edges"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (!geometry_set.has_mesh()) {
- params.set_output("Geometry", std::move(geometry_set));
- return;
- }
-
- const bool use_sharp_flag = params.extract_input<bool>("Sharp Edges");
- const bool use_edge_angle = params.extract_input<bool>("Edge Angle");
-
- if (!use_edge_angle && !use_sharp_flag) {
- params.set_output("Geometry", std::move(geometry_set));
- return;
- }
-
- const float split_angle = params.extract_input<float>("Angle");
- const Mesh *mesh_in = geometry_set.get_mesh_for_read();
-
- /* Use modifier struct to pass arguments to the modifier code. */
- EdgeSplitModifierData emd;
- memset(&emd, 0, sizeof(EdgeSplitModifierData));
- emd.split_angle = split_angle;
- if (use_edge_angle) {
- emd.flags = MOD_EDGESPLIT_FROMANGLE;
- }
- if (use_sharp_flag) {
- emd.flags |= MOD_EDGESPLIT_FROMFLAG;
- }
-
- Mesh *mesh_out = doEdgeSplit(mesh_in, &emd);
- geometry_set.replace_mesh(mesh_out);
-
- params.set_output("Geometry", std::move(geometry_set));
-}
-
-} // 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);
- 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_legacy_material_assign.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc
deleted file mode 100644
index cb5f4044d6f..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "node_geometry_util.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-
-#include "BKE_material.h"
-
-namespace blender::nodes::node_geo_legacy_material_assign_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::Material>(N_("Material")).hide_label(true);
- b.add_input<decl::String>(N_("Selection"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void assign_material_to_faces(Mesh &mesh, const VArray<bool> &face_mask, Material *material)
-{
- int new_material_index = -1;
- for (const int i : IndexRange(mesh.totcol)) {
- Material *other_material = mesh.mat[i];
- if (other_material == material) {
- new_material_index = i;
- break;
- }
- }
- if (new_material_index == -1) {
- /* Append a new material index. */
- new_material_index = mesh.totcol;
- BKE_id_material_eval_assign(&mesh.id, new_material_index + 1, material);
- }
-
- mesh.mpoly = (MPoly *)CustomData_duplicate_referenced_layer(&mesh.pdata, CD_MPOLY, mesh.totpoly);
- for (const int i : IndexRange(mesh.totpoly)) {
- if (face_mask[i]) {
- MPoly &poly = mesh.mpoly[i];
- poly.mat_nr = new_material_index;
- }
- }
-}
-
-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::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- Mesh *mesh = mesh_component.get_for_write();
- if (mesh != nullptr) {
- VArray<bool> face_mask = mesh_component.attribute_get_for_read<bool>(
- mask_name, ATTR_DOMAIN_FACE, true);
- assign_material_to_faces(*mesh, face_mask, material);
- }
- }
-
- params.set_output("Geometry", std::move(geometry_set));
-}
-
-} // 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);
- 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_legacy_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
deleted file mode 100644
index 72cb540df4a..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "GEO_mesh_to_curve.hh"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc {
-
-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 node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (!geometry_set.has_mesh()) {
- params.set_default_remaining_outputs();
- return;
- }
-
- const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
- const std::string selection_name = params.extract_input<std::string>("Selection");
- if (!selection_name.empty() && !component.attribute_exists(selection_name)) {
- params.error_message_add(NodeWarningType::Error,
- TIP_("No attribute with name \"") + selection_name + "\"");
- }
- VArray<bool> selection = component.attribute_get_for_read<bool>(
- selection_name, ATTR_DOMAIN_EDGE, true);
-
- Vector<int64_t> selected_edge_indices;
- for (const int64_t i : IndexRange(component.attribute_domain_size(ATTR_DOMAIN_EDGE))) {
- if (selection[i]) {
- selected_edge_indices.append(i);
- }
- }
-
- if (selected_edge_indices.size() == 0) {
- params.set_default_remaining_outputs();
- return;
- }
-
- Curves *curves = geometry::mesh_to_curve_convert(component, IndexMask(selected_edge_indices));
- params.set_output("Curve", GeometrySet::create_with_curves(curves));
-}
-
-} // 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);
- 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_legacy_point_distribute.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc
deleted file mode 100644
index f7cd0624b53..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc
+++ /dev/null
@@ -1,657 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_hash.h"
-#include "BLI_kdtree.h"
-#include "BLI_rand.hh"
-#include "BLI_timeit.hh"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_pointcloud_types.h"
-
-#include "BKE_attribute_math.hh"
-#include "BKE_bvhutils.h"
-#include "BKE_geometry_set_instances.hh"
-#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
-#include "BKE_mesh_sample.hh"
-#include "BKE_pointcloud.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_point_distribute_cc {
-
-using blender::bke::GeometryInstanceGroup;
-
-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);
- b.add_input<decl::Float>(N_("Density Max"))
- .default_value(1.0f)
- .min(0.0f)
- .max(100000.0f)
- .subtype(PROP_NONE);
- b.add_input<decl::String>(N_("Density Attribute"));
- b.add_input<decl::Int>(N_("Seed")).min(-10000).max(10000);
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE);
-}
-
-static void node_point_distribute_update(bNodeTree *ntree, bNode *node)
-{
- bNodeSocket *sock_min_dist = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
-
- nodeSetSocketAvailability(
- ntree, sock_min_dist, ELEM(node->custom1, GEO_NODE_POINT_DISTRIBUTE_POISSON));
-}
-
-/**
- * Use an arbitrary choice of axes for a usable rotation attribute directly out of this node.
- */
-static float3 normal_to_euler_rotation(const float3 normal)
-{
- float quat[4];
- vec_to_quat(quat, normal, OB_NEGZ, OB_POSY);
- float3 rotation;
- quat_to_eul(rotation, quat);
- return rotation;
-}
-
-static void sample_mesh_surface(const Mesh &mesh,
- const float4x4 &transform,
- const float base_density,
- const VArray<float> *density_factors,
- const int seed,
- Vector<float3> &r_positions,
- Vector<float3> &r_bary_coords,
- Vector<int> &r_looptri_indices)
-{
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
- BKE_mesh_runtime_looptri_len(&mesh)};
-
- for (const int looptri_index : looptris.index_range()) {
- const MLoopTri &looptri = looptris[looptri_index];
- const int v0_loop = looptri.tri[0];
- const int v1_loop = looptri.tri[1];
- const int v2_loop = looptri.tri[2];
- const int v0_index = mesh.mloop[v0_loop].v;
- const int v1_index = mesh.mloop[v1_loop].v;
- const int v2_index = mesh.mloop[v2_loop].v;
- const float3 v0_pos = transform * float3(mesh.mvert[v0_index].co);
- const float3 v1_pos = transform * float3(mesh.mvert[v1_index].co);
- const float3 v2_pos = transform * float3(mesh.mvert[v2_index].co);
-
- float looptri_density_factor = 1.0f;
- if (density_factors != nullptr) {
- const float v0_density_factor = std::max(0.0f, (*density_factors)[v0_loop]);
- const float v1_density_factor = std::max(0.0f, (*density_factors)[v1_loop]);
- const float v2_density_factor = std::max(0.0f, (*density_factors)[v2_loop]);
- looptri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) / 3.0f;
- }
- const float area = area_tri_v3(v0_pos, v1_pos, v2_pos);
-
- const int looptri_seed = BLI_hash_int(looptri_index + seed);
- RandomNumberGenerator looptri_rng(looptri_seed);
-
- const float points_amount_fl = area * base_density * looptri_density_factor;
- const float add_point_probability = fractf(points_amount_fl);
- const bool add_point = add_point_probability > looptri_rng.get_float();
- const int point_amount = (int)points_amount_fl + (int)add_point;
-
- for (int i = 0; i < point_amount; i++) {
- const float3 bary_coord = looptri_rng.get_barycentric_coordinates();
- float3 point_pos;
- interp_v3_v3v3v3(point_pos, v0_pos, v1_pos, v2_pos, bary_coord);
- r_positions.append(point_pos);
- r_bary_coords.append(bary_coord);
- r_looptri_indices.append(looptri_index);
- }
- }
-}
-
-BLI_NOINLINE static KDTree_3d *build_kdtree(Span<Vector<float3>> positions_all,
- const int initial_points_len)
-{
- KDTree_3d *kdtree = BLI_kdtree_3d_new(initial_points_len);
-
- int i_point = 0;
- for (const Vector<float3> &positions : positions_all) {
- for (const float3 position : positions) {
- BLI_kdtree_3d_insert(kdtree, i_point, position);
- i_point++;
- }
- }
- BLI_kdtree_3d_balance(kdtree);
- return kdtree;
-}
-
-BLI_NOINLINE static void update_elimination_mask_for_close_points(
- Span<Vector<float3>> positions_all,
- Span<int> instance_start_offsets,
- const float minimum_distance,
- MutableSpan<bool> elimination_mask,
- const int initial_points_len)
-{
- if (minimum_distance <= 0.0f) {
- return;
- }
-
- KDTree_3d *kdtree = build_kdtree(positions_all, initial_points_len);
-
- /* The elimination mask is a flattened array for every point,
- * so keep track of the index to it separately. */
- for (const int i_instance : positions_all.index_range()) {
- Span<float3> positions = positions_all[i_instance];
- const int offset = instance_start_offsets[i_instance];
-
- for (const int i : positions.index_range()) {
- if (elimination_mask[offset + i]) {
- continue;
- }
-
- struct CallbackData {
- int index;
- MutableSpan<bool> elimination_mask;
- } callback_data = {offset + i, elimination_mask};
-
- BLI_kdtree_3d_range_search_cb(
- kdtree,
- positions[i],
- minimum_distance,
- [](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) {
- CallbackData &callback_data = *static_cast<CallbackData *>(user_data);
- if (index != callback_data.index) {
- callback_data.elimination_mask[index] = true;
- }
- return true;
- },
- &callback_data);
- }
- }
- BLI_kdtree_3d_free(kdtree);
-}
-
-BLI_NOINLINE static void update_elimination_mask_based_on_density_factors(
- const Mesh &mesh,
- const VArray<float> &density_factors,
- Span<float3> bary_coords,
- Span<int> looptri_indices,
- MutableSpan<bool> elimination_mask)
-{
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
- BKE_mesh_runtime_looptri_len(&mesh)};
- for (const int i : bary_coords.index_range()) {
- if (elimination_mask[i]) {
- continue;
- }
-
- const MLoopTri &looptri = looptris[looptri_indices[i]];
- const float3 bary_coord = bary_coords[i];
-
- const int v0_loop = looptri.tri[0];
- const int v1_loop = looptri.tri[1];
- const int v2_loop = looptri.tri[2];
-
- const float v0_density_factor = std::max(0.0f, density_factors[v0_loop]);
- const float v1_density_factor = std::max(0.0f, density_factors[v1_loop]);
- const float v2_density_factor = std::max(0.0f, density_factors[v2_loop]);
-
- const float probablity = v0_density_factor * bary_coord.x + v1_density_factor * bary_coord.y +
- v2_density_factor * bary_coord.z;
-
- const float hash = BLI_hash_int_01(bary_coord.hash());
- if (hash > probablity) {
- elimination_mask[i] = true;
- }
- }
-}
-
-BLI_NOINLINE static void eliminate_points_based_on_mask(Span<bool> elimination_mask,
- Vector<float3> &positions,
- Vector<float3> &bary_coords,
- Vector<int> &looptri_indices)
-{
- for (int i = positions.size() - 1; i >= 0; i--) {
- if (elimination_mask[i]) {
- positions.remove_and_reorder(i);
- bary_coords.remove_and_reorder(i);
- looptri_indices.remove_and_reorder(i);
- }
- }
-}
-
-BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
- Span<float3> bary_coords,
- Span<int> looptri_indices,
- const AttributeDomain source_domain,
- const GVArray &source_data,
- GMutableSpan output_data)
-{
- switch (source_domain) {
- case ATTR_DOMAIN_POINT: {
- bke::mesh_surface_sample::sample_point_attribute(mesh,
- looptri_indices,
- bary_coords,
- source_data,
- IndexMask(output_data.size()),
- output_data);
- break;
- }
- case ATTR_DOMAIN_CORNER: {
- bke::mesh_surface_sample::sample_corner_attribute(mesh,
- looptri_indices,
- bary_coords,
- source_data,
- IndexMask(output_data.size()),
- output_data);
- break;
- }
- case ATTR_DOMAIN_FACE: {
- bke::mesh_surface_sample::sample_face_attribute(
- mesh, looptri_indices, source_data, IndexMask(output_data.size()), output_data);
- break;
- }
- default: {
- /* Not supported currently. */
- return;
- }
- }
-}
-
-BLI_NOINLINE static void interpolate_existing_attributes(
- Span<GeometryInstanceGroup> set_groups,
- Span<int> instance_start_offsets,
- const Map<AttributeIDRef, AttributeKind> &attributes,
- GeometryComponent &component,
- Span<Vector<float3>> bary_coords_array,
- Span<Vector<int>> looptri_indices_array)
-{
- for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) {
- const AttributeIDRef attribute_id = entry.key;
- const CustomDataType output_data_type = entry.value.data_type;
- /* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
- OutputAttribute attribute_out = component.attribute_try_get_for_output_only(
- attribute_id, ATTR_DOMAIN_POINT, output_data_type);
- if (!attribute_out) {
- continue;
- }
-
- GMutableSpan out_span = attribute_out.as_span();
-
- int i_instance = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- const MeshComponent &source_component = *set.get_component_for_read<MeshComponent>();
- const Mesh &mesh = *source_component.get_for_read();
-
- std::optional<AttributeMetaData> attribute_info = component.attribute_get_meta_data(
- attribute_id);
- if (!attribute_info) {
- i_instance += set_group.transforms.size();
- continue;
- }
-
- const AttributeDomain source_domain = attribute_info->domain;
- GVArray source_attribute = source_component.attribute_get_for_read(
- attribute_id, source_domain, output_data_type, nullptr);
- if (!source_attribute) {
- i_instance += set_group.transforms.size();
- continue;
- }
-
- for ([[maybe_unused]] const int i_set_instance : set_group.transforms.index_range()) {
- const int offset = instance_start_offsets[i_instance];
- Span<float3> bary_coords = bary_coords_array[i_instance];
- Span<int> looptri_indices = looptri_indices_array[i_instance];
-
- GMutableSpan instance_span = out_span.slice(offset, bary_coords.size());
- interpolate_attribute(
- mesh, bary_coords, looptri_indices, source_domain, source_attribute, instance_span);
-
- i_instance++;
- }
-
- attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) {
- using T = decltype(dummy);
-
- VArray_Span source_span{source_attribute.typed<T>()};
- });
- }
-
- attribute_out.save();
- }
-}
-
-BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup> sets,
- Span<int> instance_start_offsets,
- GeometryComponent &component,
- Span<Vector<float3>> bary_coords_array,
- Span<Vector<int>> looptri_indices_array)
-{
- OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
- "id", ATTR_DOMAIN_POINT);
- OutputAttribute_Typed<float3> normal_attribute =
- component.attribute_try_get_for_output_only<float3>("normal", ATTR_DOMAIN_POINT);
- OutputAttribute_Typed<float3> rotation_attribute =
- component.attribute_try_get_for_output_only<float3>("rotation", ATTR_DOMAIN_POINT);
-
- MutableSpan<int> result_ids = id_attribute.as_span();
- MutableSpan<float3> result_normals = normal_attribute.as_span();
- MutableSpan<float3> result_rotations = rotation_attribute.as_span();
-
- int i_instance = 0;
- for (const GeometryInstanceGroup &set_group : sets) {
- const GeometrySet &set = set_group.geometry_set;
- const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
- const Mesh &mesh = *component.get_for_read();
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
- BKE_mesh_runtime_looptri_len(&mesh)};
-
- for (const float4x4 &transform : set_group.transforms) {
- const int offset = instance_start_offsets[i_instance];
-
- Span<float3> bary_coords = bary_coords_array[i_instance];
- Span<int> looptri_indices = looptri_indices_array[i_instance];
- MutableSpan<int> ids = result_ids.slice(offset, bary_coords.size());
- MutableSpan<float3> normals = result_normals.slice(offset, bary_coords.size());
- MutableSpan<float3> rotations = result_rotations.slice(offset, bary_coords.size());
-
- /* Use one matrix multiplication per point instead of three (for each triangle corner). */
- float rotation_matrix[3][3];
- mat4_to_rot(rotation_matrix, transform.values);
-
- for (const int i : bary_coords.index_range()) {
- const int looptri_index = looptri_indices[i];
- const MLoopTri &looptri = looptris[looptri_index];
- const float3 &bary_coord = bary_coords[i];
-
- const int v0_index = mesh.mloop[looptri.tri[0]].v;
- const int v1_index = mesh.mloop[looptri.tri[1]].v;
- const int v2_index = mesh.mloop[looptri.tri[2]].v;
- const float3 v0_pos = float3(mesh.mvert[v0_index].co);
- const float3 v1_pos = float3(mesh.mvert[v1_index].co);
- const float3 v2_pos = float3(mesh.mvert[v2_index].co);
-
- ids[i] = (int)(bary_coord.hash() + (uint64_t)looptri_index);
- normal_tri_v3(normals[i], v0_pos, v1_pos, v2_pos);
- mul_m3_v3(rotation_matrix, normals[i]);
- rotations[i] = normal_to_euler_rotation(normals[i]);
- }
-
- i_instance++;
- }
- }
-
- id_attribute.save();
- normal_attribute.save();
- rotation_attribute.save();
-}
-
-BLI_NOINLINE static void add_remaining_point_attributes(
- Span<GeometryInstanceGroup> set_groups,
- Span<int> instance_start_offsets,
- const Map<AttributeIDRef, AttributeKind> &attributes,
- GeometryComponent &component,
- Span<Vector<float3>> bary_coords_array,
- Span<Vector<int>> looptri_indices_array)
-{
- interpolate_existing_attributes(set_groups,
- instance_start_offsets,
- attributes,
- component,
- bary_coords_array,
- looptri_indices_array);
- compute_special_attributes(
- set_groups, instance_start_offsets, component, bary_coords_array, looptri_indices_array);
-}
-
-static void distribute_points_random(Span<GeometryInstanceGroup> set_groups,
- const StringRef density_attribute_name,
- const float density,
- const int seed,
- MutableSpan<Vector<float3>> positions_all,
- MutableSpan<Vector<float3>> bary_coords_all,
- MutableSpan<Vector<int>> looptri_indices_all)
-{
- /* If there is an attribute name, the default value for the densities should be zero so that
- * points are only scattered where the attribute exists. Otherwise, just "ignore" the density
- * factors. */
- const bool use_one_default = density_attribute_name.is_empty();
-
- int i_instance = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
- VArray<float> density_factors = component.attribute_get_for_read<float>(
- density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
- const Mesh &mesh = *component.get_for_read();
- for (const float4x4 &transform : set_group.transforms) {
- Vector<float3> &positions = positions_all[i_instance];
- Vector<float3> &bary_coords = bary_coords_all[i_instance];
- Vector<int> &looptri_indices = looptri_indices_all[i_instance];
- sample_mesh_surface(mesh,
- transform,
- density,
- &density_factors,
- seed,
- positions,
- bary_coords,
- looptri_indices);
- i_instance++;
- }
- }
-}
-
-static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_groups,
- const StringRef density_attribute_name,
- const float density,
- const int seed,
- const float minimum_distance,
- MutableSpan<Vector<float3>> positions_all,
- MutableSpan<Vector<float3>> bary_coords_all,
- MutableSpan<Vector<int>> looptri_indices_all)
-{
- Array<int> instance_start_offsets(positions_all.size());
- int initial_points_len = 0;
- int i_instance = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
- const Mesh &mesh = *component.get_for_read();
- for (const float4x4 &transform : set_group.transforms) {
- Vector<float3> &positions = positions_all[i_instance];
- Vector<float3> &bary_coords = bary_coords_all[i_instance];
- Vector<int> &looptri_indices = looptri_indices_all[i_instance];
- sample_mesh_surface(
- mesh, transform, density, nullptr, seed, positions, bary_coords, looptri_indices);
-
- instance_start_offsets[i_instance] = initial_points_len;
- initial_points_len += positions.size();
- i_instance++;
- }
- }
-
- /* If there is an attribute name, the default value for the densities should be zero so that
- * points are only scattered where the attribute exists. Otherwise, just "ignore" the density
- * factors. */
- const bool use_one_default = density_attribute_name.is_empty();
-
- /* Unlike the other result arrays, the elimination mask in stored as a flat array for every
- * point, in order to simplify culling points from the KDTree (which needs to know about all
- * points at once). */
- Array<bool> elimination_mask(initial_points_len, false);
- update_elimination_mask_for_close_points(positions_all,
- instance_start_offsets,
- minimum_distance,
- elimination_mask,
- initial_points_len);
-
- i_instance = 0;
- for (const GeometryInstanceGroup &set_group : set_groups) {
- const GeometrySet &set = set_group.geometry_set;
- const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
- const Mesh &mesh = *component.get_for_read();
- const VArray<float> density_factors = component.attribute_get_for_read<float>(
- density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
-
- for ([[maybe_unused]] const int i_set_instance : set_group.transforms.index_range()) {
- Vector<float3> &positions = positions_all[i_instance];
- Vector<float3> &bary_coords = bary_coords_all[i_instance];
- Vector<int> &looptri_indices = looptri_indices_all[i_instance];
-
- const int offset = instance_start_offsets[i_instance];
- update_elimination_mask_based_on_density_factors(
- mesh,
- density_factors,
- bary_coords,
- looptri_indices,
- elimination_mask.as_mutable_span().slice(offset, positions.size()));
-
- eliminate_points_based_on_mask(elimination_mask.as_span().slice(offset, positions.size()),
- positions,
- bary_coords,
- looptri_indices);
-
- i_instance++;
- }
- }
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- const GeometryNodePointDistributeMode distribute_method =
- static_cast<GeometryNodePointDistributeMode>(params.node().custom1);
-
- const int seed = params.get_input<int>("Seed") * 5383843;
- const float density = params.extract_input<float>("Density Max");
- const std::string density_attribute_name = params.extract_input<std::string>(
- "Density Attribute");
-
- if (density <= 0.0f) {
- 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_default_remaining_outputs();
- return;
- }
-
- /* Remove any set inputs that don't contain a mesh, to avoid checking later on. */
- for (int i = set_groups.size() - 1; i >= 0; i--) {
- const GeometrySet &set = set_groups[i].geometry_set;
- if (!set.has_mesh()) {
- set_groups.remove_and_reorder(i);
- }
- }
-
- if (set_groups.is_empty()) {
- params.error_message_add(NodeWarningType::Error, TIP_("Input geometry must contain a mesh"));
- params.set_default_remaining_outputs();
- return;
- }
-
- int instances_len = 0;
- for (GeometryInstanceGroup &set_group : set_groups) {
- instances_len += set_group.transforms.size();
- }
-
- /* Store data per-instance in order to simplify attribute access after the scattering,
- * and to make the point elimination simpler for the poisson disk mode. Note that some
- * vectors will be empty if any instances don't contain mesh data. */
- Array<Vector<float3>> positions_all(instances_len);
- Array<Vector<float3>> bary_coords_all(instances_len);
- Array<Vector<int>> looptri_indices_all(instances_len);
-
- switch (distribute_method) {
- case GEO_NODE_POINT_DISTRIBUTE_RANDOM: {
- distribute_points_random(set_groups,
- density_attribute_name,
- density,
- seed,
- positions_all,
- bary_coords_all,
- looptri_indices_all);
- break;
- }
- case GEO_NODE_POINT_DISTRIBUTE_POISSON: {
- const float minimum_distance = params.extract_input<float>("Distance Min");
- distribute_points_poisson_disk(set_groups,
- density_attribute_name,
- density,
- seed,
- minimum_distance,
- positions_all,
- bary_coords_all,
- looptri_indices_all);
- break;
- }
- }
-
- int final_points_len = 0;
- Array<int> instance_start_offsets(set_groups.size());
- for (const int i : positions_all.index_range()) {
- Vector<float3> &positions = positions_all[i];
- instance_start_offsets[i] = final_points_len;
- final_points_len += positions.size();
- }
-
- if (final_points_len == 0) {
- params.set_default_remaining_outputs();
- return;
- }
-
- PointCloud *pointcloud = BKE_pointcloud_new_nomain(final_points_len);
- for (const int instance_index : positions_all.index_range()) {
- const int offset = instance_start_offsets[instance_index];
- Span<float3> positions = positions_all[instance_index];
- memcpy(pointcloud->co + offset, positions.data(), sizeof(float3) * positions.size());
- }
-
- uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f);
-
- GeometrySet geometry_set_out = GeometrySet::create_with_pointcloud(pointcloud);
- PointCloudComponent &point_component =
- geometry_set_out.get_component_for_write<PointCloudComponent>();
-
- Map<AttributeIDRef, AttributeKind> attributes;
- bke::geometry_set_gather_instances_attribute_info(
- set_groups, {GEO_COMPONENT_TYPE_MESH}, {"position", "normal", "id"}, attributes);
- add_remaining_point_attributes(set_groups,
- instance_start_offsets,
- attributes,
- point_component,
- bary_coords_all,
- looptri_indices_all);
-
- params.set_output("Geometry", std::move(geometry_set_out));
-}
-
-} // 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);
- 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_legacy_point_instance.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc
deleted file mode 100644
index 3d31773300d..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc
+++ /dev/null
@@ -1,268 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "DNA_collection_types.h"
-
-#include "BLI_hash.h"
-#include "BLI_task.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_point_instance_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::Object>(N_("Object")).hide_label();
- b.add_input<decl::Collection>(N_("Collection")).hide_label();
- b.add_input<decl::Geometry>(N_("Instance Geometry"));
- b.add_input<decl::Int>(N_("Seed")).min(-10000).max(10000);
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-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) {
- uiItemR(layout, ptr, "use_whole_collection", 0, nullptr, ICON_NONE);
- }
-}
-
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeGeometryPointInstance *data = MEM_cnew<NodeGeometryPointInstance>(__func__);
- data->instance_type = GEO_NODE_POINT_INSTANCE_TYPE_OBJECT;
- data->flag |= GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION;
- node->storage = data;
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- bNodeSocket *object_socket = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
- bNodeSocket *collection_socket = object_socket->next;
- bNodeSocket *instance_geometry_socket = collection_socket->next;
- bNodeSocket *seed_socket = instance_geometry_socket->next;
-
- NodeGeometryPointInstance *node_storage = (NodeGeometryPointInstance *)node->storage;
- GeometryNodePointInstanceType type = (GeometryNodePointInstanceType)node_storage->instance_type;
- const bool use_whole_collection = (node_storage->flag &
- GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION) != 0;
-
- nodeSetSocketAvailability(ntree, object_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_OBJECT);
- nodeSetSocketAvailability(
- ntree, collection_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION);
- nodeSetSocketAvailability(
- ntree, instance_geometry_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY);
- nodeSetSocketAvailability(ntree,
- seed_socket,
- type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION &&
- !use_whole_collection);
-}
-
-static Vector<InstanceReference> get_instance_references__object(GeoNodeExecParams &params)
-{
- Object *object = params.extract_input<Object *>("Object");
- if (object == params.self_object()) {
- return {};
- }
- if (object != nullptr) {
- return {*object};
- }
- return {};
-}
-
-static Vector<InstanceReference> get_instance_references__collection(GeoNodeExecParams &params)
-{
- const bNode &node = params.node();
- NodeGeometryPointInstance *node_storage = (NodeGeometryPointInstance *)node.storage;
-
- Collection *collection = params.get_input<Collection *>("Collection");
- if (collection == nullptr) {
- return {};
- }
-
- if (BLI_listbase_is_empty(&collection->children) &&
- BLI_listbase_is_empty(&collection->gobject)) {
- params.error_message_add(NodeWarningType::Info, TIP_("Collection is empty"));
- return {};
- }
-
- if (node_storage->flag & GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION) {
- return {*collection};
- }
-
- Vector<InstanceReference> references;
- /* Direct child objects are instanced as objects. */
- LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
- references.append(*cob->ob);
- }
- /* Direct child collections are instanced as collections. */
- LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
- references.append(*child->collection);
- }
-
- return references;
-}
-
-static Vector<InstanceReference> get_instance_references__geometry(GeoNodeExecParams &params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Instance Geometry");
- geometry_set.ensure_owns_direct_data();
- return {std::move(geometry_set)};
-}
-
-static Vector<InstanceReference> get_instance_references(GeoNodeExecParams &params)
-{
- const bNode &node = params.node();
- NodeGeometryPointInstance *node_storage = (NodeGeometryPointInstance *)node.storage;
- const GeometryNodePointInstanceType type = (GeometryNodePointInstanceType)
- node_storage->instance_type;
-
- switch (type) {
- case GEO_NODE_POINT_INSTANCE_TYPE_OBJECT: {
- return get_instance_references__object(params);
- }
- case GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION: {
- return get_instance_references__collection(params);
- }
- case GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY: {
- return get_instance_references__geometry(params);
- }
- }
- return {};
-}
-
-/**
- * Add the instance references to the component as a separate step from actually creating the
- * instances in order to avoid a map lookup for every transform. While this might add some
- * unnecessary references if they are not chosen while adding transforms, in the common cases
- * there are many more transforms than there are references, so that isn't likely.
- */
-static Array<int> add_instance_references(InstancesComponent &instance_component,
- Span<InstanceReference> possible_references)
-{
- Array<int> possible_handles(possible_references.size());
- for (const int i : possible_references.index_range()) {
- possible_handles[i] = instance_component.add_reference(possible_references[i]);
- }
- return possible_handles;
-}
-
-static void add_instances_from_component(InstancesComponent &instances,
- const GeometryComponent &src_geometry,
- Span<int> possible_handles,
- const GeoNodeExecParams &params)
-{
- 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});
- VArray<float3> rotations = src_geometry.attribute_get_for_read<float3>(
- "rotation", domain, {0, 0, 0});
- VArray<float3> scales = src_geometry.attribute_get_for_read<float3>("scale", domain, {1, 1, 1});
- VArray<int> id_attribute = src_geometry.attribute_get_for_read<int>("id", domain, -1);
-
- /* The initial size of the component might be non-zero if there are two component types. */
- const int start_len = instances.instances_amount();
- 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);
- 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). */
- if (possible_handles.size() == 1) {
- const int handle = possible_handles.first();
- threading::parallel_for(IndexRange(domain_size), 1024, [&](IndexRange range) {
- for (const int i : range) {
- handles[i] = handle;
- transforms[i] = float4x4::from_loc_eul_scale(positions[i], rotations[i], scales[i]);
- instance_ids[i] = id_attribute[i];
- }
- });
- }
- else {
- const int seed = params.get_input<int>("Seed");
- Array<uint32_t> ids = get_geometry_element_ids_as_uints(src_geometry, ATTR_DOMAIN_POINT);
- threading::parallel_for(IndexRange(domain_size), 1024, [&](IndexRange range) {
- for (const int i : range) {
- const int index = BLI_hash_int_2d(ids[i], seed) % possible_handles.size();
- const int handle = possible_handles[index];
- handles[i] = handle;
- transforms[i] = float4x4::from_loc_eul_scale(positions[i], rotations[i], scales[i]);
- instance_ids[i] = id_attribute[i];
- }
- });
- }
-
- instance_id_attribute.save();
-}
-
-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::realize_instances_legacy(geometry_set);
-
- const Vector<InstanceReference> possible_references = get_instance_references(params);
- if (possible_references.is_empty()) {
- params.set_output("Geometry", std::move(geometry_set_out));
- return;
- }
-
- InstancesComponent &instances = geometry_set_out.get_component_for_write<InstancesComponent>();
- Array<int> possible_handles = add_instance_references(instances, possible_references);
-
- if (geometry_set.has<MeshComponent>()) {
- add_instances_from_component(instances,
- *geometry_set.get_component_for_read<MeshComponent>(),
- possible_handles,
- params);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- add_instances_from_component(instances,
- *geometry_set.get_component_for_read<PointCloudComponent>(),
- possible_handles,
- params);
- }
- if (geometry_set.has<CurveComponent>()) {
- add_instances_from_component(instances,
- *geometry_set.get_component_for_read<CurveComponent>(),
- possible_handles,
- params);
- }
-
- params.set_output("Geometry", std::move(geometry_set_out));
-}
-
-} // 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);
- node_type_init(&ntype, file_ns::node_init);
- node_type_storage(
- &ntype, "NodeGeometryPointInstance", node_free_standard_storage, node_copy_standard_storage);
- 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_legacy_point_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc
deleted file mode 100644
index 2895c15cb8c..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc
+++ /dev/null
@@ -1,223 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_math_rotation.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_point_rotate_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Axis"));
- b.add_input<decl::Vector>(N_("Axis"), "Axis_001")
- .default_value({0.0, 0.0, 1.0})
- .subtype(PROP_XYZ);
- b.add_input<decl::String>(N_("Angle"));
- b.add_input<decl::Float>(N_("Angle"), "Angle_001").subtype(PROP_ANGLE);
- b.add_input<decl::String>(N_("Rotation"));
- b.add_input<decl::Vector>(N_("Rotation"), "Rotation_001").subtype(PROP_EULER);
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- NodeGeometryRotatePoints *storage = (NodeGeometryRotatePoints *)((bNode *)ptr->data)->storage;
-
- uiItemR(layout, ptr, "type", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
-
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
-
- uiLayout *col = uiLayoutColumn(layout, false);
- if (storage->type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE) {
- uiItemR(col, ptr, "input_type_axis", 0, IFACE_("Axis"), ICON_NONE);
- uiItemR(col, ptr, "input_type_angle", 0, IFACE_("Angle"), ICON_NONE);
- }
- else {
- uiItemR(col, ptr, "input_type_rotation", 0, IFACE_("Rotation"), ICON_NONE);
- }
-}
-
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeGeometryRotatePoints *node_storage = MEM_cnew<NodeGeometryRotatePoints>(__func__);
-
- node_storage->type = GEO_NODE_POINT_ROTATE_TYPE_EULER;
- node_storage->space = GEO_NODE_POINT_ROTATE_SPACE_OBJECT;
- node_storage->input_type_axis = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
- node_storage->input_type_angle = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
- node_storage->input_type_rotation = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
-
- node->storage = node_storage;
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)node->storage;
- update_attribute_input_socket_availabilities(
- *ntree,
- *node,
- "Axis",
- (GeometryNodeAttributeInputMode)node_storage->input_type_axis,
- node_storage->type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE);
- update_attribute_input_socket_availabilities(
- *ntree,
- *node,
- "Angle",
- (GeometryNodeAttributeInputMode)node_storage->input_type_angle,
- node_storage->type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE);
- update_attribute_input_socket_availabilities(
- *ntree,
- *node,
- "Rotation",
- (GeometryNodeAttributeInputMode)node_storage->input_type_rotation,
- node_storage->type == GEO_NODE_POINT_ROTATE_TYPE_EULER);
-}
-
-static void point_rotate__axis_angle__object_space(const int domain_size,
- const VArray<float3> &axis,
- const VArray<float> &angles,
- MutableSpan<float3> rotations)
-{
- for (const int i : IndexRange(domain_size)) {
- float old_rotation[3][3];
- eul_to_mat3(old_rotation, rotations[i]);
- float rotation[3][3];
- axis_angle_to_mat3(rotation, axis[i], angles[i]);
- float new_rotation[3][3];
- mul_m3_m3m3(new_rotation, rotation, old_rotation);
- mat3_to_eul(rotations[i], new_rotation);
- }
-}
-
-static void point_rotate__axis_angle__point_space(const int domain_size,
- const VArray<float3> &axis,
- const VArray<float> &angles,
- MutableSpan<float3> rotations)
-{
- for (const int i : IndexRange(domain_size)) {
- float old_rotation[3][3];
- eul_to_mat3(old_rotation, rotations[i]);
- float rotation[3][3];
- axis_angle_to_mat3(rotation, axis[i], angles[i]);
- float new_rotation[3][3];
- mul_m3_m3m3(new_rotation, old_rotation, rotation);
- mat3_to_eul(rotations[i], new_rotation);
- }
-}
-
-static void point_rotate__euler__object_space(const int domain_size,
- const VArray<float3> &eulers,
- MutableSpan<float3> rotations)
-{
- for (const int i : IndexRange(domain_size)) {
- float old_rotation[3][3];
- eul_to_mat3(old_rotation, rotations[i]);
- float rotation[3][3];
- eul_to_mat3(rotation, eulers[i]);
- float new_rotation[3][3];
- mul_m3_m3m3(new_rotation, rotation, old_rotation);
- mat3_to_eul(rotations[i], new_rotation);
- }
-}
-
-static void point_rotate__euler__point_space(const int domain_size,
- const VArray<float3> &eulers,
- MutableSpan<float3> rotations)
-{
- for (const int i : IndexRange(domain_size)) {
- float old_rotation[3][3];
- eul_to_mat3(old_rotation, rotations[i]);
- float rotation[3][3];
- eul_to_mat3(rotation, eulers[i]);
- float new_rotation[3][3];
- mul_m3_m3m3(new_rotation, old_rotation, rotation);
- mat3_to_eul(rotations[i], new_rotation);
- }
-}
-
-static void point_rotate_on_component(GeometryComponent &component,
- const GeoNodeExecParams &params)
-{
- const bNode &node = params.node();
- const NodeGeometryRotatePoints &storage = *(const NodeGeometryRotatePoints *)node.storage;
-
- OutputAttribute_Typed<float3> rotation_attribute =
- component.attribute_try_get_for_output<float3>("rotation", ATTR_DOMAIN_POINT, {0, 0, 0});
- if (!rotation_attribute) {
- return;
- }
-
- MutableSpan<float3> rotations = rotation_attribute.as_span();
- const int domain_size = rotations.size();
-
- if (storage.type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE) {
- VArray<float3> axis = params.get_input_attribute<float3>(
- "Axis", component, ATTR_DOMAIN_POINT, {0, 0, 1});
- VArray<float> angles = params.get_input_attribute<float>(
- "Angle", component, ATTR_DOMAIN_POINT, 0);
-
- if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) {
- point_rotate__axis_angle__object_space(domain_size, axis, angles, rotations);
- }
- else {
- point_rotate__axis_angle__point_space(domain_size, axis, angles, rotations);
- }
- }
- else {
- VArray<float3> eulers = params.get_input_attribute<float3>(
- "Rotation", component, ATTR_DOMAIN_POINT, {0, 0, 0});
-
- if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) {
- point_rotate__euler__object_space(domain_size, eulers, rotations);
- }
- else {
- point_rotate__euler__point_space(domain_size, eulers, rotations);
- }
- }
-
- rotation_attribute.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- 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);
- }
- if (geometry_set.has<PointCloudComponent>()) {
- point_rotate_on_component(geometry_set.get_component_for_write<PointCloudComponent>(), params);
- }
- if (geometry_set.has<CurveComponent>()) {
- point_rotate_on_component(geometry_set.get_component_for_write<CurveComponent>(), params);
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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);
- 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 = 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_legacy_point_scale.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc
deleted file mode 100644
index b51ef22fb49..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BKE_colorband.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_point_scale_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Factor"));
- b.add_input<decl::Vector>(N_("Factor"), "Factor_001")
- .default_value({1.0f, 1.0f, 1.0f})
- .subtype(PROP_XYZ);
- b.add_input<decl::Float>(N_("Factor"), "Factor_002").default_value(1.0f).min(0.0f);
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-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 node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeGeometryPointScale *data = MEM_cnew<NodeGeometryPointScale>(__func__);
-
- data->input_type = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
- node->storage = data;
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeGeometryPointScale &node_storage = *(NodeGeometryPointScale *)node->storage;
-
- update_attribute_input_socket_availabilities(
- *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage.input_type);
-}
-
-static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component)
-{
- /* Note that scale doesn't necessarily need to be created with a vector type-- it could also use
- * the highest complexity of the existing attribute's type (if it exists) and the data type used
- * for the factor. But for it's simpler to simply always use float3, since that is usually
- * expected anyway. */
- static const float3 scale_default = float3(1.0f);
- OutputAttribute_Typed<float3> scale_attribute = component.attribute_try_get_for_output(
- "scale", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, &scale_default);
- if (!scale_attribute) {
- return;
- }
-
- const bNode &node = params.node();
- const NodeGeometryPointScale &node_storage = *(const NodeGeometryPointScale *)node.storage;
- const GeometryNodeAttributeInputMode input_type = (GeometryNodeAttributeInputMode)
- node_storage.input_type;
- const CustomDataType data_type = (input_type == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) ? CD_PROP_FLOAT :
- CD_PROP_FLOAT3;
-
- GVArray attribute = params.get_input_attribute(
- "Factor", component, ATTR_DOMAIN_POINT, data_type, nullptr);
- if (!attribute) {
- return;
- }
-
- MutableSpan<float3> scale_span = scale_attribute.as_span();
- if (data_type == CD_PROP_FLOAT) {
- VArray<float> factors = attribute.typed<float>();
- for (const int i : scale_span.index_range()) {
- scale_span[i] = scale_span[i] * factors[i];
- }
- }
- else if (data_type == CD_PROP_FLOAT3) {
- VArray<float3> factors = attribute.typed<float3>();
- for (const int i : scale_span.index_range()) {
- scale_span[i] = scale_span[i] * factors[i];
- }
- }
-
- scale_attribute.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
- }
- if (geometry_set.has<PointCloudComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<PointCloudComponent>());
- }
- if (geometry_set.has<CurveComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<CurveComponent>());
- }
-
- params.set_output("Geometry", std::move(geometry_set));
-}
-
-} // 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);
-
- 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 = 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_legacy_point_separate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc
deleted file mode 100644
index 541be1933af..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc
+++ /dev/null
@@ -1,165 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BKE_attribute_math.hh"
-#include "BKE_mesh.h"
-#include "BKE_pointcloud.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_pointcloud_types.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes {
-
-template<typename T>
-static void copy_data_based_on_mask(Span<T> data,
- Span<bool> masks,
- const bool invert,
- MutableSpan<T> out_data)
-{
- int offset = 0;
- for (const int i : data.index_range()) {
- if (masks[i] != invert) {
- out_data[offset] = data[i];
- offset++;
- }
- }
-}
-
-void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
- GeometryComponent &result_component,
- Span<bool> masks,
- const bool invert)
-{
- for (const AttributeIDRef &attribute_id : in_component.attribute_ids()) {
- ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id);
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type());
-
- /* Only copy point attributes. Theoretically this could interpolate attributes on other
- * domains to the point domain, but that would conflict with attributes that are built-in
- * on other domains, which causes creating the attributes to fail. */
- if (attribute.domain != ATTR_DOMAIN_POINT) {
- continue;
- }
-
- OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
- attribute_id, ATTR_DOMAIN_POINT, data_type);
-
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- VArray_Span span{attribute.varray.typed<T>()};
- MutableSpan<T> out_span = result_attribute.as_span<T>();
- copy_data_based_on_mask(span, masks, invert, out_span);
- });
-
- result_attribute.save();
- }
-}
-
-} // 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()) {
- case GEO_COMPONENT_TYPE_MESH:
- static_cast<MeshComponent &>(component).replace(BKE_mesh_new_nomain(total, 0, 0, 0, 0));
- break;
- case GEO_COMPONENT_TYPE_POINT_CLOUD:
- static_cast<PointCloudComponent &>(component).replace(BKE_pointcloud_new_nomain(total));
- break;
- default:
- BLI_assert(false);
- break;
- }
-}
-
-static void separate_points_from_component(const GeometryComponent &in_component,
- GeometryComponent &out_component,
- const StringRef mask_name,
- const bool invert)
-{
- if (!in_component.attribute_domain_supported(ATTR_DOMAIN_POINT) ||
- in_component.attribute_domain_size(ATTR_DOMAIN_POINT) == 0) {
- return;
- }
-
- const VArray<bool> mask_attribute = in_component.attribute_get_for_read<bool>(
- mask_name, ATTR_DOMAIN_POINT, false);
- VArray_Span<bool> masks{mask_attribute};
-
- const int total = masks.count(!invert);
- if (total == 0) {
- return;
- }
-
- create_component_points(out_component, total);
-
- copy_point_attributes_based_on_mask(in_component, out_component, masks, invert);
-}
-
-static GeometrySet separate_geometry_set(const GeometrySet &set_in,
- const StringRef mask_name,
- const bool invert)
-{
- GeometrySet set_out;
- for (const GeometryComponent *component : set_in.get_components_for_read()) {
- if (component->type() == GEO_COMPONENT_TYPE_CURVE) {
- /* Don't support the curve component for now, even though it has a point domain. */
- continue;
- }
- GeometryComponent &out_component = set_out.get_component_for_write(component->type());
- separate_points_from_component(*component, out_component, mask_name, invert);
- }
- return set_out;
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- bool wait_for_inputs = false;
- wait_for_inputs |= params.lazy_require_input("Geometry");
- wait_for_inputs |= params.lazy_require_input("Mask");
- if (wait_for_inputs) {
- return;
- }
- const std::string mask_attribute_name = params.get_input<std::string>("Mask");
- GeometrySet geometry_set = params.get_input<GeometrySet>("Geometry");
-
- /* 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::realize_instances_legacy(geometry_set);
-
- if (params.lazy_output_is_required("Geometry 1")) {
- params.set_output("Geometry 1",
- separate_geometry_set(geometry_set, mask_attribute_name, true));
- }
- if (params.lazy_output_is_required("Geometry 2")) {
- params.set_output("Geometry 2",
- separate_geometry_set(geometry_set, mask_attribute_name, false));
- }
-}
-
-} // 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);
- 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_legacy_point_translate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc
deleted file mode 100644
index c1486da3c2e..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_point_translate_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Translation"));
- b.add_input<decl::Vector>(N_("Translation"), "Translation_001").subtype(PROP_TRANSLATION);
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-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 execute_on_component(GeoNodeExecParams params, GeometryComponent &component)
-{
- OutputAttribute_Typed<float3> position_attribute =
- component.attribute_try_get_for_output<float3>("position", ATTR_DOMAIN_POINT, {0, 0, 0});
- if (!position_attribute) {
- return;
- }
- VArray<float3> attribute = params.get_input_attribute<float3>(
- "Translation", component, ATTR_DOMAIN_POINT, {0, 0, 0});
-
- for (const int i : attribute.index_range()) {
- position_attribute->set(i, position_attribute->get(i) + attribute[i]);
- }
-
- position_attribute.save();
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<MeshComponent>());
- }
- if (geometry_set.has<PointCloudComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<PointCloudComponent>());
- }
- if (geometry_set.has<CurveComponent>()) {
- execute_on_component(params, geometry_set.get_component_for_write<CurveComponent>());
- }
-
- params.set_output("Geometry", std::move(geometry_set));
-}
-
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeGeometryPointTranslate *data = MEM_cnew<NodeGeometryPointTranslate>(__func__);
-
- data->input_type = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
- node->storage = data;
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage;
-
- update_attribute_input_socket_availabilities(
- *ntree, *node, "Translation", (GeometryNodeAttributeInputMode)node_storage.input_type);
-}
-
-} // 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);
- 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 = 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_legacy_points_to_volume.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc
deleted file mode 100644
index c83571f1967..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc
+++ /dev/null
@@ -1,266 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#ifdef WITH_OPENVDB
-# include <openvdb/openvdb.h>
-# include <openvdb/tools/LevelSetUtil.h>
-# include <openvdb/tools/ParticlesToLevelSet.h>
-#endif
-
-#include "node_geometry_util.hh"
-
-#include "BKE_lib_id.h"
-#include "BKE_volume.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-namespace blender::nodes::node_geo_legacy_points_to_volume_cc {
-
-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);
- 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::String>(N_("Radius"));
- b.add_input<decl::Float>(N_("Radius"), "Radius_001").default_value(0.5f).min(0.0f);
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-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);
- uiItemR(layout, ptr, "input_type_radius", 0, IFACE_("Radius"), ICON_NONE);
-}
-
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeGeometryPointsToVolume *data = MEM_cnew<NodeGeometryPointsToVolume>(__func__);
- data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
- data->input_type_radius = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
- node->storage = data;
-
- bNodeSocket *radius_attribute_socket = nodeFindSocket(node, SOCK_IN, "Radius");
- bNodeSocketValueString *radius_attribute_socket_value =
- (bNodeSocketValueString *)radius_attribute_socket->default_value;
- STRNCPY(radius_attribute_socket_value->value, "radius");
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage;
- 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 ==
- GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT);
- nodeSetSocketAvailability(ntree,
- voxel_size_socket,
- data->resolution_mode ==
- GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE);
-
- update_attribute_input_socket_availabilities(
- *ntree, *node, "Radius", (GeometryNodeAttributeInputMode)data->input_type_radius);
-}
-
-#ifdef WITH_OPENVDB
-namespace {
-/* Implements the interface required by #openvdb::tools::ParticlesToLevelSet. */
-struct ParticleList {
- using PosType = openvdb::Vec3R;
-
- Span<float3> positions;
- Span<float> radii;
-
- size_t size() const
- {
- return (size_t)positions.size();
- }
-
- void getPos(size_t n, openvdb::Vec3R &xyz) const
- {
- xyz = &positions[n].x;
- }
-
- void getPosRad(size_t n, openvdb::Vec3R &xyz, openvdb::Real &radius) const
- {
- xyz = &positions[n].x;
- radius = radii[n];
- }
-};
-} // namespace
-
-static openvdb::FloatGrid::Ptr generate_volume_from_points(const Span<float3> positions,
- const Span<float> radii,
- const float density)
-{
- /* Create a new grid that will be filled. #ParticlesToLevelSet requires the background value to
- * be positive. It will be set to zero later on. */
- openvdb::FloatGrid::Ptr new_grid = openvdb::FloatGrid::create(1.0f);
-
- /* Create a narrow-band level set grid based on the positions and radii. */
- openvdb::tools::ParticlesToLevelSet op{*new_grid};
- /* Don't ignore particles based on their radius. */
- op.setRmin(0.0f);
- op.setRmax(FLT_MAX);
- ParticleList particles{positions, radii};
- op.rasterizeSpheres(particles);
- op.finalize();
-
- /* Convert the level set to a fog volume. This also sets the background value to zero. Inside the
- * fog there will be a density of 1. */
- openvdb::tools::sdfToFogVolume(*new_grid);
-
- /* Take the desired density into account. */
- openvdb::tools::foreach (new_grid->beginValueOn(),
- [&](const openvdb::FloatGrid::ValueOnIter &iter) {
- iter.modifyValue([&](float &value) { value *= density; });
- });
- return new_grid;
-}
-
-static float compute_voxel_size(const GeoNodeExecParams &params,
- Span<float3> positions,
- const float radius)
-{
- const NodeGeometryPointsToVolume &storage =
- *(const NodeGeometryPointsToVolume *)params.node().storage;
-
- if (storage.resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE) {
- return params.get_input<float>("Voxel Size");
- }
-
- if (positions.is_empty()) {
- return 0.0f;
- }
-
- float3 min, max;
- INIT_MINMAX(min, max);
- minmax_v3v3_v3_array(min, max, (float(*)[3])positions.data(), positions.size());
-
- const float voxel_amount = params.get_input<float>("Voxel Amount");
- if (voxel_amount <= 1) {
- return 0.0f;
- }
-
- /* The voxel size adapts to the final size of the volume. */
- const float diagonal = math::distance(min, max);
- const float extended_diagonal = diagonal + 2.0f * radius;
- const float voxel_size = extended_diagonal / voxel_amount;
- return voxel_size;
-}
-
-static void gather_point_data_from_component(const GeoNodeExecParams &params,
- const GeometryComponent &component,
- Vector<float3> &r_positions,
- Vector<float> &r_radii)
-{
- VArray<float3> positions = component.attribute_get_for_read<float3>(
- "position", ATTR_DOMAIN_POINT, {0, 0, 0});
- VArray<float> radii = params.get_input_attribute<float>(
- "Radius", component, ATTR_DOMAIN_POINT, 0.0f);
-
- for (const int i : positions.index_range()) {
- r_positions.append(positions[i]);
- r_radii.append(radii[i]);
- }
-}
-
-static void convert_to_grid_index_space(const float voxel_size,
- MutableSpan<float3> positions,
- MutableSpan<float> radii)
-{
- const float voxel_size_inv = 1.0f / voxel_size;
- for (const int i : positions.index_range()) {
- positions[i] *= voxel_size_inv;
- /* Better align generated grid with source points. */
- positions[i] -= float3(0.5f);
- radii[i] *= voxel_size_inv;
- }
-}
-
-static void initialize_volume_component_from_points(const GeometrySet &geometry_set_in,
- GeometrySet &geometry_set_out,
- const GeoNodeExecParams &params)
-{
- Vector<float3> positions;
- Vector<float> radii;
-
- if (geometry_set_in.has<MeshComponent>()) {
- gather_point_data_from_component(
- params, *geometry_set_in.get_component_for_read<MeshComponent>(), positions, radii);
- }
- if (geometry_set_in.has<PointCloudComponent>()) {
- gather_point_data_from_component(
- params, *geometry_set_in.get_component_for_read<PointCloudComponent>(), positions, radii);
- }
- if (geometry_set_in.has<CurveComponent>()) {
- gather_point_data_from_component(
- params, *geometry_set_in.get_component_for_read<CurveComponent>(), positions, radii);
- }
-
- const float max_radius = *std::max_element(radii.begin(), radii.end());
- const float voxel_size = compute_voxel_size(params, positions, max_radius);
- if (voxel_size == 0.0f || positions.is_empty()) {
- return;
- }
-
- Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr);
- BKE_volume_init_grids(volume);
-
- VolumeGrid *c_density_grid = BKE_volume_grid_add(volume, "density", VOLUME_GRID_FLOAT);
- openvdb::FloatGrid::Ptr density_grid = openvdb::gridPtrCast<openvdb::FloatGrid>(
- BKE_volume_grid_openvdb_for_write(volume, c_density_grid, false));
-
- const float density = params.get_input<float>("Density");
- convert_to_grid_index_space(voxel_size, positions, radii);
- openvdb::FloatGrid::Ptr new_grid = generate_volume_from_points(positions, radii, density);
- /* This merge is cheap, because the #density_grid is empty. */
- density_grid->merge(*new_grid);
- density_grid->transform().postScale(voxel_size);
-
- VolumeComponent &volume_component = geometry_set_out.get_component_for_write<VolumeComponent>();
- volume_component.replace(volume);
-}
-#endif
-
-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::realize_instances_legacy(geometry_set_in);
-
-#ifdef WITH_OPENVDB
- initialize_volume_component_from_points(geometry_set_in, geometry_set_out, params);
-#endif
-
- params.set_output("Geometry", std::move(geometry_set_out));
-}
-
-} // 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(
- &ntype, GEO_NODE_LEGACY_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY);
- node_type_storage(&ntype,
- "NodeGeometryPointsToVolume",
- node_free_standard_storage,
- node_copy_standard_storage);
- node_type_size(&ntype, 170, 120, 700);
- 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_legacy_raycast.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
deleted file mode 100644
index 1420edcca0b..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
+++ /dev/null
@@ -1,313 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "DNA_mesh_types.h"
-
-#include "BKE_bvhutils.h"
-#include "BKE_mesh_sample.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_raycast_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::Geometry>(N_("Target Geometry"));
- b.add_input<decl::String>(N_("Ray Direction"));
- b.add_input<decl::Vector>(N_("Ray Direction"), "Ray Direction_001")
- .default_value({0.0f, 0.0f, 1.0f});
- b.add_input<decl::String>(N_("Ray Length"));
- b.add_input<decl::Float>(N_("Ray Length"), "Ray Length_001")
- .default_value(100.0f)
- .min(0.0f)
- .subtype(PROP_DISTANCE);
- b.add_input<decl::String>(N_("Target Attribute"));
- b.add_input<decl::String>(N_("Is Hit"));
- b.add_input<decl::String>(N_("Hit Position"));
- b.add_input<decl::String>(N_("Hit Normal"));
- b.add_input<decl::String>(N_("Hit Distance"));
- b.add_input<decl::String>(N_("Hit Attribute"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "mapping", 0, IFACE_("Mapping"), ICON_NONE);
- uiItemR(layout, ptr, "input_type_ray_direction", 0, IFACE_("Ray Direction"), ICON_NONE);
- uiItemR(layout, ptr, "input_type_ray_length", 0, IFACE_("Ray Length"), ICON_NONE);
-}
-
-static void node_init(bNodeTree *UNUSED(tree), bNode *node)
-{
- NodeGeometryRaycast *data = MEM_cnew<NodeGeometryRaycast>(__func__);
- data->input_type_ray_direction = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
- data->input_type_ray_length = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
- node->storage = data;
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeGeometryRaycast *node_storage = (NodeGeometryRaycast *)node->storage;
- update_attribute_input_socket_availabilities(
- *ntree,
- *node,
- "Ray Direction",
- (GeometryNodeAttributeInputMode)node_storage->input_type_ray_direction);
- update_attribute_input_socket_availabilities(
- *ntree,
- *node,
- "Ray Length",
- (GeometryNodeAttributeInputMode)node_storage->input_type_ray_length);
-}
-
-static void raycast_to_mesh(const Mesh &mesh,
- const VArray<float3> &ray_origins,
- const VArray<float3> &ray_directions,
- const VArray<float> &ray_lengths,
- const MutableSpan<bool> r_hit,
- const MutableSpan<int> r_hit_indices,
- const MutableSpan<float3> r_hit_positions,
- const MutableSpan<float3> r_hit_normals,
- const MutableSpan<float> r_hit_distances)
-{
- BLI_assert(ray_origins.size() == ray_directions.size());
- BLI_assert(ray_origins.size() == ray_lengths.size());
- BLI_assert(ray_origins.size() == r_hit.size() || r_hit.is_empty());
- BLI_assert(ray_origins.size() == r_hit_indices.size() || r_hit_indices.is_empty());
- BLI_assert(ray_origins.size() == r_hit_positions.size() || r_hit_positions.is_empty());
- BLI_assert(ray_origins.size() == r_hit_normals.size() || r_hit_normals.is_empty());
- BLI_assert(ray_origins.size() == r_hit_distances.size() || r_hit_distances.is_empty());
-
- BVHTreeFromMesh tree_data;
- BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_LOOPTRI, 4);
- if (tree_data.tree == nullptr) {
- free_bvhtree_from_mesh(&tree_data);
- return;
- }
-
- for (const int i : ray_origins.index_range()) {
- const float ray_length = ray_lengths[i];
- const float3 ray_origin = ray_origins[i];
- const float3 ray_direction = math::normalize(ray_directions[i]);
-
- BVHTreeRayHit hit;
- hit.index = -1;
- hit.dist = ray_length;
- if (BLI_bvhtree_ray_cast(tree_data.tree,
- ray_origin,
- ray_direction,
- 0.0f,
- &hit,
- tree_data.raycast_callback,
- &tree_data) != -1) {
- if (!r_hit.is_empty()) {
- r_hit[i] = hit.index >= 0;
- }
- if (!r_hit_indices.is_empty()) {
- /* Index should always be a valid looptri index, use 0 when hit failed. */
- r_hit_indices[i] = max_ii(hit.index, 0);
- }
- if (!r_hit_positions.is_empty()) {
- r_hit_positions[i] = hit.co;
- }
- if (!r_hit_normals.is_empty()) {
- r_hit_normals[i] = hit.no;
- }
- if (!r_hit_distances.is_empty()) {
- r_hit_distances[i] = hit.dist;
- }
- }
- else {
- if (!r_hit.is_empty()) {
- r_hit[i] = false;
- }
- if (!r_hit_indices.is_empty()) {
- r_hit_indices[i] = 0;
- }
- if (!r_hit_positions.is_empty()) {
- r_hit_positions[i] = float3(0.0f, 0.0f, 0.0f);
- }
- if (!r_hit_normals.is_empty()) {
- r_hit_normals[i] = float3(0.0f, 0.0f, 0.0f);
- }
- if (!r_hit_distances.is_empty()) {
- r_hit_distances[i] = ray_length;
- }
- }
- }
-
- free_bvhtree_from_mesh(&tree_data);
-}
-
-static bke::mesh_surface_sample::eAttributeMapMode get_map_mode(
- GeometryNodeRaycastMapMode map_mode)
-{
- switch (map_mode) {
- case GEO_NODE_RAYCAST_INTERPOLATED:
- return bke::mesh_surface_sample::eAttributeMapMode::INTERPOLATED;
- default:
- case GEO_NODE_RAYCAST_NEAREST:
- return bke::mesh_surface_sample::eAttributeMapMode::NEAREST;
- }
-}
-
-static void raycast_from_points(const GeoNodeExecParams &params,
- const GeometrySet &target_geometry,
- GeometryComponent &dst_component,
- const StringRef hit_name,
- const StringRef hit_position_name,
- const StringRef hit_normal_name,
- const StringRef hit_distance_name,
- const Span<std::string> hit_attribute_names,
- const Span<std::string> hit_attribute_output_names)
-{
- BLI_assert(hit_attribute_names.size() == hit_attribute_output_names.size());
-
- const MeshComponent *src_mesh_component =
- target_geometry.get_component_for_read<MeshComponent>();
- if (src_mesh_component == nullptr) {
- return;
- }
- const Mesh *src_mesh = src_mesh_component->get_for_read();
- if (src_mesh == nullptr) {
- return;
- }
- if (src_mesh->totpoly == 0) {
- return;
- }
-
- const NodeGeometryRaycast &storage = *(const NodeGeometryRaycast *)params.node().storage;
- bke::mesh_surface_sample::eAttributeMapMode map_mode = get_map_mode(
- (GeometryNodeRaycastMapMode)storage.mapping);
- const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
-
- VArray<float3> ray_origins = dst_component.attribute_get_for_read<float3>(
- "position", result_domain, {0, 0, 0});
- VArray<float3> ray_directions = params.get_input_attribute<float3>(
- "Ray Direction", dst_component, result_domain, {0, 0, 0});
- VArray<float> ray_lengths = params.get_input_attribute<float>(
- "Ray Length", dst_component, result_domain, 0);
-
- OutputAttribute_Typed<bool> hit_attribute =
- dst_component.attribute_try_get_for_output_only<bool>(hit_name, result_domain);
- OutputAttribute_Typed<float3> hit_position_attribute =
- dst_component.attribute_try_get_for_output_only<float3>(hit_position_name, result_domain);
- OutputAttribute_Typed<float3> hit_normal_attribute =
- dst_component.attribute_try_get_for_output_only<float3>(hit_normal_name, result_domain);
- OutputAttribute_Typed<float> hit_distance_attribute =
- dst_component.attribute_try_get_for_output_only<float>(hit_distance_name, result_domain);
-
- /* Positions and looptri indices are always needed for interpolation,
- * so create temporary arrays if no output attribute is given. */
- Array<int> hit_indices;
- Array<float3> hit_positions_internal;
- if (!hit_attribute_names.is_empty()) {
- hit_indices.reinitialize(ray_origins.size());
-
- if (!hit_position_attribute) {
- hit_positions_internal.reinitialize(ray_origins.size());
- }
- }
- const MutableSpan<bool> is_hit = hit_attribute ? hit_attribute.as_span() : MutableSpan<bool>();
- const MutableSpan<float3> hit_positions = hit_position_attribute ?
- hit_position_attribute.as_span() :
- hit_positions_internal;
- const MutableSpan<float3> hit_normals = hit_normal_attribute ? hit_normal_attribute.as_span() :
- MutableSpan<float3>();
- const MutableSpan<float> hit_distances = hit_distance_attribute ?
- hit_distance_attribute.as_span() :
- MutableSpan<float>();
-
- raycast_to_mesh(*src_mesh,
- ray_origins,
- ray_directions,
- ray_lengths,
- is_hit,
- hit_indices,
- hit_positions,
- hit_normals,
- hit_distances);
-
- hit_attribute.save();
- hit_position_attribute.save();
- hit_normal_attribute.save();
- hit_distance_attribute.save();
-
- /* Custom interpolated attributes */
- bke::mesh_surface_sample::MeshAttributeInterpolator interp(
- src_mesh, IndexMask(ray_origins.size()), hit_positions, hit_indices);
- for (const int i : hit_attribute_names.index_range()) {
- const std::optional<AttributeMetaData> meta_data = src_mesh_component->attribute_get_meta_data(
- hit_attribute_names[i]);
- if (meta_data) {
- ReadAttributeLookup hit_attribute = src_mesh_component->attribute_try_get_for_read(
- hit_attribute_names[i]);
- OutputAttribute hit_attribute_output = dst_component.attribute_try_get_for_output_only(
- hit_attribute_output_names[i], result_domain, meta_data->data_type);
-
- interp.sample_attribute(hit_attribute, hit_attribute_output, map_mode);
-
- hit_attribute_output.save();
- }
- }
-}
-
-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");
-
- const std::string hit_name = params.extract_input<std::string>("Is Hit");
- const std::string hit_position_name = params.extract_input<std::string>("Hit Position");
- const std::string hit_normal_name = params.extract_input<std::string>("Hit Normal");
- const std::string hit_distance_name = params.extract_input<std::string>("Hit Distance");
-
- 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 = 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};
- for (const GeometryComponentType type : types) {
- if (geometry_set.has(type)) {
- raycast_from_points(params,
- target_geometry_set,
- geometry_set.get_component_for_write(type),
- hit_name,
- hit_position_name,
- hit_normal_name,
- hit_distance_name,
- hit_names,
- hit_output_names);
- }
- }
-
- params.set_output("Geometry", geometry_set);
-}
-
-} // 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);
- node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- 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 = 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_legacy_select_by_material.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc
deleted file mode 100644
index 150fd56abe3..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "node_geometry_util.hh"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-
-#include "BLI_task.hh"
-
-#include "BKE_material.h"
-
-namespace blender::nodes::node_geo_legacy_select_by_material_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::Material>(N_("Material")).hide_label();
- b.add_input<decl::String>(N_("Selection"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void select_mesh_by_material(const Mesh &mesh,
- const Material *material,
- const MutableSpan<bool> r_selection)
-{
- BLI_assert(mesh.totpoly == r_selection.size());
- Vector<int> material_indices;
- for (const int i : IndexRange(mesh.totcol)) {
- if (mesh.mat[i] == material) {
- material_indices.append(i);
- }
- }
- threading::parallel_for(r_selection.index_range(), 1024, [&](IndexRange range) {
- for (const int i : range) {
- r_selection[i] = material_indices.contains(mesh.mpoly[i].mat_nr);
- }
- });
-}
-
-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::realize_instances_legacy(geometry_set);
-
- if (geometry_set.has<MeshComponent>()) {
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- const Mesh *mesh = mesh_component.get_for_read();
- if (mesh != nullptr) {
- OutputAttribute_Typed<bool> selection =
- mesh_component.attribute_try_get_for_output_only<bool>(selection_name, ATTR_DOMAIN_FACE);
- if (selection) {
- select_mesh_by_material(*mesh, material, selection.as_span());
- selection.save();
- }
- }
- }
-
- params.set_output("Geometry", std::move(geometry_set));
-}
-
-} // 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);
- 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_legacy_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc
deleted file mode 100644
index 9eef4b84c36..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc
+++ /dev/null
@@ -1,132 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BKE_mesh.h"
-#include "BKE_subdiv.h"
-#include "BKE_subdiv_mesh.h"
-
-#include "DNA_modifier_types.h"
-#include "UI_interface.h"
-#include "UI_resources.h"
-#include "node_geometry_util.hh"
-
-namespace blender::nodes::node_geo_legacy_subdivision_surface_cc {
-
-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);
- b.add_input<decl::Bool>(N_("Use Creases"));
- b.add_output<decl::Geometry>(N_("Geometry"));
-}
-
-static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
-{
-#ifdef WITH_OPENSUBDIV
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
- uiItemR(layout, ptr, "uv_smooth", 0, nullptr, ICON_NONE);
- uiItemR(layout, ptr, "boundary_smooth", 0, nullptr, ICON_NONE);
-#else
- UNUSED_VARS(layout, ptr);
-#endif
-}
-
-static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeGeometrySubdivisionSurface *data = MEM_cnew<NodeGeometrySubdivisionSurface>(__func__);
- data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
- data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL;
- node->storage = data;
-}
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
-
- geometry_set = geometry::realize_instances_legacy(geometry_set);
-
- if (!geometry_set.has_mesh()) {
- params.set_output("Geometry", geometry_set);
- return;
- }
-
-#ifndef WITH_OPENSUBDIV
- params.error_message_add(NodeWarningType::Error,
- TIP_("Disabled, Blender was compiled without OpenSubdiv"));
-#else
- const NodeGeometrySubdivisionSurface &storage =
- *(const NodeGeometrySubdivisionSurface *)params.node().storage;
- 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);
-
- /* Only process subdivision if level is greater than 0. */
- if (subdiv_level == 0) {
- params.set_output("Geometry", std::move(geometry_set));
- return;
- }
-
- const bool use_crease = params.extract_input<bool>("Use Creases");
- const Mesh *mesh_in = geometry_set.get_mesh_for_read();
-
- /* Initialize mesh settings. */
- SubdivToMeshSettings mesh_settings;
- mesh_settings.resolution = (1 << subdiv_level) + 1;
- mesh_settings.use_optimal_display = false;
-
- /* Initialize subdivision settings. */
- SubdivSettings subdiv_settings;
- subdiv_settings.is_simple = false;
- subdiv_settings.is_adaptive = false;
- subdiv_settings.use_creases = use_crease;
- subdiv_settings.level = subdiv_level;
-
- subdiv_settings.vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
- boundary_smooth);
- subdiv_settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
- uv_smooth);
-
- /* Apply subdivision to mesh. */
- Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, mesh_in);
-
- /* In case of bad topology, skip to input mesh. */
- if (subdiv == nullptr) {
- params.set_output("Geometry", std::move(geometry_set));
- return;
- }
-
- Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh_in);
- BKE_mesh_normals_tag_dirty(mesh_out);
-
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- mesh_component.replace(mesh_out);
-
- // BKE_subdiv_stats_print(&subdiv->stats);
- BKE_subdiv_free(subdiv);
-
-#endif
-
- params.set_output("Geometry", std::move(geometry_set));
-}
-
-} // 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);
- 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",
- node_free_standard_storage,
- node_copy_standard_storage);
- nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc
deleted file mode 100644
index 768932a7fe7..00000000000
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc
+++ /dev/null
@@ -1,162 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "DEG_depsgraph_query.h"
-#ifdef WITH_OPENVDB
-# include <openvdb/tools/GridTransformer.h>
-# include <openvdb/tools/VolumeToMesh.h>
-#endif
-
-#include "node_geometry_util.hh"
-
-#include "BKE_lib_id.h"
-#include "BKE_material.h"
-#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
-#include "BKE_volume.h"
-#include "BKE_volume_to_mesh.hh"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-namespace blender::nodes::node_geo_legacy_volume_to_mesh_cc {
-
-static void node_declare(NodeDeclarationBuilder &b)
-{
- b.add_input<decl::Geometry>(N_("Geometry"));
- b.add_input<decl::String>(N_("Density"));
- 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_("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_("Geometry"));
-}
-
-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 node_init(bNodeTree *UNUSED(ntree), bNode *node)
-{
- NodeGeometryVolumeToMesh *data = MEM_cnew<NodeGeometryVolumeToMesh>(__func__);
- data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
-
- bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Density");
- bNodeSocketValueString *grid_socket_value = (bNodeSocketValueString *)grid_socket->default_value;
- STRNCPY(grid_socket_value->value, "density");
-
- node->storage = data;
-}
-
-static void node_update(bNodeTree *ntree, bNode *node)
-{
- NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)node->storage;
-
- 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);
- nodeSetSocketAvailability(ntree,
- voxel_size_socket,
- data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE);
-}
-
-#ifdef WITH_OPENVDB
-
-static void create_mesh_from_volume(GeometrySet &geometry_set_in,
- GeometrySet &geometry_set_out,
- GeoNodeExecParams &params)
-{
- if (!geometry_set_in.has<VolumeComponent>()) {
- return;
- }
-
- const NodeGeometryVolumeToMesh &storage =
- *(const NodeGeometryVolumeToMesh *)params.node().storage;
-
- bke::VolumeToMeshResolution resolution;
- resolution.mode = (VolumeToMeshResolutionMode)storage.resolution_mode;
- if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT) {
- resolution.settings.voxel_amount = params.get_input<float>("Voxel Amount");
- if (resolution.settings.voxel_amount <= 0.0f) {
- return;
- }
- }
- else if (resolution.mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE) {
- resolution.settings.voxel_size = params.get_input<float>("Voxel Size");
- if (resolution.settings.voxel_size <= 0.0f) {
- return;
- }
- }
-
- const VolumeComponent *component = geometry_set_in.get_component_for_read<VolumeComponent>();
- const Volume *volume = component->get_for_read();
- if (volume == nullptr) {
- return;
- }
-
- const Main *bmain = DEG_get_bmain(params.depsgraph());
- BKE_volume_load(volume, bmain);
-
- const std::string grid_name = params.get_input<std::string>("Density");
- const VolumeGrid *volume_grid = BKE_volume_grid_find_for_read(volume, grid_name.c_str());
- if (volume_grid == nullptr) {
- return;
- }
-
- float threshold = params.get_input<float>("Threshold");
- float adaptivity = params.get_input<float>("Adaptivity");
-
- const openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid);
- Mesh *mesh = bke::volume_to_mesh(*grid, resolution, threshold, adaptivity);
- if (mesh == nullptr) {
- return;
- }
- BKE_id_material_eval_ensure_default_slot(&mesh->id);
- MeshComponent &dst_component = geometry_set_out.get_component_for_write<MeshComponent>();
- dst_component.replace(mesh);
-}
-
-#endif /* WITH_OPENVDB */
-
-static void node_geo_exec(GeoNodeExecParams params)
-{
- GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry");
- GeometrySet geometry_set_out;
-
-#ifdef WITH_OPENVDB
- create_mesh_from_volume(geometry_set_in, geometry_set_out, params);
-#else
- params.error_message_add(NodeWarningType::Error,
- TIP_("Disabled, Blender was compiled without OpenVDB"));
-#endif
-
- params.set_output("Geometry", geometry_set_out);
-}
-
-} // 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);
- 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, 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_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
index 412f35d62fd..6794671f707 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -4,9 +4,9 @@
#include "DNA_meshdata_types.h"
#include "DNA_pointcloud_types.h"
+#include "BKE_curves.hh"
#include "BKE_material.h"
#include "BKE_mesh.h"
-#include "BKE_spline.hh"
#include "node_geometry_util.hh"
@@ -162,14 +162,12 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
}
if (geometry_set.has_curves()) {
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
- *geometry_set.get_curves_for_read());
- for (const SplinePtr &spline : curve->splines()) {
- positions_span = spline->evaluated_positions();
- total_size += positions_span.size();
- count++;
- span_count++;
- }
+ count++;
+ span_count++;
+ const Curves &curves_id = *geometry_set.get_curves_for_read();
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+ positions_span = curves.evaluated_positions();
+ total_size += positions_span.size();
}
if (count == 0) {
@@ -203,13 +201,11 @@ static Mesh *compute_hull(const GeometrySet &geometry_set)
}
if (geometry_set.has_curves()) {
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
- *geometry_set.get_curves_for_read());
- for (const SplinePtr &spline : curve->splines()) {
- Span<float3> array = spline->evaluated_positions();
- positions.as_mutable_span().slice(offset, array.size()).copy_from(array);
- offset += array.size();
- }
+ const Curves &curves_id = *geometry_set.get_curves_for_read();
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+ Span<float3> array = curves.evaluated_positions();
+ positions.as_mutable_span().slice(offset, array.size()).copy_from(array);
+ offset += array.size();
}
return hull_from_bullet(geometry_set.get_mesh_for_read(), positions);
@@ -240,20 +236,16 @@ static void read_positions(const GeometryComponent &component,
}
}
-static void read_curve_positions(const CurveEval &curve,
+static void read_curve_positions(const Curves &curves_id,
Span<float4x4> transforms,
Vector<float3> *r_coords)
{
- const Array<int> offsets = curve.evaluated_point_offsets();
- const int total_size = offsets.last();
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+ const int total_size = curves.evaluated_points_num();
r_coords->reserve(r_coords->size() + total_size * transforms.size());
- for (const SplinePtr &spline : curve.splines()) {
- Span<float3> positions = spline->evaluated_positions();
- for (const float4x4 &transform : transforms) {
- for (const float3 &position : positions) {
- r_coords->append(transform * position);
- }
- }
+ r_coords->as_mutable_span().take_back(total_size).copy_from(curves.evaluated_positions());
+ for (const float3 &position : curves.evaluated_positions()) {
+ r_coords->append(transform * postition);
}
}
@@ -275,7 +267,7 @@ static Mesh *convex_hull_from_instances(const GeometrySet &geometry_set)
read_positions(*set.get_component_for_read<MeshComponent>(), transforms, &coords);
}
if (set.has_curves()) {
- read_curve_positions(*curves_to_curve_eval(*set.get_curves_for_read()), transforms, &coords);
+ read_curve_positions(*set.get_curves_for_read(), transforms, &coords);
}
}
return hull_from_bullet(nullptr, coords);
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 2c72e5f14f5..bbc8758952d 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
@@ -55,24 +55,24 @@ class EndpointFieldInput final : public GeometryFieldInput {
const Curves &curves_id = *curve_component.get_for_read();
const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- if (curves.points_size() == 0) {
+ if (curves.points_num() == 0) {
return nullptr;
}
GeometryComponentFieldContext size_context{curve_component, ATTR_DOMAIN_CURVE};
- fn::FieldEvaluator evaluator{size_context, curves.curves_size()};
+ fn::FieldEvaluator evaluator{size_context, curves.curves_num()};
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);
- Array<bool> selection(curves.points_size(), false);
+ Array<bool> selection(curves.points_num(), false);
MutableSpan<bool> selection_span = selection.as_mutable_span();
devirtualize_varray2(start_size, end_size, [&](const auto &start_size, const auto &end_size) {
threading::parallel_for(curves.curves_range(), 1024, [&](IndexRange curves_range) {
for (const int i : curves_range) {
- const IndexRange range = curves.range_for_curve(i);
+ const IndexRange range = curves.points_for_curve(i);
const int start = std::max(start_size[i], 0);
const int end = std::max(end_size[i], 0);
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 08aa7415073..f29b193d98b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
@@ -7,8 +7,8 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_curves.hh"
#include "BKE_mesh.h"
-#include "BKE_spline.hh"
#include "BLI_task.hh"
@@ -40,43 +40,42 @@ static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
-static blender::meshintersect::CDT_result<double> do_cdt(const CurveEval &curve,
- const CDT_output_type output_type)
+static meshintersect::CDT_result<double> do_cdt(const bke::CurvesGeometry &curves,
+ const CDT_output_type output_type)
{
- Span<SplinePtr> splines = curve.splines();
- blender::meshintersect::CDT_input<double> input;
+ meshintersect::CDT_input<double> input;
input.need_ids = false;
- Array<int> offsets = curve.evaluated_point_offsets();
- input.vert.reinitialize(offsets.last());
- input.face.reinitialize(splines.size());
+ input.vert.reinitialize(curves.evaluated_points_num());
+ input.face.reinitialize(curves.curves_num());
- for (const int i_spline : splines.index_range()) {
- const SplinePtr &spline = splines[i_spline];
- const int vert_offset = offsets[i_spline];
+ VArray<bool> cyclic = curves.cyclic();
+ Span<float3> positions = curves.evaluated_positions();
- Span<float3> positions = spline->evaluated_positions();
- for (const int i : positions.index_range()) {
- input.vert[vert_offset + i] = double2(positions[i].x, positions[i].y);
+ for (const int i_curve : curves.curves_range()) {
+ const IndexRange points = curves.evaluated_points_for_curve(i_curve);
+ const int segment_size = bke::curves::curve_segment_size(points.size(), cyclic[i_curve]);
+
+ for (const int i : points) {
+ input.vert[i] = double2(positions[i].x, positions[i].y);
}
- input.face[i_spline].resize(spline->evaluated_edges_size());
- MutableSpan<int> face_verts = input.face[i_spline];
- for (const int i : IndexRange(spline->evaluated_edges_size())) {
- face_verts[i] = vert_offset + i;
+ input.face[i_curve].resize(segment_size);
+ MutableSpan<int> face_verts = input.face[i_curve];
+ for (const int i : IndexRange(segment_size)) {
+ face_verts[i] = points[i];
}
}
- blender::meshintersect::CDT_result<double> result = delaunay_2d_calc(input, output_type);
+ meshintersect::CDT_result<double> result = delaunay_2d_calc(input, output_type);
return result;
}
/* Converts the CDT result into a Mesh. */
-static Mesh *cdt_to_mesh(const blender::meshintersect::CDT_result<double> &result)
+static Mesh *cdt_to_mesh(const meshintersect::CDT_result<double> &result)
{
- int vert_len = result.vert.size();
- int edge_len = result.edge.size();
- int poly_len = result.face.size();
+ const int vert_len = result.vert.size();
+ const int edge_len = result.edge.size();
+ const int poly_len = result.face.size();
int loop_len = 0;
-
for (const Vector<int> &face : result.face) {
loop_len += face.size();
}
@@ -117,9 +116,9 @@ static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCu
return;
}
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
- *geometry_set.get_curves_for_read());
- if (curve->splines().is_empty()) {
+ const Curves &curves_id = *geometry_set.get_curves_for_read();
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+ if (curves.curves_num() == 0) {
geometry_set.replace_curves(nullptr);
return;
}
@@ -128,7 +127,7 @@ static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCu
CDT_CONSTRAINTS_VALID_BMESH_WITH_HOLES :
CDT_INSIDE_WITH_HOLES;
- const blender::meshintersect::CDT_result<double> results = do_cdt(*curve, output_type);
+ const meshintersect::CDT_result<double> results = do_cdt(curves, output_type);
Mesh *mesh = cdt_to_mesh(results);
geometry_set.replace_mesh(mesh);
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 0aa603a7736..dc2b9d40894 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
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
+#include "BKE_curves.hh"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -47,24 +47,24 @@ static HandleType handle_type_from_input_type(const GeometryNodeCurveHandleType
return BEZIER_HANDLE_AUTO;
}
-static void select_by_handle_type(const CurveEval &curve,
+static void select_by_handle_type(const bke::CurvesGeometry &curves,
const HandleType type,
const GeometryNodeCurveHandleMode mode,
const MutableSpan<bool> r_selection)
{
- int offset = 0;
- for (const SplinePtr &spline : curve.splines()) {
- if (spline->type() != CURVE_TYPE_BEZIER) {
- r_selection.slice(offset, spline->size()).fill(false);
- offset += spline->size();
+ VArray<int8_t> curve_types = curves.curve_types();
+ VArray<int8_t> left = curves.handle_types_left();
+ VArray<int8_t> right = curves.handle_types_right();
+
+ for (const int i_curve : curves.curves_range()) {
+ const IndexRange points = curves.points_for_curve(i_curve);
+ if (curve_types[i_curve] != CURVE_TYPE_BEZIER) {
+ r_selection.slice(points).fill(false);
}
else {
- BezierSpline *b = static_cast<BezierSpline *>(spline.get());
- for (int i : IndexRange(b->size())) {
- r_selection[offset++] = (mode & GEO_NODE_CURVE_HANDLE_LEFT &&
- b->handle_types_left()[i] == type) ||
- (mode & GEO_NODE_CURVE_HANDLE_RIGHT &&
- b->handle_types_right()[i] == type);
+ for (const int i_point : points) {
+ r_selection[i_point] = (mode & GEO_NODE_CURVE_HANDLE_LEFT && left[i_point] == type) ||
+ (mode & GEO_NODE_CURVE_HANDLE_RIGHT && right[i_point] == type);
}
}
}
@@ -87,22 +87,19 @@ class HandleTypeFieldInput final : public GeometryFieldInput {
const AttributeDomain domain,
IndexMask mask) const final
{
- if (component.type() != GEO_COMPONENT_TYPE_CURVE) {
+ if (component.type() != GEO_COMPONENT_TYPE_CURVE || domain != ATTR_DOMAIN_POINT) {
return {};
}
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
- const Curves *curve = curve_component.get_for_read();
- if (curve == nullptr) {
+ const Curves *curves_id = curve_component.get_for_read();
+ if (curves_id == nullptr) {
return {};
}
- if (domain == ATTR_DOMAIN_POINT) {
- Array<bool> selection(mask.min_array_size());
- select_by_handle_type(*curves_to_curve_eval(*curve), type_, mode_, selection);
- return VArray<bool>::ForContainer(std::move(selection));
- }
- return {};
+ Array<bool> selection(mask.min_array_size());
+ select_by_handle_type(bke::CurvesGeometry::wrap(curves_id->geometry), type_, mode_, selection);
+ return VArray<bool>::ForContainer(std::move(selection));
}
uint64_t hash() const override
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
index 6c7d7ed375b..38d81c54933 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_arc.cc
@@ -17,6 +17,13 @@ NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveArc)
static void node_declare(NodeDeclarationBuilder &b)
{
+ auto enable_points = [](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS;
+ };
+ auto enable_radius = [](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_RADIUS;
+ };
+
b.add_input<decl::Int>(N_("Resolution"))
.default_value(16)
.min(2)
@@ -26,34 +33,41 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Vector>(N_("Start"))
.default_value({-1.0f, 0.0f, 0.0f})
.subtype(PROP_TRANSLATION)
- .description(N_("Position of the first control point"));
+ .description(N_("Position of the first control point"))
+ .make_available(enable_points);
b.add_input<decl::Vector>(N_("Middle"))
.default_value({0.0f, 2.0f, 0.0f})
.subtype(PROP_TRANSLATION)
- .description(N_("Position of the middle control point"));
+ .description(N_("Position of the middle control point"))
+ .make_available(enable_points);
b.add_input<decl::Vector>(N_("End"))
.default_value({1.0f, 0.0f, 0.0f})
.subtype(PROP_TRANSLATION)
- .description(N_("Position of the last control point"));
+ .description(N_("Position of the last control point"))
+ .make_available(enable_points);
b.add_input<decl::Float>(N_("Radius"))
.default_value(1.0f)
.min(0.0f)
.subtype(PROP_DISTANCE)
- .description(N_("Distance of the points from the origin"));
+ .description(N_("Distance of the points from the origin"))
+ .make_available(enable_radius);
b.add_input<decl::Float>(N_("Start Angle"))
.default_value(0.0f)
.subtype(PROP_ANGLE)
- .description(N_("Starting angle of the arc"));
+ .description(N_("Starting angle of the arc"))
+ .make_available(enable_radius);
b.add_input<decl::Float>(N_("Sweep Angle"))
.default_value(1.75f * M_PI)
.min(-2 * M_PI)
.max(2 * M_PI)
.subtype(PROP_ANGLE)
- .description(N_("Length of the arc"));
+ .description(N_("Length of the arc"))
+ .make_available(enable_radius);
b.add_input<decl::Float>(N_("Offset Angle"))
.default_value(0.0f)
.subtype(PROP_ANGLE)
- .description(N_("Offset angle of the arc"));
+ .description(N_("Offset angle of the arc"))
+ .make_available(enable_points);
b.add_input<decl::Bool>(N_("Connect Center"))
.default_value(false)
.description(N_("Connect the arc at the center"));
@@ -64,17 +78,14 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Geometry>(N_("Curve"));
b.add_output<decl::Vector>(N_("Center"))
.description(N_("The center of the circle described by the three points"))
- .make_available(
- [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; });
+ .make_available(enable_points);
b.add_output<decl::Vector>(N_("Normal"))
.description(N_("The normal direction of the plane described by the three points, pointing "
"towards the positive Z axis"))
- .make_available(
- [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; });
+ .make_available(enable_points);
b.add_output<decl::Float>(N_("Radius"))
.description(N_("The radius of the circle described by the three points"))
- .make_available(
- [](bNode &node) { node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_ARC_TYPE_POINTS; });
+ .make_available(enable_points);
}
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
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 78e1613b630..297674e11f4 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
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
+#include "BKE_curves.hh"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -55,30 +55,26 @@ static void node_init(bNodeTree *UNUSED(tree), bNode *node)
node->storage = data;
}
-static std::unique_ptr<CurveEval> create_bezier_segment_curve(
- const float3 start,
- const float3 start_handle_right,
- const float3 end,
- const float3 end_handle_left,
- const int resolution,
- const GeometryNodeCurvePrimitiveBezierSegmentMode mode)
+static Curves *create_bezier_segment_curve(const float3 start,
+ const float3 start_handle_right,
+ const float3 end,
+ const float3 end_handle_left,
+ const int resolution,
+ const GeometryNodeCurvePrimitiveBezierSegmentMode mode)
{
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>();
- spline->set_resolution(resolution);
+ Curves *curves_id = bke::curves_new_nomain_single(2, CURVE_TYPE_BEZIER);
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id->geometry);
+ curves.resolution().fill(resolution);
- spline->resize(2);
- MutableSpan<float3> positions = spline->positions();
- spline->handle_types_left().fill(BEZIER_HANDLE_ALIGN);
- spline->handle_types_right().fill(BEZIER_HANDLE_ALIGN);
- spline->radii().fill(1.0f);
- spline->tilts().fill(0.0f);
+ MutableSpan<float3> positions = curves.positions();
+ curves.handle_types_left().fill(BEZIER_HANDLE_ALIGN);
+ curves.handle_types_right().fill(BEZIER_HANDLE_ALIGN);
positions.first() = start;
positions.last() = end;
- MutableSpan<float3> handles_right = spline->handle_positions_right();
- MutableSpan<float3> handles_left = spline->handle_positions_left();
+ MutableSpan<float3> handles_right = curves.handle_positions_right();
+ MutableSpan<float3> handles_left = curves.handle_positions_left();
if (mode == GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION) {
handles_left.first() = 2.0f * start - start_handle_right;
@@ -95,9 +91,7 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve(
handles_right.last() = end - end_handle_left;
}
- curve->add_spline(std::move(spline));
- curve->attributes.reallocate(1);
- return curve;
+ return curves_id;
}
static void node_geo_exec(GeoNodeExecParams params)
@@ -106,14 +100,14 @@ static void node_geo_exec(GeoNodeExecParams params)
const GeometryNodeCurvePrimitiveBezierSegmentMode mode =
(const GeometryNodeCurvePrimitiveBezierSegmentMode)storage.mode;
- std::unique_ptr<CurveEval> curve = create_bezier_segment_curve(
+ Curves *curves = create_bezier_segment_curve(
params.extract_input<float3>("Start"),
params.extract_input<float3>("Start Handle"),
params.extract_input<float3>("End"),
params.extract_input<float3>("End Handle"),
std::max(params.extract_input<int>("Resolution"), 1),
mode);
- params.set_output("Curve", GeometrySet::create_with_curves(curve_eval_to_curves(*curve)));
+ params.set_output("Curve", GeometrySet::create_with_curves(curves));
}
} // namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc
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 2fb9f724130..aa4b3a785f1 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
@@ -13,6 +13,13 @@ NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveCircle)
static void node_declare(NodeDeclarationBuilder &b)
{
+ auto endable_points = [](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS;
+ };
+ auto enable_radius = [](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS;
+ };
+
b.add_input<decl::Int>(N_("Resolution"))
.default_value(32)
.min(3)
@@ -23,28 +30,30 @@ static void node_declare(NodeDeclarationBuilder &b)
.subtype(PROP_TRANSLATION)
.description(
N_("One of the three points on the circle. The point order determines the circle's "
- "direction"));
+ "direction"))
+ .make_available(endable_points);
b.add_input<decl::Vector>(N_("Point 2"))
.default_value({0.0f, 1.0f, 0.0f})
.subtype(PROP_TRANSLATION)
.description(
N_("One of the three points on the circle. The point order determines the circle's "
- "direction"));
+ "direction"))
+ .make_available(endable_points);
b.add_input<decl::Vector>(N_("Point 3"))
.default_value({1.0f, 0.0f, 0.0f})
.subtype(PROP_TRANSLATION)
.description(
N_("One of the three points on the circle. The point order determines the circle's "
- "direction"));
+ "direction"))
+ .make_available(endable_points);
b.add_input<decl::Float>(N_("Radius"))
.default_value(1.0f)
.min(0.0f)
.subtype(PROP_DISTANCE)
- .description(N_("Distance of the points from the origin"));
+ .description(N_("Distance of the points from the origin"))
+ .make_available(enable_radius);
b.add_output<decl::Geometry>(N_("Curve"));
- b.add_output<decl::Vector>(N_("Center")).make_available([](bNode &node) {
- node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS;
- });
+ b.add_output<decl::Vector>(N_("Center")).make_available(endable_points);
}
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
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 2e2f4254752..62dbcc91cc6 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
@@ -13,21 +13,29 @@ NODE_STORAGE_FUNCS(NodeGeometryCurvePrimitiveLine)
static void node_declare(NodeDeclarationBuilder &b)
{
+ auto enable_direction = [](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION;
+ };
+
b.add_input<decl::Vector>(N_("Start"))
.subtype(PROP_TRANSLATION)
.description(N_("Position of the first control point"));
b.add_input<decl::Vector>(N_("End"))
.default_value({0.0f, 0.0f, 1.0f})
.subtype(PROP_TRANSLATION)
- .description(N_("Position of the second control point"));
+ .description(N_("Position of the second control point"))
+ .make_available([](bNode &node) {
+ node_storage(node).mode = GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS;
+ });
b.add_input<decl::Vector>(N_("Direction"))
.default_value({0.0f, 0.0f, 1.0f})
- .description(
- N_("Direction the line is going in. The length of this vector does not matter"));
+ .description(N_("Direction the line is going in. The length of this vector does not matter"))
+ .make_available(enable_direction);
b.add_input<decl::Float>(N_("Length"))
.default_value(1.0f)
.subtype(PROP_DISTANCE)
- .description(N_("Distance between the two points"));
+ .description(N_("Distance between the two points"))
+ .make_available(enable_direction);
b.add_output<decl::Geometry>(N_("Curve"));
}
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 8393f9615aa..de29735bd2d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -2,7 +2,7 @@
#include "BLI_task.hh"
-#include "BKE_spline.hh"
+#include "BKE_curves.hh"
#include "node_geometry_util.hh"
@@ -25,7 +25,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
Field<bool> selection_field = params.get_input<Field<bool>>("Selection");
- CurveComponent &component = geometry_set.get_component_for_write<CurveComponent>();
+ const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>();
GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_CURVE};
const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_CURVE);
@@ -33,16 +33,13 @@ static void node_geo_exec(GeoNodeExecParams params)
selection_evaluator.add(selection_field);
selection_evaluator.evaluate();
const IndexMask selection = selection_evaluator.get_evaluated_as_mask(0);
+ if (selection.is_empty()) {
+ return;
+ }
- std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_write());
- MutableSpan<SplinePtr> splines = curve->splines();
- threading::parallel_for(selection.index_range(), 128, [&](IndexRange range) {
- for (const int i : range) {
- splines[selection[i]]->reverse();
- }
- });
-
- component.replace(curve_eval_to_curves(*curve));
+ Curves &curves_id = *geometry_set.get_curves_for_write();
+ bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+ curves.reverse_curves(selection);
});
params.set_output("Curve", std::move(geometry_set));
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 1eb18b2f910..894580f2932 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
@@ -12,20 +12,6 @@
#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)
@@ -76,6 +62,18 @@ static void node_update(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH);
}
+static 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();
+ }
+ });
+}
+
static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
const GeometryNodeCurveResampleMode mode,
const CurveEval &curve,
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 bdd4d74fe4b..d9f29d1ef1c 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
@@ -26,17 +26,35 @@ namespace blender::nodes::node_geo_distribute_points_on_faces_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
+ auto enable_random = [](bNode &node) {
+ node.custom1 = GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM;
+ };
+ auto enable_poisson = [](bNode &node) {
+ node.custom1 = GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON;
+ };
+
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_input<decl::Float>(N_("Distance Min")).min(0.0f).subtype(PROP_DISTANCE);
- b.add_input<decl::Float>(N_("Density Max")).default_value(10.0f).min(0.0f);
- b.add_input<decl::Float>(N_("Density")).default_value(10.0f).min(0.0f).supports_field();
+ b.add_input<decl::Float>(N_("Distance Min"))
+ .min(0.0f)
+ .subtype(PROP_DISTANCE)
+ .make_available(enable_poisson);
+ b.add_input<decl::Float>(N_("Density Max"))
+ .default_value(10.0f)
+ .min(0.0f)
+ .make_available(enable_poisson);
+ b.add_input<decl::Float>(N_("Density"))
+ .default_value(10.0f)
+ .min(0.0f)
+ .supports_field()
+ .make_available(enable_random);
b.add_input<decl::Float>(N_("Density Factor"))
.default_value(1.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR)
- .supports_field();
+ .supports_field()
+ .make_available(enable_poisson);
b.add_input<decl::Int>(N_("Seed"));
b.add_output<decl::Geometry>(N_("Points"));
@@ -114,10 +132,8 @@ static void sample_mesh_surface(const Mesh &mesh,
const int looptri_seed = noise::hash(looptri_index, seed);
RandomNumberGenerator looptri_rng(looptri_seed);
- const float points_amount_fl = area * base_density * looptri_density_factor;
- const float add_point_probability = fractf(points_amount_fl);
- const bool add_point = add_point_probability > looptri_rng.get_float();
- const int point_amount = (int)points_amount_fl + (int)add_point;
+ const int point_amount = looptri_rng.round_probabilistic(area * base_density *
+ looptri_density_factor);
for (int i = 0; i < point_amount; i++) {
const float3 bary_coord = looptri_rng.get_barycentric_coordinates();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
index 8beb6dcb5ce..2aa768129cd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
@@ -10,9 +10,9 @@
#include "DNA_pointcloud_types.h"
#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
#include "node_geometry_util.hh"
@@ -34,8 +34,7 @@ static void node_declare(NodeDeclarationBuilder &b)
.description(N_("The number of duplicates to create for each element"));
b.add_output<decl::Geometry>(N_("Geometry"))
- .description(
- N_("The duplicated geometry only. The output does not contain the original geometry"));
+ .description(N_("The duplicated geometry, not including the original geometry"));
b.add_output<decl::Int>(N_("Duplicate Index"))
.field_source()
.description(N_("The indices of the duplicates for each element"));
@@ -58,21 +57,19 @@ struct IndexAttributes {
};
/* -------------------------------------------------------------------- */
-/** \name Attribute Copy/Creation Functions
+/** \name Utility Functions
* \{ */
-static void gather_attributes_without_id(const GeometrySet &geometry_set,
- const GeometryComponentType component_type,
- const Span<std::string> skip_attributes,
- const bool include_instances,
- Map<AttributeIDRef, AttributeKind> &r_gathered_attributes)
+static Map<AttributeIDRef, AttributeKind> gather_attributes_without_id(
+ const GeometrySet &geometry_set,
+ const GeometryComponentType component_type,
+ const bool include_instances)
{
+ Map<AttributeIDRef, AttributeKind> attributes;
geometry_set.gather_attributes_for_propagation(
- {component_type}, component_type, include_instances, r_gathered_attributes);
- for (const std::string &attribute : skip_attributes) {
- r_gathered_attributes.remove(attribute);
- }
- r_gathered_attributes.remove("id");
+ {component_type}, component_type, include_instances, attributes);
+ attributes.remove("id");
+ return attributes;
};
static IndexRange range_for_offsets_index(const Span<int> offsets, const int index)
@@ -84,12 +81,12 @@ static Array<int> accumulate_counts_to_offsets(const IndexMask selection,
const VArray<int> &counts)
{
Array<int> offsets(selection.size() + 1);
- int dst_points_size = 0;
- for (const int i_point : selection.index_range()) {
- offsets[i_point] = dst_points_size;
- dst_points_size += std::max(counts[selection[i_point]], 0);
+ int total = 0;
+ for (const int i : selection.index_range()) {
+ offsets[i] = total;
+ total += std::max(counts[selection[i]], 0);
}
- offsets.last() = dst_points_size;
+ offsets.last() = total;
return offsets;
}
@@ -100,7 +97,7 @@ static void threaded_slice_fill(Span<int> offsets, Span<T> src, MutableSpan<T> d
BLI_assert(offsets.last() == dst.size());
threading::parallel_for(IndexRange(offsets.size() - 1), 512, [&](IndexRange range) {
for (const int i : range) {
- dst.slice(offsets[i], offsets[i + 1] - offsets[i]).fill(src[i]);
+ dst.slice(range_for_offsets_index(offsets, i)).fill(src[i]);
}
});
}
@@ -115,6 +112,13 @@ static void threaded_mapped_copy(const Span<int> mapping, const Span<T> src, Mut
});
}
+static void copy_hashed_ids(const Span<int> src, const int hash, MutableSpan<int> dst)
+{
+ for (const int i : src.index_range()) {
+ dst[i] = noise::hash(src[i], hash);
+ }
+}
+
static void threaded_id_offset_copy(const Span<int> offsets,
const Span<int> src,
MutableSpan<int> dst)
@@ -135,11 +139,11 @@ static void threaded_id_offset_copy(const Span<int> offsets,
static void create_duplicate_index_attribute(GeometryComponent &component,
const AttributeDomain output_domain,
const IndexMask selection,
- const IndexAttributes &attributes,
+ const IndexAttributes &attribute_outputs,
const Span<int> offsets)
{
OutputAttribute_Typed<int> copy_attribute = component.attribute_try_get_for_output_only<int>(
- attributes.duplicate_index.get(), output_domain);
+ attribute_outputs.duplicate_index.get(), output_domain);
MutableSpan<int> duplicate_indices = copy_attribute.as_span();
for (const int i : IndexRange(selection.size())) {
const IndexRange range = range_for_offsets_index(offsets, i);
@@ -175,156 +179,6 @@ static void copy_stable_id_point(const Span<int> offsets,
dst_attribute.save();
}
-/**
- * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
- * and the duplicate number. This function is used for points when duplicating the edge domain.
- */
-static void copy_stable_id_edges(const Mesh &mesh,
- const IndexMask selection,
- const Span<int> edge_offsets,
- const GeometryComponent &src_component,
- GeometryComponent &dst_component)
-{
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
- if (!src_attribute) {
- return;
- }
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
- if (!dst_attribute) {
- return;
- }
-
- Span<MEdge> edges(mesh.medge, mesh.totedge);
-
- VArray_Span<int> src{src_attribute.varray.typed<int>()};
- MutableSpan<int> dst = dst_attribute.as_span<int>();
- threading::parallel_for(IndexRange(selection.size()), 1024, [&](IndexRange range) {
- for (const int i_edge : range) {
- const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge);
- if (edge_range.size() == 0) {
- continue;
- }
- const MEdge &edge = edges[i_edge];
- const IndexRange vert_range = {edge_range.start() * 2, edge_range.size() * 2};
-
- dst[vert_range[0]] = src[edge.v1];
- dst[vert_range[1]] = src[edge.v2];
- for (const int i_duplicate : IndexRange(1, edge_range.size() - 1)) {
- dst[vert_range[i_duplicate * 2]] = noise::hash(src[edge.v1], i_duplicate);
- dst[vert_range[i_duplicate * 2 + 1]] = noise::hash(src[edge.v2], i_duplicate);
- }
- }
- });
- dst_attribute.save();
-}
-
-/**
- * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
- * and the duplicate number. This function is used for points when duplicating the face domain.
- *
- * This function could be threaded in the future, but since it is only 1 attribute and the
- * `face->edge->vert` mapping would mean creating a 1/1 mapping to allow for it, is it worth it?
- */
-static void copy_stable_id_faces(const Mesh &mesh,
- const IndexMask selection,
- const Span<int> poly_offsets,
- const Span<int> vert_mapping,
- const GeometryComponent &src_component,
- GeometryComponent &dst_component)
-{
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
- if (!src_attribute) {
- return;
- }
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
- if (!dst_attribute) {
- return;
- }
-
- VArray_Span<int> src{src_attribute.varray.typed<int>()};
- MutableSpan<int> dst = dst_attribute.as_span<int>();
-
- Span<MPoly> polys(mesh.mpoly, mesh.totpoly);
- int loop_index = 0;
- for (const int i_poly : selection.index_range()) {
- const IndexRange range = range_for_offsets_index(poly_offsets, i_poly);
- if (range.size() == 0) {
- continue;
- }
- const MPoly &source = polys[i_poly];
- for ([[maybe_unused]] const int i_duplicate : IndexRange(range.size())) {
- for ([[maybe_unused]] const int i_loops : IndexRange(source.totloop)) {
- if (i_duplicate == 0) {
- dst[loop_index] = src[vert_mapping[loop_index]];
- }
- else {
- dst[loop_index] = noise::hash(src[vert_mapping[loop_index]], i_duplicate);
- }
- loop_index++;
- }
- }
- }
-
- dst_attribute.save();
-}
-
-/**
- * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
- * and the duplicate number. In the spline case, copy the entire spline's points to the
- * destination,
- * then loop over the remaining ones point by point, hashing their ids to the new ids.
- */
-static void copy_stable_id_splines(const CurveEval &curve,
- const IndexMask selection,
- const Span<int> curve_offsets,
- const GeometryComponent &src_component,
- GeometryComponent &dst_component)
-{
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
- if (!src_attribute) {
- return;
- }
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
- if (!dst_attribute) {
- return;
- }
-
- Array<int> control_point_offsets = curve.control_point_offsets();
- VArray_Span<int> src{src_attribute.varray.typed<int>()};
- MutableSpan<int> dst = dst_attribute.as_span<int>();
-
- Array<int> curve_point_offsets(selection.size() + 1);
- int dst_point_size = 0;
- for (const int i_curve : selection.index_range()) {
- const int spline_size = curve.splines()[i_curve]->size();
- const IndexRange curve_range = range_for_offsets_index(curve_offsets, i_curve);
-
- curve_point_offsets[i_curve] = dst_point_size;
- dst_point_size += curve_range.size() * spline_size;
- }
- curve_point_offsets.last() = dst_point_size;
-
- threading::parallel_for(IndexRange(curve_point_offsets.size() - 1), 512, [&](IndexRange range) {
- for (const int i_curve : range) {
- const int spline_size = curve.splines()[i_curve]->size();
- const IndexRange curve_range = range_for_offsets_index(curve_offsets, i_curve);
-
- dst.slice(curve_point_offsets[i_curve], spline_size)
- .copy_from(src.slice(control_point_offsets[i_curve], spline_size));
- for (const int i_duplicate : IndexRange(1, curve_range.size() - 1)) {
- for (const int i_point : IndexRange(spline_size)) {
- dst[curve_point_offsets[i_curve] + i_duplicate * spline_size + i_point] = noise::hash(
- src[control_point_offsets[i_curve] + i_point], i_duplicate);
- }
- }
- }
- });
- dst_attribute.save();
-}
-
/* The attributes for the point (also instance) duplicated elements are stored sequentially
* (1,1,1,2,2,2,3,3,3,etc) They can be copied by using a simple offset array. For each domain, if
* elements are ordered differently a custom function is called to copy the attributes.
@@ -337,11 +191,10 @@ static void copy_point_attributes_without_id(GeometrySet &geometry_set,
const GeometryComponent &src_component,
GeometryComponent &dst_component)
{
- Map<AttributeIDRef, AttributeKind> gathered_attributes;
- gather_attributes_without_id(
- geometry_set, component_type, {}, include_instances, gathered_attributes);
+ Map<AttributeIDRef, AttributeKind> attributes = gather_attributes_without_id(
+ geometry_set, component_type, include_instances);
- for (const Map<AttributeIDRef, AttributeKind>::Item entry : gathered_attributes.items()) {
+ for (const 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 || src_attribute.domain != ATTR_DOMAIN_POINT) {
@@ -365,23 +218,28 @@ static void copy_point_attributes_without_id(GeometrySet &geometry_set,
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Curves
+ * \{ */
+
/**
- * Copies the attributes for spline duplicates. If copying the spline domain, the attributes are
+ * Copies the attributes for curve duplicates. If copying the curve domain, the attributes are
* copied with an offset fill, otherwise a mapping is used.
*/
-static void copy_spline_attributes_without_id(const GeometrySet &geometry_set,
- const Span<int> point_mapping,
- const Span<int> offsets,
- const Span<std::string> attributes_to_ignore,
- const GeometryComponent &src_component,
- GeometryComponent &dst_component)
+static void copy_curve_attributes_without_id(const GeometrySet &geometry_set,
+ const CurveComponent &src_component,
+ const bke::CurvesGeometry &src_curves,
+ const IndexMask selection,
+ const Span<int> curve_offsets,
+ bke::CurvesGeometry &dst_curves,
+ CurveComponent &dst_component)
{
- Map<AttributeIDRef, AttributeKind> gathered_attributes;
- gather_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_CURVE, attributes_to_ignore, false, gathered_attributes);
-
- for (const Map<AttributeIDRef, AttributeKind>::Item entry : gathered_attributes.items()) {
+ Map<AttributeIDRef, AttributeKind> attributes = gather_attributes_without_id(
+ geometry_set, GEO_COMPONENT_TYPE_CURVE, false);
+ for (const 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) {
@@ -404,10 +262,18 @@ static void copy_spline_attributes_without_id(const GeometrySet &geometry_set,
switch (out_domain) {
case ATTR_DOMAIN_CURVE:
- threaded_slice_fill<T>(offsets, src, dst);
+ threaded_slice_fill<T>(curve_offsets, src, dst);
break;
case ATTR_DOMAIN_POINT:
- threaded_mapped_copy<T>(point_mapping, src, dst);
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i_selection : range) {
+ const int i_src_curve = selection[i_selection];
+ const Span<T> curve_src = src.slice(src_curves.points_for_curve(i_src_curve));
+ for (const int i_dst_curve : range_for_offsets_index(curve_offsets, i_selection)) {
+ dst.slice(dst_curves.points_for_curve(i_dst_curve)).copy_from(curve_src);
+ }
+ }
+ });
break;
default:
break;
@@ -418,54 +284,126 @@ static void copy_spline_attributes_without_id(const GeometrySet &geometry_set,
}
/**
- * Copies the attributes for edge duplicates. If copying the edge domain, the attributes are
- * copied with an offset fill, for point domain a mapping is used.
+ * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
+ * and the duplicate number. In the curve case, copy the entire curve's points to the
+ * destination,
+ * then loop over the remaining ones point by point, hashing their ids to the new ids.
*/
-static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
- const Span<int> point_mapping,
- const Span<int> offsets,
- const GeometryComponent &src_component,
- GeometryComponent &dst_component)
+static void copy_stable_id_curves(const bke::CurvesGeometry &src_curves,
+ const IndexMask selection,
+ const Span<int> curve_offsets,
+ const CurveComponent &src_component,
+ bke::CurvesGeometry &dst_curves,
+ CurveComponent &dst_component)
{
- Map<AttributeIDRef, AttributeKind> gathered_attributes;
- gather_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_MESH, {}, false, gathered_attributes);
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ if (!src_attribute) {
+ return;
+ }
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ if (!dst_attribute) {
+ return;
+ }
- for (const Map<AttributeIDRef, AttributeKind>::Item entry : gathered_attributes.items()) {
- const AttributeIDRef attribute_id = entry.key;
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
- if (!src_attribute) {
- continue;
- }
+ VArray_Span<int> src{src_attribute.varray.typed<int>()};
+ MutableSpan<int> dst = dst_attribute.as_span<int>();
- const AttributeDomain 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;
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i_selection : range) {
+ const int i_src_curve = selection[i_selection];
+ const Span<int> curve_src = src.slice(src_curves.points_for_curve(i_src_curve));
+ const IndexRange duplicates_range = range_for_offsets_index(curve_offsets, i_selection);
+ for (const int i_duplicate : IndexRange(duplicates_range.size()).drop_front(1)) {
+ const int i_dst_curve = duplicates_range[i_duplicate];
+ copy_hashed_ids(
+ curve_src, i_duplicate, dst.slice(dst_curves.points_for_curve(i_dst_curve)));
+ }
}
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- VArray_Span<T> src{src_attribute.varray.typed<T>()};
- MutableSpan<T> dst = dst_attribute.as_span<T>();
+ });
+ dst_attribute.save();
+}
- switch (out_domain) {
- case ATTR_DOMAIN_EDGE:
- threaded_slice_fill<T>(offsets, src, dst);
- break;
- case ATTR_DOMAIN_POINT:
- threaded_mapped_copy<T>(point_mapping, src, dst);
- break;
- default:
- break;
+static void duplicate_curves(GeometrySet &geometry_set,
+ const Field<int> &count_field,
+ const Field<bool> &selection_field,
+ const IndexAttributes &attribute_outputs)
+{
+ if (!geometry_set.has_curves()) {
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
+ return;
+ }
+ geometry_set.keep_only({GEO_COMPONENT_TYPE_CURVE, GEO_COMPONENT_TYPE_INSTANCES});
+
+ const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
+ const Curves &curves_id = *src_component.get_for_read();
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+
+ GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
+ FieldEvaluator evaluator{field_context, curves.curves_num()};
+ evaluator.add(count_field);
+ evaluator.set_selection(selection_field);
+ evaluator.evaluate();
+ const VArray<int> counts = evaluator.get_evaluated<int>(0);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
+
+ /* The offset in the result curve domain at every selected input curve. */
+ Array<int> curve_offsets(selection.size() + 1);
+ Array<int> point_offsets(selection.size() + 1);
+
+ int dst_curves_size = 0;
+ int dst_points_size = 0;
+ for (const int i_curve : selection.index_range()) {
+ const int count = std::max(counts[selection[i_curve]], 0);
+ curve_offsets[i_curve] = dst_curves_size;
+ point_offsets[i_curve] = dst_points_size;
+ dst_curves_size += count;
+ dst_points_size += count * curves.points_for_curve(selection[i_curve]).size();
+ }
+ curve_offsets.last() = dst_curves_size;
+ point_offsets.last() = dst_points_size;
+
+ Curves *new_curves_id = bke::curves_new_nomain(dst_points_size, dst_curves_size);
+ bke::CurvesGeometry &new_curves = bke::CurvesGeometry::wrap(new_curves_id->geometry);
+ MutableSpan<int> all_dst_offsets = new_curves.offsets();
+
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i_selection : range) {
+ const int i_src_curve = selection[i_selection];
+ const IndexRange src_curve_range = curves.points_for_curve(i_src_curve);
+ const IndexRange dst_curves_range = range_for_offsets_index(curve_offsets, i_selection);
+ MutableSpan<int> dst_offsets = all_dst_offsets.slice(dst_curves_range);
+ for (const int i_duplicate : IndexRange(dst_curves_range.size())) {
+ dst_offsets[i_duplicate] = point_offsets[i_selection] +
+ src_curve_range.size() * i_duplicate;
}
- });
- dst_attribute.save();
+ }
+ });
+ all_dst_offsets.last() = dst_points_size;
+
+ CurveComponent dst_component;
+ dst_component.replace(new_curves_id, GeometryOwnershipType::Editable);
+
+ copy_curve_attributes_without_id(
+ geometry_set, src_component, curves, selection, curve_offsets, new_curves, dst_component);
+
+ copy_stable_id_curves(
+ curves, selection, curve_offsets, src_component, new_curves, dst_component);
+
+ if (attribute_outputs.duplicate_index) {
+ create_duplicate_index_attribute(
+ dst_component, ATTR_DOMAIN_CURVE, selection, attribute_outputs, curve_offsets);
}
+
+ geometry_set.replace_curves(new_curves_id);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Faces
+ * \{ */
+
/**
* Copies the attributes for face duplicates. If copying the face domain, the attributes are
* copied with an offset fill, otherwise a mapping is used.
@@ -478,11 +416,10 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set,
const GeometryComponent &src_component,
GeometryComponent &dst_component)
{
- Map<AttributeIDRef, AttributeKind> gathered_attributes;
- gather_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_MESH, {}, false, gathered_attributes);
+ Map<AttributeIDRef, AttributeKind> attributes = gather_attributes_without_id(
+ geometry_set, GEO_COMPONENT_TYPE_MESH, false);
- for (const Map<AttributeIDRef, AttributeKind>::Item entry : gathered_attributes.items()) {
+ for (const 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) {
@@ -524,88 +461,61 @@ static void copy_face_attributes_without_id(GeometrySet &geometry_set,
}
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Duplication Functions
- * \{ */
-
-static void duplicate_splines(GeometrySet &geometry_set,
- const Field<int> &count_field,
- const Field<bool> &selection_field,
- IndexAttributes &attributes)
+/**
+ * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
+ * and the duplicate number. This function is used for points when duplicating the face domain.
+ *
+ * This function could be threaded in the future, but since it is only 1 attribute and the
+ * `face->edge->vert` mapping would mean creating a 1/1 mapping to allow for it, is it worth it?
+ */
+static void copy_stable_id_faces(const Mesh &mesh,
+ const IndexMask selection,
+ const Span<int> poly_offsets,
+ const Span<int> vert_mapping,
+ const MeshComponent &src_component,
+ MeshComponent &dst_component)
{
- if (!geometry_set.has_curves()) {
- geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ if (!src_attribute) {
+ return;
+ }
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ if (!dst_attribute) {
return;
}
- geometry_set.keep_only({GEO_COMPONENT_TYPE_CURVE, GEO_COMPONENT_TYPE_INSTANCES});
-
- const GeometryComponent &src_component = *geometry_set.get_component_for_read(
- GEO_COMPONENT_TYPE_CURVE);
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
- *geometry_set.get_curves_for_read());
- const int domain_size = src_component.attribute_domain_size(ATTR_DOMAIN_CURVE);
- GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_CURVE};
- FieldEvaluator evaluator{field_context, domain_size};
- evaluator.add(count_field);
- evaluator.set_selection(selection_field);
- evaluator.evaluate();
- const VArray<int> counts = evaluator.get_evaluated<int>(0);
- const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
- Array<int> curve_offsets(selection.size() + 1);
+ VArray_Span<int> src{src_attribute.varray.typed<int>()};
+ MutableSpan<int> dst = dst_attribute.as_span<int>();
- int dst_splines_size = 0;
- int dst_points_size = 0;
- for (const int i_spline : selection.index_range()) {
- int count = std::max(counts[selection[i_spline]], 0);
- curve_offsets[i_spline] = dst_splines_size;
- dst_splines_size += count;
- dst_points_size += count * curve->splines()[selection[i_spline]]->size();
- }
- curve_offsets.last() = dst_splines_size;
-
- Array<int> control_point_offsets = curve->control_point_offsets();
- Array<int> point_mapping(dst_points_size);
-
- std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
- int point_index = 0;
- for (const int i_spline : selection.index_range()) {
- const IndexRange spline_range = range_for_offsets_index(curve_offsets, i_spline);
- for ([[maybe_unused]] const int i_duplicate : IndexRange(spline_range.size())) {
- SplinePtr spline = curve->splines()[selection[i_spline]]->copy();
- for (const int i_point : IndexRange(curve->splines()[selection[i_spline]]->size())) {
- point_mapping[point_index++] = control_point_offsets[selection[i_spline]] + i_point;
+ Span<MPoly> polys(mesh.mpoly, mesh.totpoly);
+ int loop_index = 0;
+ for (const int i_poly : selection.index_range()) {
+ const IndexRange range = range_for_offsets_index(poly_offsets, i_poly);
+ if (range.size() == 0) {
+ continue;
+ }
+ const MPoly &source = polys[i_poly];
+ for ([[maybe_unused]] const int i_duplicate : IndexRange(range.size())) {
+ for ([[maybe_unused]] const int i_loops : IndexRange(source.totloop)) {
+ if (i_duplicate == 0) {
+ dst[loop_index] = src[vert_mapping[loop_index]];
+ }
+ else {
+ dst[loop_index] = noise::hash(src[vert_mapping[loop_index]], i_duplicate);
+ }
+ loop_index++;
}
- new_curve->add_spline(std::move(spline));
}
}
- new_curve->attributes.reallocate(new_curve->splines().size());
-
- CurveComponent dst_component;
- dst_component.replace(curve_eval_to_curves(*new_curve), GeometryOwnershipType::Editable);
-
- Vector<std::string> skip(
- {"position", "radius", "resolution", "cyclic", "tilt", "handle_left", "handle_right"});
-
- copy_spline_attributes_without_id(
- geometry_set, point_mapping, curve_offsets, skip, src_component, dst_component);
-
- copy_stable_id_splines(*curve, selection, curve_offsets, src_component, dst_component);
-
- if (attributes.duplicate_index) {
- create_duplicate_index_attribute(
- dst_component, ATTR_DOMAIN_CURVE, selection, attributes, curve_offsets);
- }
- geometry_set.replace_curves(dst_component.get_for_write());
+ dst_attribute.save();
}
static void duplicate_faces(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
- IndexAttributes &attributes)
+ const IndexAttributes &attribute_outputs)
{
if (!geometry_set.has_mesh()) {
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
@@ -613,25 +523,21 @@ static void duplicate_faces(GeometrySet &geometry_set,
}
geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES});
- GeometryComponent &component = geometry_set.get_component_for_write(GEO_COMPONENT_TYPE_MESH);
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_FACE);
-
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_FACE};
- FieldEvaluator evaluator(field_context, domain_size);
+ const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>();
+ const Mesh &mesh = *src_component.get_for_read();
+ Span<MVert> verts(mesh.mvert, mesh.totvert);
+ Span<MEdge> edges(mesh.medge, mesh.totedge);
+ Span<MPoly> polys(mesh.mpoly, mesh.totpoly);
+ Span<MLoop> loops(mesh.mloop, mesh.totloop);
+ GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_FACE};
+ FieldEvaluator evaluator(field_context, polys.size());
evaluator.add(count_field);
evaluator.set_selection(selection_field);
evaluator.evaluate();
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
const VArray<int> counts = evaluator.get_evaluated<int>(0);
- MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
- const Mesh &mesh = *mesh_component.get_for_read();
- Span<MVert> verts(mesh.mvert, mesh.totvert);
- Span<MEdge> edges(mesh.medge, mesh.totedge);
- Span<MPoly> polys(mesh.mpoly, mesh.totpoly);
- Span<MLoop> loops(mesh.mloop, mesh.totloop);
-
int total_polys = 0;
int total_loops = 0;
Array<int> offsets(selection.size() + 1);
@@ -643,17 +549,16 @@ static void duplicate_faces(GeometrySet &geometry_set,
}
offsets[selection.size()] = total_polys;
- Array<int> vert_mapping(total_loops);
- Array<int> edge_mapping(total_loops);
- Array<int> loop_mapping(total_loops);
-
Mesh *new_mesh = BKE_mesh_new_nomain(total_loops, total_loops, 0, total_loops, total_polys);
-
MutableSpan<MVert> new_verts(new_mesh->mvert, new_mesh->totvert);
MutableSpan<MEdge> new_edges(new_mesh->medge, new_mesh->totedge);
MutableSpan<MLoop> new_loops(new_mesh->mloop, new_mesh->totloop);
MutableSpan<MPoly> new_poly(new_mesh->mpoly, new_mesh->totpoly);
+ Array<int> vert_mapping(new_verts.size());
+ Array<int> edge_mapping(new_edges.size());
+ Array<int> loop_mapping(new_loops.size());
+
int poly_index = 0;
int loop_index = 0;
for (const int i_selection : selection.index_range()) {
@@ -684,6 +589,7 @@ static void duplicate_faces(GeometrySet &geometry_set,
poly_index++;
}
}
+
MeshComponent dst_component;
dst_component.replace(new_mesh, GeometryOwnershipType::Editable);
@@ -692,33 +598,133 @@ static void duplicate_faces(GeometrySet &geometry_set,
vert_mapping,
loop_mapping,
offsets,
- mesh_component,
+ src_component,
dst_component);
- copy_stable_id_faces(mesh, selection, offsets, vert_mapping, mesh_component, dst_component);
- mesh_component.replace(dst_component.get_for_write());
+ copy_stable_id_faces(mesh, selection, offsets, vert_mapping, src_component, dst_component);
- if (attributes.duplicate_index) {
+ if (attribute_outputs.duplicate_index) {
create_duplicate_index_attribute(
- dst_component, ATTR_DOMAIN_FACE, selection, attributes, offsets);
+ dst_component, ATTR_DOMAIN_FACE, selection, attribute_outputs, offsets);
+ }
+
+ geometry_set.replace_mesh(new_mesh);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Edges
+ * \{ */
+
+/**
+ * Copies the attributes for edge duplicates. If copying the edge domain, the attributes are
+ * copied with an offset fill, for point domain a mapping is used.
+ */
+static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
+ const Span<int> point_mapping,
+ const Span<int> offsets,
+ const GeometryComponent &src_component,
+ GeometryComponent &dst_component)
+{
+ Map<AttributeIDRef, AttributeKind> attributes = gather_attributes_without_id(
+ geometry_set, GEO_COMPONENT_TYPE_MESH, false);
+
+ for (const 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;
+ }
+
+ const AttributeDomain 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> src{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst = dst_attribute.as_span<T>();
+
+ switch (out_domain) {
+ case ATTR_DOMAIN_EDGE:
+ threaded_slice_fill<T>(offsets, src, dst);
+ break;
+ case ATTR_DOMAIN_POINT:
+ threaded_mapped_copy<T>(point_mapping, src, dst);
+ break;
+ default:
+ break;
+ }
+ });
+ dst_attribute.save();
+ }
+}
+
+/**
+ * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
+ * and the duplicate number. This function is used for points when duplicating the edge domain.
+ */
+static void copy_stable_id_edges(const Mesh &mesh,
+ const IndexMask selection,
+ const Span<int> edge_offsets,
+ const MeshComponent &src_component,
+ MeshComponent &dst_component)
+{
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ if (!src_attribute) {
+ return;
}
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ if (!dst_attribute) {
+ return;
+ }
+
+ Span<MEdge> edges(mesh.medge, mesh.totedge);
+
+ VArray_Span<int> src{src_attribute.varray.typed<int>()};
+ MutableSpan<int> dst = dst_attribute.as_span<int>();
+ threading::parallel_for(IndexRange(selection.size()), 1024, [&](IndexRange range) {
+ for (const int i_edge : range) {
+ const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge);
+ if (edge_range.size() == 0) {
+ continue;
+ }
+ const MEdge &edge = edges[i_edge];
+ const IndexRange vert_range = {edge_range.start() * 2, edge_range.size() * 2};
+
+ dst[vert_range[0]] = src[edge.v1];
+ dst[vert_range[1]] = src[edge.v2];
+ for (const int i_duplicate : IndexRange(1, edge_range.size() - 1)) {
+ dst[vert_range[i_duplicate * 2]] = noise::hash(src[edge.v1], i_duplicate);
+ dst[vert_range[i_duplicate * 2 + 1]] = noise::hash(src[edge.v2], i_duplicate);
+ }
+ }
+ });
+ dst_attribute.save();
}
static void duplicate_edges(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
- IndexAttributes &attributes)
+ const IndexAttributes &attribute_outputs)
{
if (!geometry_set.has_mesh()) {
geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
return;
};
- const GeometryComponent &src_component = *geometry_set.get_component_for_read(
- GEO_COMPONENT_TYPE_MESH);
- const int domain_size = src_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
+ const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>();
+ const Mesh &mesh = *src_component.get_for_read();
+ Span<MVert> verts(mesh.mvert, mesh.totvert);
+ Span<MEdge> edges(mesh.medge, mesh.totedge);
GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_EDGE};
- FieldEvaluator evaluator{field_context, domain_size};
+ FieldEvaluator evaluator{field_context, edges.size()};
evaluator.add(count_field);
evaluator.set_selection(selection_field);
evaluator.evaluate();
@@ -727,10 +733,6 @@ static void duplicate_edges(GeometrySet &geometry_set,
Array<int> edge_offsets = accumulate_counts_to_offsets(selection, counts);
- const Mesh *mesh = geometry_set.get_mesh_for_read();
- Span<MVert> verts(mesh->mvert, mesh->totvert);
- Span<MEdge> edges(mesh->medge, mesh->totedge);
-
Mesh *new_mesh = BKE_mesh_new_nomain(edge_offsets.last() * 2, edge_offsets.last(), 0, 0, 0);
MutableSpan<MVert> new_verts(new_mesh->mvert, new_mesh->totvert);
MutableSpan<MEdge> new_edges(new_mesh->medge, new_mesh->totedge);
@@ -767,31 +769,36 @@ static void duplicate_edges(GeometrySet &geometry_set,
copy_edge_attributes_without_id(
geometry_set, vert_orig_indices, edge_offsets, src_component, dst_component);
- copy_stable_id_edges(*mesh, selection, edge_offsets, src_component, dst_component);
+ copy_stable_id_edges(mesh, selection, edge_offsets, src_component, dst_component);
- if (attributes.duplicate_index) {
+ if (attribute_outputs.duplicate_index) {
create_duplicate_index_attribute(
- dst_component, ATTR_DOMAIN_EDGE, selection, attributes, edge_offsets);
+ dst_component, ATTR_DOMAIN_EDGE, selection, attribute_outputs, edge_offsets);
}
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- mesh_component.replace(dst_component.get_for_write());
+ geometry_set.replace_mesh(new_mesh);
}
-static void duplicate_points_curve(const GeometryComponentType component_type,
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Points (Curves)
+ * \{ */
+
+static void duplicate_points_curve(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
- GeometrySet &geometry_set,
- IndexAttributes &attributes)
+ const IndexAttributes &attribute_outputs)
{
- const GeometryComponent &src_component = *geometry_set.get_component_for_read(component_type);
- const int domain_size = src_component.attribute_domain_size(ATTR_DOMAIN_POINT);
- if (domain_size == 0) {
+ const CurveComponent &src_component = *geometry_set.get_component_for_read<CurveComponent>();
+ const Curves &src_curves_id = *src_component.get_for_read();
+ const bke::CurvesGeometry &src_curves = bke::CurvesGeometry::wrap(src_curves_id.geometry);
+ if (src_curves.points_num() == 0) {
return;
}
GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_POINT};
- FieldEvaluator evaluator{field_context, domain_size};
+ FieldEvaluator evaluator{field_context, src_curves.points_num()};
evaluator.add(count_field);
evaluator.set_selection(selection_field);
evaluator.evaluate();
@@ -799,82 +806,98 @@ static void duplicate_points_curve(const GeometryComponentType component_type,
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
Array<int> offsets = accumulate_counts_to_offsets(selection, counts);
+ const int dst_size = offsets.last();
- CurveComponent &curve_component = geometry_set.get_component_for_write<CurveComponent>();
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(
- *geometry_set.get_curves_for_read());
- Array<int> control_point_offsets = curve->control_point_offsets();
- std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>();
-
- Array<int> parent(domain_size);
- int spline = 0;
- for (const int i_spline : IndexRange(domain_size)) {
- if (i_spline == control_point_offsets[spline + 1]) {
- spline++;
+ Array<int> point_to_curve_map(src_curves.points_num());
+ threading::parallel_for(src_curves.curves_range(), 1024, [&](const IndexRange range) {
+ for (const int i_curve : range) {
+ const IndexRange point_range = src_curves.points_for_curve(i_curve);
+ point_to_curve_map.as_mutable_span().slice(point_range).fill(i_curve);
}
- parent[i_spline] = spline;
+ });
+
+ Curves *new_curves_id = bke::curves_new_nomain(dst_size, dst_size);
+ bke::CurvesGeometry &new_curves = bke::CurvesGeometry::wrap(new_curves_id->geometry);
+ MutableSpan<int> new_curve_offsets = new_curves.offsets();
+ for (const int i : new_curves.curves_range()) {
+ new_curve_offsets[i] = i;
}
+ new_curve_offsets.last() = dst_size;
- for (const int i_point : selection) {
- const IndexRange point_range = range_for_offsets_index(offsets, i_point);
- for ([[maybe_unused]] const int i_duplicate : IndexRange(point_range.size())) {
- const SplinePtr &parent_spline = curve->splines()[parent[i_point]];
- switch (parent_spline->type()) {
- case CurveType::CURVE_TYPE_BEZIER: {
- std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>();
- spline->resize(1);
- spline->set_resolution(2);
- new_curve->add_spline(std::move(spline));
- break;
- }
- case CurveType::CURVE_TYPE_NURBS: {
- std::unique_ptr<NURBSpline> spline = std::make_unique<NURBSpline>();
- spline->resize(1);
- spline->set_resolution(2);
- new_curve->add_spline(std::move(spline));
+ CurveComponent dst_component;
+ dst_component.replace(new_curves_id, GeometryOwnershipType::Editable);
+
+ Map<AttributeIDRef, AttributeKind> attributes = gather_attributes_without_id(
+ geometry_set, GEO_COMPONENT_TYPE_CURVE, false);
+
+ for (const 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 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, domain, data_type);
+ if (!dst_attribute) {
+ continue;
+ }
+
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> src{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst = dst_attribute.as_span<T>();
+
+ switch (domain) {
+ case ATTR_DOMAIN_CURVE:
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i_selection : range) {
+ const T &src_value = src[point_to_curve_map[selection[i_selection]]];
+ const IndexRange duplicate_range = range_for_offsets_index(offsets, i_selection);
+ dst.slice(duplicate_range).fill(src_value);
+ }
+ });
break;
- }
- case CurveType::CURVE_TYPE_POLY: {
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- spline->resize(1);
- new_curve->add_spline(std::move(spline));
+ case ATTR_DOMAIN_POINT:
+ threaded_slice_fill(offsets, src, dst);
break;
- }
- case CurveType::CURVE_TYPE_CATMULL_ROM: {
- /* Catmull Rom curves are not supported yet. */
+ default:
break;
- }
}
- }
+ });
+ dst_attribute.save();
}
- new_curve->attributes.reallocate(new_curve->splines().size());
- CurveComponent dst_component;
- dst_component.replace(curve_eval_to_curves(*new_curve), GeometryOwnershipType::Editable);
-
- copy_point_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_CURVE, false, offsets, src_component, dst_component);
copy_stable_id_point(offsets, src_component, dst_component);
- if (attributes.duplicate_index) {
+ if (attribute_outputs.duplicate_index) {
create_duplicate_index_attribute(
- dst_component, ATTR_DOMAIN_POINT, selection, attributes, offsets.as_span());
+ dst_component, ATTR_DOMAIN_POINT, selection, attribute_outputs, offsets.as_span());
}
- curve_component.replace(dst_component.get_for_write());
+ geometry_set.replace_curves(new_curves_id);
}
-static void duplicate_points_mesh(const GeometryComponentType component_type,
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Points (Mesh)
+ * \{ */
+
+static void duplicate_points_mesh(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
- GeometrySet &geometry_set,
- IndexAttributes &attributes)
+ const IndexAttributes &attribute_outputs)
{
- const GeometryComponent &src_component = *geometry_set.get_component_for_read(component_type);
- const int domain_size = src_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ const MeshComponent &src_component = *geometry_set.get_component_for_read<MeshComponent>();
+ const Mesh &mesh = *geometry_set.get_mesh_for_read();
+ Span<MVert> src_verts(mesh.mvert, mesh.totvert);
GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_POINT};
- FieldEvaluator evaluator{field_context, domain_size};
+ FieldEvaluator evaluator{field_context, src_verts.size()};
evaluator.add(count_field);
evaluator.set_selection(selection_field);
evaluator.evaluate();
@@ -883,13 +906,10 @@ static void duplicate_points_mesh(const GeometryComponentType component_type,
Array<int> offsets = accumulate_counts_to_offsets(selection, counts);
- const Mesh *mesh = geometry_set.get_mesh_for_read();
- Span<MVert> src_verts(mesh->mvert, mesh->totvert);
-
Mesh *new_mesh = BKE_mesh_new_nomain(offsets.last(), 0, 0, 0, 0);
MutableSpan<MVert> dst_verts(new_mesh->mvert, new_mesh->totvert);
- threaded_slice_fill<MVert>(offsets.as_span(), src_verts, dst_verts);
+ threaded_slice_fill(offsets.as_span(), src_verts, dst_verts);
MeshComponent dst_component;
dst_component.replace(new_mesh, GeometryOwnershipType::Editable);
@@ -898,26 +918,31 @@ static void duplicate_points_mesh(const GeometryComponentType component_type,
copy_stable_id_point(offsets, src_component, dst_component);
- if (attributes.duplicate_index) {
+ if (attribute_outputs.duplicate_index) {
create_duplicate_index_attribute(
- dst_component, ATTR_DOMAIN_POINT, selection, attributes, offsets.as_span());
+ dst_component, ATTR_DOMAIN_POINT, selection, attribute_outputs, offsets.as_span());
}
- MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- mesh_component.replace(dst_component.get_for_write());
+ geometry_set.replace_mesh(new_mesh);
}
-static void duplicate_points_pointcloud(const GeometryComponentType component_type,
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Points (Point Cloud)
+ * \{ */
+
+static void duplicate_points_pointcloud(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
- GeometrySet &geometry_set,
- IndexAttributes &attributes)
+ const IndexAttributes &attribute_outputs)
{
- const GeometryComponent &src_component = *geometry_set.get_component_for_read(component_type);
- const int domain_size = src_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ const PointCloudComponent &src_points =
+ *geometry_set.get_component_for_read<PointCloudComponent>();
+ const int point_size = src_points.attribute_domain_size(ATTR_DOMAIN_POINT);
- GeometryComponentFieldContext field_context{src_component, ATTR_DOMAIN_POINT};
- FieldEvaluator evaluator{field_context, domain_size};
+ GeometryComponentFieldContext field_context{src_points, ATTR_DOMAIN_POINT};
+ FieldEvaluator evaluator{field_context, point_size};
evaluator.add(count_field);
evaluator.set_selection(selection_field);
evaluator.evaluate();
@@ -931,58 +956,65 @@ static void duplicate_points_pointcloud(const GeometryComponentType component_ty
dst_component.replace(pointcloud, GeometryOwnershipType::Editable);
copy_point_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_POINT_CLOUD, false, offsets, src_component, dst_component);
+ geometry_set, GEO_COMPONENT_TYPE_POINT_CLOUD, false, offsets, src_points, dst_component);
- copy_stable_id_point(offsets, src_component, dst_component);
+ copy_stable_id_point(offsets, src_points, dst_component);
- if (attributes.duplicate_index) {
+ if (attribute_outputs.duplicate_index) {
create_duplicate_index_attribute(
- dst_component, ATTR_DOMAIN_POINT, selection, attributes, offsets);
+ dst_component, ATTR_DOMAIN_POINT, selection, attribute_outputs, offsets);
}
geometry_set.replace_pointcloud(pointcloud);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Points
+ * \{ */
+
static void duplicate_points(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
- IndexAttributes &attributes)
+ const IndexAttributes &attribute_outputs)
{
- if (!geometry_set.has_mesh() && !geometry_set.has_curves() && !geometry_set.has_pointcloud()) {
- geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
- return;
- }
-
Vector<GeometryComponentType> component_types = geometry_set.gather_component_types(true, true);
- Vector<GeometryComponentType> types_to_keep;
for (const GeometryComponentType component_type : component_types) {
switch (component_type) {
case GEO_COMPONENT_TYPE_POINT_CLOUD:
- types_to_keep.append(component_type);
- duplicate_points_pointcloud(
- component_type, count_field, selection_field, geometry_set, attributes);
+ if (geometry_set.has_pointcloud()) {
+ duplicate_points_pointcloud(
+ geometry_set, count_field, selection_field, attribute_outputs);
+ }
break;
case GEO_COMPONENT_TYPE_MESH:
- types_to_keep.append(component_type);
- duplicate_points_mesh(
- component_type, count_field, selection_field, geometry_set, attributes);
+ if (geometry_set.has_mesh()) {
+ duplicate_points_mesh(geometry_set, count_field, selection_field, attribute_outputs);
+ }
break;
case GEO_COMPONENT_TYPE_CURVE:
- types_to_keep.append(component_type);
- duplicate_points_curve(
- component_type, count_field, selection_field, geometry_set, attributes);
+ if (geometry_set.has_curves()) {
+ duplicate_points_curve(geometry_set, count_field, selection_field, attribute_outputs);
+ }
break;
default:
break;
}
}
- types_to_keep.append(GEO_COMPONENT_TYPE_INSTANCES);
- geometry_set.keep_only(types_to_keep);
+ component_types.append(GEO_COMPONENT_TYPE_INSTANCES);
+ geometry_set.keep_only(component_types);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Instances
+ * \{ */
+
static void duplicate_instances(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
- IndexAttributes &attributes)
+ const IndexAttributes &attribute_outputs)
{
if (!geometry_set.has_instances()) {
geometry_set.clear();
@@ -992,9 +1024,8 @@ static void duplicate_instances(GeometrySet &geometry_set,
const InstancesComponent &src_instances =
*geometry_set.get_component_for_read<InstancesComponent>();
- const int domain_size = src_instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE);
GeometryComponentFieldContext field_context{src_instances, ATTR_DOMAIN_INSTANCE};
- FieldEvaluator evaluator{field_context, domain_size};
+ FieldEvaluator evaluator{field_context, src_instances.instances_amount()};
evaluator.add(count_field);
evaluator.set_selection(selection_field);
evaluator.evaluate();
@@ -1002,41 +1033,44 @@ static void duplicate_instances(GeometrySet &geometry_set,
const VArray<int> counts = evaluator.get_evaluated<int>(0);
Array<int> offsets = accumulate_counts_to_offsets(selection, counts);
-
if (offsets.last() == 0) {
geometry_set.clear();
return;
}
- GeometrySet instances_geometry;
- InstancesComponent &dst_instances =
- instances_geometry.get_component_for_write<InstancesComponent>();
+ GeometrySet dst_geometry;
+ InstancesComponent &dst_instances = dst_geometry.get_component_for_write<InstancesComponent>();
dst_instances.resize(offsets.last());
for (const int i_selection : selection.index_range()) {
- const int count = offsets[i_selection + 1] - offsets[i_selection];
- if (count == 0) {
+ const IndexRange range = range_for_offsets_index(offsets, i_selection);
+ if (range.size() == 0) {
continue;
}
const int old_handle = src_instances.instance_reference_handles()[i_selection];
const InstanceReference reference = src_instances.references()[old_handle];
const int new_handle = dst_instances.add_reference(reference);
const float4x4 transform = src_instances.instance_transforms()[i_selection];
- dst_instances.instance_transforms().slice(offsets[i_selection], count).fill(transform);
- dst_instances.instance_reference_handles().slice(offsets[i_selection], count).fill(new_handle);
+ dst_instances.instance_transforms().slice(range).fill(transform);
+ dst_instances.instance_reference_handles().slice(range).fill(new_handle);
}
copy_point_attributes_without_id(
geometry_set, GEO_COMPONENT_TYPE_INSTANCES, true, offsets, src_instances, dst_instances);
- if (attributes.duplicate_index) {
+ if (attribute_outputs.duplicate_index) {
create_duplicate_index_attribute(
- dst_instances, ATTR_DOMAIN_INSTANCE, selection, attributes, offsets);
+ dst_instances, ATTR_DOMAIN_INSTANCE, selection, attribute_outputs, offsets);
}
- geometry_set.remove(GEO_COMPONENT_TYPE_INSTANCES);
- geometry_set.add(dst_instances);
+ geometry_set = std::move(dst_geometry);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Entry Point
+ * \{ */
+
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
@@ -1046,33 +1080,28 @@ static void node_geo_exec(GeoNodeExecParams params)
Field<int> count_field = params.extract_input<Field<int>>("Amount");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
- IndexAttributes attributes;
+ IndexAttributes attribute_outputs;
if (params.output_is_required("Duplicate Index")) {
- attributes.duplicate_index = StrongAnonymousAttributeID("duplicate_index");
+ attribute_outputs.duplicate_index = StrongAnonymousAttributeID("duplicate_index");
}
if (duplicate_domain == ATTR_DOMAIN_INSTANCE) {
- geometry_set.keep_only({GEO_COMPONENT_TYPE_INSTANCES});
- duplicate_instances(geometry_set, count_field, selection_field, attributes);
+ duplicate_instances(geometry_set, count_field, selection_field, attribute_outputs);
}
else {
- if (geometry_set.is_empty()) {
- params.set_default_remaining_outputs();
- return;
- }
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
switch (duplicate_domain) {
case ATTR_DOMAIN_CURVE:
- duplicate_splines(geometry_set, count_field, selection_field, attributes);
+ duplicate_curves(geometry_set, count_field, selection_field, attribute_outputs);
break;
case ATTR_DOMAIN_FACE:
- duplicate_faces(geometry_set, count_field, selection_field, attributes);
+ duplicate_faces(geometry_set, count_field, selection_field, attribute_outputs);
break;
case ATTR_DOMAIN_EDGE:
- duplicate_edges(geometry_set, count_field, selection_field, attributes);
+ duplicate_edges(geometry_set, count_field, selection_field, attribute_outputs);
break;
case ATTR_DOMAIN_POINT:
- duplicate_points(geometry_set, count_field, selection_field, attributes);
+ duplicate_points(geometry_set, count_field, selection_field, attribute_outputs);
break;
default:
BLI_assert_unreachable();
@@ -1086,13 +1115,13 @@ static void node_geo_exec(GeoNodeExecParams params)
return;
}
- if (attributes.duplicate_index) {
+ if (attribute_outputs.duplicate_index) {
params.set_output(
"Duplicate Index",
- AnonymousAttributeFieldInput::Create<int>(std::move(attributes.duplicate_index),
+ AnonymousAttributeFieldInput::Create<int>(std::move(attribute_outputs.duplicate_index),
params.attribute_producer_name()));
}
- params.set_output("Geometry", geometry_set);
+ params.set_output("Geometry", std::move(geometry_set));
}
/** \} */
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 6e131dac3de..3ba1378abe1 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
@@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
-
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_input_curve_handles_cc {
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 f6c45c4bca3..756f9123f2b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
@@ -1,13 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BLI_task.hh"
-
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-
-#include "BKE_mesh.h"
-#include "BKE_spline.hh"
-
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_input_normal_cc {
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 c3d87055745..ab6f6b40d5e 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
@@ -2,6 +2,7 @@
#include "node_geometry_util.hh"
+#include "BKE_curves.hh"
#include "BKE_spline.hh"
namespace blender::nodes::node_geo_input_spline_length_cc {
@@ -82,16 +83,16 @@ static VArray<int> construct_spline_count_gvarray(const CurveComponent &componen
if (!component.has_curves()) {
return {};
}
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read());
+ const Curves &curves_id = *component.get_for_read();
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
- Span<SplinePtr> splines = curve->splines();
- auto count_fn = [splines](int i) { return splines[i]->size(); };
+ auto count_fn = [curves](int64_t i) { return curves.points_for_curve(i).size(); };
if (domain == ATTR_DOMAIN_CURVE) {
- return VArray<int>::ForFunc(splines.size(), count_fn);
+ return VArray<int>::ForFunc(curves.curves_num(), count_fn);
}
if (domain == ATTR_DOMAIN_POINT) {
- VArray<int> count = VArray<int>::ForFunc(splines.size(), count_fn);
+ VArray<int> count = VArray<int>::ForFunc(curves.curves_num(), count_fn);
return component.attribute_try_adapt_domain<int>(
std::move(count), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT);
}
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 05cc91b41e3..0e2803cd035 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -1,15 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_material.h"
-#include "BKE_mesh.h"
-#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 "GEO_realize_instances.hh"
#include "node_geometry_util.hh"
diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
index f9d9ed75f30..7923ad6264d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc
@@ -31,7 +31,8 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_input<decl::Vector>(N_("Axis"))
.default_value({1.0f, 0.0f, 0.0f})
.supports_field()
- .description(N_("Direction in which to scale the element"));
+ .description(N_("Direction in which to scale the element"))
+ .make_available([](bNode &node) { node.custom2 = GEO_NODE_SCALE_ELEMENTS_SINGLE_AXIS; });
b.add_output<decl::Geometry>(N_("Geometry"));
};
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 301410f5126..271dd824d27 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
@@ -106,10 +106,12 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
for (const int i : bezier.positions().index_range()) {
if (current_mask < selection.size() && selection[current_mask] == current_point) {
if (mode & GEO_NODE_CURVE_HANDLE_LEFT) {
- bezier.set_handle_position_left(i, positions_input[i] + offsets_input[i]);
+ bezier.set_handle_position_left(
+ i, positions_input[current_point] + offsets_input[current_point]);
}
else {
- bezier.set_handle_position_right(i, positions_input[i] + offsets_input[i]);
+ bezier.set_handle_position_right(
+ i, positions_input[current_point] + offsets_input[current_point]);
}
current_mask++;
}
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 543e57d38ad..0892e068ce2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
@@ -16,8 +16,11 @@ static void set_id_in_component(GeometryComponent &component,
const Field<bool> &selection_field,
const Field<int> &id_field)
{
- GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT};
- const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ const AttributeDomain domain = (component.type() == GEO_COMPONENT_TYPE_INSTANCES) ?
+ ATTR_DOMAIN_INSTANCE :
+ ATTR_DOMAIN_POINT;
+ GeometryComponentFieldContext field_context{component, domain};
+ const int domain_size = component.attribute_domain_size(domain);
if (domain_size == 0) {
return;
}
@@ -30,7 +33,7 @@ static void set_id_in_component(GeometryComponent &component,
* the field. However, as an optimization, use a faster code path when it already exists. */
if (component.attribute_exists("id")) {
OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
- "id", ATTR_DOMAIN_POINT);
+ "id", domain);
evaluator.add_with_destination(id_field, id_attribute.varray());
evaluator.evaluate();
id_attribute.save();
@@ -41,7 +44,7 @@ static void set_id_in_component(GeometryComponent &component,
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);
+ "id", domain);
result_ids.materialize(selection, id_attribute.as_span());
id_attribute.save();
}
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 fccfed21ef4..f3031ff3678 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
@@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include "BKE_spline.hh"
-
#include "node_geometry_util.hh"
namespace blender::nodes::node_geo_set_spline_resolution_cc {
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 2d5b0e58367..7f0ba950490 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include "BLI_generic_array.hh"
#include "BLI_kdopbvh.h"
#include "BLI_task.hh"
@@ -12,8 +13,6 @@
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_sample.hh"
-#include "FN_generic_array.hh"
-
#include "UI_interface.h"
#include "UI_resources.h"
@@ -24,7 +23,6 @@
namespace blender::nodes::node_geo_transfer_attribute_cc {
using namespace blender::bke::mesh_surface_sample;
-using blender::fn::GArray;
NODE_STORAGE_FUNCS(NodeGeometryTransferAttribute)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index 9159ac081e0..a04544e2814 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -13,7 +13,6 @@
#include "BKE_curves.hh"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
-#include "BKE_spline.hh"
#include "BKE_volume.h"
#include "DEG_depsgraph_query.h"
@@ -127,9 +126,7 @@ static void translate_geometry_set(GeometrySet &geometry,
const Depsgraph &depsgraph)
{
if (Curves *curves = geometry.get_curves_for_write()) {
- std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves);
- curve->translate(translation);
- geometry.replace_curves(curve_eval_to_curves(*curve));
+ bke::CurvesGeometry::wrap(curves->geometry).translate(translation);
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
translate_mesh(*mesh, translation);
@@ -150,9 +147,7 @@ void transform_geometry_set(GeometrySet &geometry,
const Depsgraph &depsgraph)
{
if (Curves *curves = geometry.get_curves_for_write()) {
- std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*curves);
- curve->transform(transform);
- geometry.replace_curves(curve_eval_to_curves(*curve));
+ bke::CurvesGeometry::wrap(curves->geometry).transform(transform);
}
if (Mesh *mesh = geometry.get_mesh_for_write()) {
transform_mesh(*mesh, transform);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index 5ded8413cf9..76cdbfb140f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -44,7 +44,13 @@ static Mesh *triangulate_mesh_selection(const Mesh &mesh,
CustomData_MeshMasks cd_mask_extra = {
CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, 0, CD_MASK_ORIGINDEX};
BMeshCreateParams create_params{0};
- BMeshFromMeshParams from_mesh_params{true, 1, 1, 1, cd_mask_extra};
+ BMeshFromMeshParams from_mesh_params{};
+ from_mesh_params.calc_face_normal = true;
+ from_mesh_params.calc_vert_normal = true;
+ from_mesh_params.add_key_index = true;
+ from_mesh_params.use_shapekey = true;
+ from_mesh_params.active_shapekey = 1;
+ from_mesh_params.cd_mask_extra = cd_mask_extra;
BMesh *bm = BKE_mesh_to_bmesh_ex(&mesh, &create_params, &from_mesh_params);
/* Tag faces to be triangulated from the selection mask. */
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
index 5b1b0a21614..5c8f4c52f75 100644
--- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -15,7 +15,6 @@
namespace blender::nodes::geometry_nodes_eval_log {
-using fn::CPPType;
using fn::FieldCPPType;
using fn::FieldInput;
using fn::GField;
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index 948c8376460..0ab446d8b0c 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -10,6 +10,7 @@
#include "DNA_node_types.h"
#include "BLI_color.hh"
+#include "BLI_cpp_type_make.hh"
#include "BLI_listbase.h"
#include "BLI_math_vec_types.hh"
#include "BLI_string.h"
@@ -30,7 +31,6 @@
#include "NOD_node_declaration.hh"
#include "NOD_socket.h"
-#include "FN_cpp_type_make.hh"
#include "FN_field.hh"
using namespace blender;
@@ -683,11 +683,11 @@ static bNodeSocketType *make_socket_type_virtual()
static bNodeSocketType *make_socket_type_bool()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE);
- socktype->base_cpp_type = &blender::fn::CPPType::get<bool>();
+ socktype->base_cpp_type = &blender::CPPType::get<bool>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value;
};
- socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<bool>>();
+ socktype->geometry_nodes_cpp_type = &blender::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);
@@ -699,11 +699,11 @@ static bNodeSocketType *make_socket_type_bool()
static bNodeSocketType *make_socket_type_float(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype);
- socktype->base_cpp_type = &blender::fn::CPPType::get<float>();
+ socktype->base_cpp_type = &blender::CPPType::get<float>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value;
};
- socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<float>>();
+ socktype->geometry_nodes_cpp_type = &blender::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);
@@ -715,11 +715,11 @@ 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->base_cpp_type = &blender::fn::CPPType::get<int>();
+ socktype->base_cpp_type = &blender::CPPType::get<int>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value;
};
- socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<int>>();
+ socktype->geometry_nodes_cpp_type = &blender::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);
@@ -731,11 +731,11 @@ 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->base_cpp_type = &blender::fn::CPPType::get<blender::float3>();
+ socktype->base_cpp_type = &blender::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->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<blender::float3>>();
+ socktype->geometry_nodes_cpp_type = &blender::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);
@@ -747,12 +747,12 @@ 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->base_cpp_type = &blender::fn::CPPType::get<blender::ColorGeometry4f>();
+ socktype->base_cpp_type = &blender::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->geometry_nodes_cpp_type =
- &blender::fn::CPPType::get<ValueOrField<blender::ColorGeometry4f>>();
+ &blender::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);
@@ -764,11 +764,11 @@ static bNodeSocketType *make_socket_type_rgba()
static bNodeSocketType *make_socket_type_string()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE);
- socktype->base_cpp_type = &blender::fn::CPPType::get<std::string>();
+ socktype->base_cpp_type = &blender::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->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<std::string>>();
+ socktype->geometry_nodes_cpp_type = &blender::CPPType::get<ValueOrField<std::string>>();
socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) {
std::string value;
value.~basic_string();
@@ -778,16 +778,16 @@ static bNodeSocketType *make_socket_type_string()
return socktype;
}
-MAKE_CPP_TYPE(Object, Object *, CPPTypeFlags::BasicType)
-MAKE_CPP_TYPE(Collection, Collection *, CPPTypeFlags::BasicType)
-MAKE_CPP_TYPE(Texture, Tex *, CPPTypeFlags::BasicType)
-MAKE_CPP_TYPE(Image, Image *, CPPTypeFlags::BasicType)
-MAKE_CPP_TYPE(Material, Material *, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(Object, Object *, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(Collection, Collection *, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(Texture, Tex *, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(Image, Image *, CPPTypeFlags::BasicType)
+BLI_CPP_TYPE_MAKE(Material, Material *, CPPTypeFlags::BasicType)
static bNodeSocketType *make_socket_type_object()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_OBJECT, PROP_NONE);
- socktype->base_cpp_type = &blender::fn::CPPType::get<Object *>();
+ socktype->base_cpp_type = &blender::CPPType::get<Object *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Object **)r_value = ((bNodeSocketValueObject *)socket.default_value)->value;
};
@@ -799,7 +799,7 @@ static bNodeSocketType *make_socket_type_object()
static bNodeSocketType *make_socket_type_geometry()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_GEOMETRY, PROP_NONE);
- socktype->base_cpp_type = &blender::fn::CPPType::get<GeometrySet>();
+ socktype->base_cpp_type = &blender::CPPType::get<GeometrySet>();
socktype->get_base_cpp_value = [](const bNodeSocket &UNUSED(socket), void *r_value) {
new (r_value) GeometrySet();
};
@@ -811,7 +811,7 @@ static bNodeSocketType *make_socket_type_geometry()
static bNodeSocketType *make_socket_type_collection()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_COLLECTION, PROP_NONE);
- socktype->base_cpp_type = &blender::fn::CPPType::get<Collection *>();
+ socktype->base_cpp_type = &blender::CPPType::get<Collection *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Collection **)r_value = ((bNodeSocketValueCollection *)socket.default_value)->value;
};
@@ -823,7 +823,7 @@ static bNodeSocketType *make_socket_type_collection()
static bNodeSocketType *make_socket_type_texture()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_TEXTURE, PROP_NONE);
- socktype->base_cpp_type = &blender::fn::CPPType::get<Tex *>();
+ socktype->base_cpp_type = &blender::CPPType::get<Tex *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Tex **)r_value = ((bNodeSocketValueTexture *)socket.default_value)->value;
};
@@ -835,7 +835,7 @@ static bNodeSocketType *make_socket_type_texture()
static bNodeSocketType *make_socket_type_image()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_IMAGE, PROP_NONE);
- socktype->base_cpp_type = &blender::fn::CPPType::get<Image *>();
+ socktype->base_cpp_type = &blender::CPPType::get<Image *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Image **)r_value = ((bNodeSocketValueImage *)socket.default_value)->value;
};
@@ -847,7 +847,7 @@ static bNodeSocketType *make_socket_type_image()
static bNodeSocketType *make_socket_type_material()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATERIAL, PROP_NONE);
- socktype->base_cpp_type = &blender::fn::CPPType::get<Material *>();
+ socktype->base_cpp_type = &blender::CPPType::get<Material *>();
socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) {
*(Material **)r_value = ((bNodeSocketValueMaterial *)socket.default_value)->value;
};
diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt
index 9a3663b51c2..9b4ea0e0db6 100644
--- a/source/blender/nodes/shader/CMakeLists.txt
+++ b/source/blender/nodes/shader/CMakeLists.txt
@@ -127,6 +127,7 @@ set(SRC
set(LIB
bf_functions
bf_intern_sky
+ bf_nodes
)
if(WITH_PYTHON)
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
index 9b1d2ee1d63..c8785721dfb 100644
--- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
@@ -42,12 +42,12 @@ static int gpu_shader_clamp(GPUMaterial *mat,
GPU_stack_link(mat, node, "clamp_range", in, out);
}
-static void sh_node_clamp_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_clamp_build_multi_function(NodeMultiFunctionBuilder &builder)
{
- static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, float> minmax_fn{
+ static fn::CustomMF_SI_SI_SI_SO<float, float, float, float> minmax_fn{
"Clamp (Min Max)",
[](float value, float min, float max) { return std::min(std::max(value, min), max); }};
- static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, float> range_fn{
+ static fn::CustomMF_SI_SI_SI_SO<float, float, float, float> range_fn{
"Clamp (Range)", [](float value, float a, float b) {
if (a < b) {
return clamp_f(value, a, b);
diff --git a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc
index 0c8cc209d5a..3723480ffa3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc
@@ -87,37 +87,35 @@ static int gpu_shader_valtorgb(GPUMaterial *mat,
return GPU_stack_link(mat, node, "valtorgb", in, out, tex, GPU_constant(&layer));
}
-class ColorBandFunction : public blender::fn::MultiFunction {
+class ColorBandFunction : public fn::MultiFunction {
private:
const ColorBand &color_band_;
public:
ColorBandFunction(const ColorBand &color_band) : color_band_(color_band)
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Color Band"};
+ fn::MFSignatureBuilder signature{"Color Band"};
signature.single_input<float>("Value");
- signature.single_output<blender::ColorGeometry4f>("Color");
+ signature.single_output<ColorGeometry4f>("Color");
signature.single_output<float>("Alpha");
return signature.build();
}
- void call(blender::IndexMask mask,
- blender::fn::MFParams params,
- blender::fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
- const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
- blender::MutableSpan<blender::ColorGeometry4f> colors =
- params.uninitialized_single_output<blender::ColorGeometry4f>(1, "Color");
- blender::MutableSpan<float> alphas = params.uninitialized_single_output<float>(2, "Alpha");
+ const VArray<float> &values = params.readonly_single_input<float>(0, "Value");
+ MutableSpan<ColorGeometry4f> colors = params.uninitialized_single_output<ColorGeometry4f>(
+ 1, "Color");
+ MutableSpan<float> alphas = params.uninitialized_single_output<float>(2, "Alpha");
for (int64_t i : mask) {
- blender::ColorGeometry4f color;
+ ColorGeometry4f color;
BKE_colorband_evaluate(&color_band_, values[i], color);
colors[i] = color;
alphas[i] = color.a;
@@ -125,8 +123,7 @@ class ColorBandFunction : public blender::fn::MultiFunction {
}
};
-static void sh_node_valtorgb_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_valtorgb_build_multi_function(nodes::NodeMultiFunctionBuilder &builder)
{
bNode &bnode = builder.node();
const ColorBand *color_band = (const ColorBand *)bnode.storage;
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc
index 64a5cd97250..b1db0248d9f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc
@@ -72,35 +72,31 @@ static int gpu_shader_curve_vec(GPUMaterial *mat,
GPU_uniform(ext_xyz[2]));
}
-class CurveVecFunction : public blender::fn::MultiFunction {
+class CurveVecFunction : public fn::MultiFunction {
private:
const CurveMapping &cumap_;
public:
CurveVecFunction(const CurveMapping &cumap) : cumap_(cumap)
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Curve Vec"};
+ fn::MFSignatureBuilder signature{"Curve Vec"};
signature.single_input<float>("Fac");
- signature.single_input<blender::float3>("Vector");
- signature.single_output<blender::float3>("Vector");
+ signature.single_input<float3>("Vector");
+ signature.single_output<float3>("Vector");
return signature.build();
}
- void call(blender::IndexMask mask,
- blender::fn::MFParams params,
- blender::fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
- const blender::VArray<float> &fac = params.readonly_single_input<float>(0, "Fac");
- const blender::VArray<blender::float3> &vec_in = params.readonly_single_input<blender::float3>(
- 1, "Vector");
- blender::MutableSpan<blender::float3> vec_out =
- params.uninitialized_single_output<blender::float3>(2, "Vector");
+ const VArray<float> &fac = params.readonly_single_input<float>(0, "Fac");
+ const VArray<float3> &vec_in = params.readonly_single_input<float3>(1, "Vector");
+ MutableSpan<float3> vec_out = params.uninitialized_single_output<float3>(2, "Vector");
for (int64_t i : mask) {
BKE_curvemapping_evaluate3F(&cumap_, vec_out[i], vec_in[i]);
@@ -111,8 +107,7 @@ class CurveVecFunction : public blender::fn::MultiFunction {
}
};
-static void sh_node_curve_vec_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_curve_vec_build_multi_function(NodeMultiFunctionBuilder &builder)
{
bNode &bnode = builder.node();
CurveMapping *cumap = (CurveMapping *)bnode.storage;
@@ -230,35 +225,33 @@ static int gpu_shader_curve_rgb(GPUMaterial *mat,
GPU_uniform(ext_rgba[3]));
}
-class CurveRGBFunction : public blender::fn::MultiFunction {
+class CurveRGBFunction : public fn::MultiFunction {
private:
const CurveMapping &cumap_;
public:
CurveRGBFunction(const CurveMapping &cumap) : cumap_(cumap)
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Curve RGB"};
+ fn::MFSignatureBuilder signature{"Curve RGB"};
signature.single_input<float>("Fac");
- signature.single_input<blender::ColorGeometry4f>("Color");
- signature.single_output<blender::ColorGeometry4f>("Color");
+ signature.single_input<ColorGeometry4f>("Color");
+ signature.single_output<ColorGeometry4f>("Color");
return signature.build();
}
- void call(blender::IndexMask mask,
- blender::fn::MFParams params,
- blender::fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
- const blender::VArray<float> &fac = params.readonly_single_input<float>(0, "Fac");
- const blender::VArray<blender::ColorGeometry4f> &col_in =
- params.readonly_single_input<blender::ColorGeometry4f>(1, "Color");
- blender::MutableSpan<blender::ColorGeometry4f> col_out =
- params.uninitialized_single_output<blender::ColorGeometry4f>(2, "Color");
+ const VArray<float> &fac = params.readonly_single_input<float>(0, "Fac");
+ const VArray<ColorGeometry4f> &col_in = params.readonly_single_input<ColorGeometry4f>(1,
+ "Color");
+ MutableSpan<ColorGeometry4f> col_out = params.uninitialized_single_output<ColorGeometry4f>(
+ 2, "Color");
for (int64_t i : mask) {
BKE_curvemapping_evaluateRGBF(&cumap_, col_out[i], col_in[i]);
@@ -269,8 +262,7 @@ class CurveRGBFunction : public blender::fn::MultiFunction {
}
};
-static void sh_node_curve_rgb_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_curve_rgb_build_multi_function(NodeMultiFunctionBuilder &builder)
{
bNode &bnode = builder.node();
CurveMapping *cumap = (CurveMapping *)bnode.storage;
@@ -360,33 +352,31 @@ static int gpu_shader_curve_float(GPUMaterial *mat,
GPU_uniform(ext_xyz));
}
-class CurveFloatFunction : public blender::fn::MultiFunction {
+class CurveFloatFunction : public fn::MultiFunction {
private:
const CurveMapping &cumap_;
public:
CurveFloatFunction(const CurveMapping &cumap) : cumap_(cumap)
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Curve Float"};
+ fn::MFSignatureBuilder signature{"Curve Float"};
signature.single_input<float>("Factor");
signature.single_input<float>("Value");
signature.single_output<float>("Value");
return signature.build();
}
- void call(blender::IndexMask mask,
- blender::fn::MFParams params,
- blender::fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
- const blender::VArray<float> &fac = params.readonly_single_input<float>(0, "Factor");
- const blender::VArray<float> &val_in = params.readonly_single_input<float>(1, "Value");
- blender::MutableSpan<float> val_out = params.uninitialized_single_output<float>(2, "Value");
+ const VArray<float> &fac = params.readonly_single_input<float>(0, "Factor");
+ const VArray<float> &val_in = params.readonly_single_input<float>(1, "Value");
+ MutableSpan<float> val_out = params.uninitialized_single_output<float>(2, "Value");
for (int64_t i : mask) {
val_out[i] = BKE_curvemapping_evaluateF(&cumap_, 0, val_in[i]);
@@ -397,8 +387,7 @@ class CurveFloatFunction : public blender::fn::MultiFunction {
}
};
-static void sh_node_curve_float_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_curve_float_build_multi_function(NodeMultiFunctionBuilder &builder)
{
bNode &bnode = builder.node();
CurveMapping *cumap = (CurveMapping *)bnode.storage;
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 f922499b910..8e7934bf34e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
@@ -223,7 +223,7 @@ static float3 clamp_range(const float3 value, const float3 min, const float3 max
clamp_range(value.z, min.z, max.z));
}
-static void map_range_vector_signature(blender::fn::MFSignatureBuilder *signature, bool use_steps)
+static void map_range_vector_signature(fn::MFSignatureBuilder *signature, bool use_steps)
{
signature->single_input<float3>("Vector");
signature->single_input<float3>("From Min");
@@ -236,34 +236,32 @@ static void map_range_vector_signature(blender::fn::MFSignatureBuilder *signatur
signature->single_output<float3>("Vector");
}
-class MapRangeVectorFunction : public blender::fn::MultiFunction {
+class MapRangeVectorFunction : public fn::MultiFunction {
private:
bool clamp_;
public:
MapRangeVectorFunction(bool clamp) : clamp_(clamp)
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Vector Map Range"};
+ 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
+ void call(IndexMask mask, fn::MFParams params, 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");
+ const VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector");
for (int64_t i : mask) {
float3 factor = math::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
@@ -278,35 +276,33 @@ class MapRangeVectorFunction : public blender::fn::MultiFunction {
}
};
-class MapRangeSteppedVectorFunction : public blender::fn::MultiFunction {
+class MapRangeSteppedVectorFunction : public fn::MultiFunction {
private:
bool clamp_;
public:
MapRangeSteppedVectorFunction(bool clamp) : clamp_(clamp)
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Vector Map Range Stepped"};
+ 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
+ void call(IndexMask mask, fn::MFParams params, 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");
+ const VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ const VArray<float3> &steps = params.readonly_single_input<float3>(5, "Steps");
+ MutableSpan<float3> results = params.uninitialized_single_output<float3>(6, "Vector");
for (int64_t i : mask) {
float3 factor = math::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
@@ -322,31 +318,29 @@ class MapRangeSteppedVectorFunction : public blender::fn::MultiFunction {
}
};
-class MapRangeSmoothstepVectorFunction : public blender::fn::MultiFunction {
+class MapRangeSmoothstepVectorFunction : public fn::MultiFunction {
public:
MapRangeSmoothstepVectorFunction()
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Vector Map Range Smoothstep"};
+ 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
+ void call(IndexMask mask, fn::MFParams params, 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");
+ const VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector");
for (int64_t i : mask) {
float3 factor = math::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
@@ -357,31 +351,29 @@ class MapRangeSmoothstepVectorFunction : public blender::fn::MultiFunction {
}
};
-class MapRangeSmootherstepVectorFunction : public blender::fn::MultiFunction {
+class MapRangeSmootherstepVectorFunction : public fn::MultiFunction {
public:
MapRangeSmootherstepVectorFunction()
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Vector Map Range Smoothstep"};
+ 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
+ void call(IndexMask mask, fn::MFParams params, 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");
+ const VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector");
+ const VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min");
+ const VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max");
+ const VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min");
+ const VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max");
+ MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector");
for (int64_t i : mask) {
float3 factor = math::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
@@ -392,7 +384,7 @@ class MapRangeSmootherstepVectorFunction : public blender::fn::MultiFunction {
}
};
-static void map_range_signature(blender::fn::MFSignatureBuilder *signature, bool use_steps)
+static void map_range_signature(fn::MFSignatureBuilder *signature, bool use_steps)
{
signature->single_input<float>("Value");
signature->single_input<float>("From Min");
@@ -405,34 +397,32 @@ static void map_range_signature(blender::fn::MFSignatureBuilder *signature, bool
signature->single_output<float>("Result");
}
-class MapRangeFunction : public blender::fn::MultiFunction {
+class MapRangeFunction : public fn::MultiFunction {
private:
bool clamp_;
public:
MapRangeFunction(bool clamp) : clamp_(clamp)
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Map Range"};
+ fn::MFSignatureBuilder signature{"Map Range"};
map_range_signature(&signature, false);
return signature.build();
}
- void call(blender::IndexMask mask,
- blender::fn::MFParams params,
- blender::fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
- const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
- const blender::VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
- const blender::VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
- const blender::VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
- const blender::VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
- blender::MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result");
+ const VArray<float> &values = params.readonly_single_input<float>(0, "Value");
+ const VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
+ const VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
+ const VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
+ const VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
+ MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result");
for (int64_t i : mask) {
float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
@@ -447,35 +437,33 @@ class MapRangeFunction : public blender::fn::MultiFunction {
}
};
-class MapRangeSteppedFunction : public blender::fn::MultiFunction {
+class MapRangeSteppedFunction : public fn::MultiFunction {
private:
bool clamp_;
public:
MapRangeSteppedFunction(bool clamp) : clamp_(clamp)
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Map Range Stepped"};
+ fn::MFSignatureBuilder signature{"Map Range Stepped"};
map_range_signature(&signature, true);
return signature.build();
}
- void call(blender::IndexMask mask,
- blender::fn::MFParams params,
- blender::fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
- const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
- const blender::VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
- const blender::VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
- const blender::VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
- const blender::VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
- const blender::VArray<float> &steps = params.readonly_single_input<float>(5, "Steps");
- blender::MutableSpan<float> results = params.uninitialized_single_output<float>(6, "Result");
+ const VArray<float> &values = params.readonly_single_input<float>(0, "Value");
+ const VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
+ const VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
+ const VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
+ const VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
+ const VArray<float> &steps = params.readonly_single_input<float>(5, "Steps");
+ MutableSpan<float> results = params.uninitialized_single_output<float>(6, "Result");
for (int64_t i : mask) {
float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
@@ -491,31 +479,29 @@ class MapRangeSteppedFunction : public blender::fn::MultiFunction {
}
};
-class MapRangeSmoothstepFunction : public blender::fn::MultiFunction {
+class MapRangeSmoothstepFunction : public fn::MultiFunction {
public:
MapRangeSmoothstepFunction()
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Map Range Smoothstep"};
+ fn::MFSignatureBuilder signature{"Map Range Smoothstep"};
map_range_signature(&signature, false);
return signature.build();
}
- void call(blender::IndexMask mask,
- blender::fn::MFParams params,
- blender::fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
- const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
- const blender::VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
- const blender::VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
- const blender::VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
- const blender::VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
- blender::MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result");
+ const VArray<float> &values = params.readonly_single_input<float>(0, "Value");
+ const VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
+ const VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
+ const VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
+ const VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
+ MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result");
for (int64_t i : mask) {
float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
@@ -526,31 +512,29 @@ class MapRangeSmoothstepFunction : public blender::fn::MultiFunction {
}
};
-class MapRangeSmootherstepFunction : public blender::fn::MultiFunction {
+class MapRangeSmootherstepFunction : public fn::MultiFunction {
public:
MapRangeSmootherstepFunction()
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Map Range Smoothstep"};
+ fn::MFSignatureBuilder signature{"Map Range Smoothstep"};
map_range_signature(&signature, false);
return signature.build();
}
- void call(blender::IndexMask mask,
- blender::fn::MFParams params,
- blender::fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
- const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value");
- const blender::VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
- const blender::VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
- const blender::VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
- const blender::VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
- blender::MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result");
+ const VArray<float> &values = params.readonly_single_input<float>(0, "Value");
+ const VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min");
+ const VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max");
+ const VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min");
+ const VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max");
+ MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result");
for (int64_t i : mask) {
float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]);
@@ -561,8 +545,7 @@ class MapRangeSmootherstepFunction : public blender::fn::MultiFunction {
}
};
-static void sh_node_map_range_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_map_range_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const NodeMapRange &storage = node_storage(builder.node());
bool clamp = storage.clamp != 0;
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc
index 83d0ff8177b..a828011a3ab 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_math.cc
@@ -69,8 +69,7 @@ static void sh_node_math_gather_link_searches(GatherLinkSearchOpParams &params)
static const char *gpu_shader_get_name(int mode)
{
- const blender::nodes::FloatMathOperationInfo *info =
- blender::nodes::get_float_math_operation_info(mode);
+ const FloatMathOperationInfo *info = get_float_math_operation_info(mode);
if (!info) {
return nullptr;
}
@@ -102,34 +101,32 @@ static int gpu_shader_math(GPUMaterial *mat,
return 0;
}
-static const blender::fn::MultiFunction *get_base_multi_function(bNode &node)
+static const fn::MultiFunction *get_base_multi_function(bNode &node)
{
const int mode = node.custom1;
- const blender::fn::MultiFunction *base_fn = nullptr;
+ const fn::MultiFunction *base_fn = nullptr;
- 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.c_str(),
- function};
- base_fn = &fn;
- });
+ try_dispatch_float_math_fl_to_fl(mode, [&](auto function, const FloatMathOperationInfo &info) {
+ static fn::CustomMF_SI_SO<float, float> fn{info.title_case_name.c_str(), function};
+ base_fn = &fn;
+ });
if (base_fn != nullptr) {
return base_fn;
}
- 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.c_str(),
- function};
- base_fn = &fn;
- });
+ try_dispatch_float_math_fl_fl_to_fl(mode,
+ [&](auto function, const FloatMathOperationInfo &info) {
+ static fn::CustomMF_SI_SI_SO<float, float, float> fn{
+ info.title_case_name.c_str(), function};
+ base_fn = &fn;
+ });
if (base_fn != nullptr) {
return base_fn;
}
- 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{
+ try_dispatch_float_math_fl_fl_fl_to_fl(
+ mode, [&](auto function, const FloatMathOperationInfo &info) {
+ static fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{
info.title_case_name.c_str(), function};
base_fn = &fn;
});
@@ -140,27 +137,24 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node)
return nullptr;
}
-class ClampWrapperFunction : public blender::fn::MultiFunction {
+class ClampWrapperFunction : public fn::MultiFunction {
private:
- const blender::fn::MultiFunction &fn_;
+ const fn::MultiFunction &fn_;
public:
- ClampWrapperFunction(const blender::fn::MultiFunction &fn) : fn_(fn)
+ ClampWrapperFunction(const fn::MultiFunction &fn) : fn_(fn)
{
this->set_signature(&fn.signature());
}
- void call(blender::IndexMask mask,
- blender::fn::MFParams params,
- blender::fn::MFContext context) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext context) const override
{
fn_.call(mask, params, context);
/* Assumes the output parameter is the last one. */
const int output_param_index = this->param_amount() - 1;
/* This has actually been initialized in the call above. */
- blender::MutableSpan<float> results = params.uninitialized_single_output<float>(
- output_param_index);
+ MutableSpan<float> results = params.uninitialized_single_output<float>(output_param_index);
for (const int i : mask) {
float &value = results[i];
@@ -169,9 +163,9 @@ class ClampWrapperFunction : public blender::fn::MultiFunction {
}
};
-static void sh_node_math_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_math_build_multi_function(NodeMultiFunctionBuilder &builder)
{
- const blender::fn::MultiFunction *base_function = get_base_multi_function(builder.node());
+ const fn::MultiFunction *base_function = get_base_multi_function(builder.node());
const bool clamp_output = builder.node().custom2 != 0;
if (clamp_output) {
diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
index fc6ce6a11f7..12707623049 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
@@ -84,7 +84,7 @@ static int gpu_shader_mix_rgb(GPUMaterial *mat,
return 0;
}
-class MixRGBFunction : public blender::fn::MultiFunction {
+class MixRGBFunction : public fn::MultiFunction {
private:
bool clamp_;
int type_;
@@ -92,31 +92,29 @@ class MixRGBFunction : public blender::fn::MultiFunction {
public:
MixRGBFunction(bool clamp, int type) : clamp_(clamp), type_(type)
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"MixRGB"};
+ fn::MFSignatureBuilder signature{"MixRGB"};
signature.single_input<float>("Fac");
- signature.single_input<blender::ColorGeometry4f>("Color1");
- signature.single_input<blender::ColorGeometry4f>("Color2");
- signature.single_output<blender::ColorGeometry4f>("Color");
+ signature.single_input<ColorGeometry4f>("Color1");
+ signature.single_input<ColorGeometry4f>("Color2");
+ signature.single_output<ColorGeometry4f>("Color");
return signature.build();
}
- void call(blender::IndexMask mask,
- blender::fn::MFParams params,
- blender::fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
- const blender::VArray<float> &fac = params.readonly_single_input<float>(0, "Fac");
- const blender::VArray<blender::ColorGeometry4f> &col1 =
- params.readonly_single_input<blender::ColorGeometry4f>(1, "Color1");
- const blender::VArray<blender::ColorGeometry4f> &col2 =
- params.readonly_single_input<blender::ColorGeometry4f>(2, "Color2");
- blender::MutableSpan<blender::ColorGeometry4f> results =
- params.uninitialized_single_output<blender::ColorGeometry4f>(3, "Color");
+ const VArray<float> &fac = params.readonly_single_input<float>(0, "Fac");
+ const VArray<ColorGeometry4f> &col1 = params.readonly_single_input<ColorGeometry4f>(1,
+ "Color1");
+ const VArray<ColorGeometry4f> &col2 = params.readonly_single_input<ColorGeometry4f>(2,
+ "Color2");
+ MutableSpan<ColorGeometry4f> results = params.uninitialized_single_output<ColorGeometry4f>(
+ 3, "Color");
for (int64_t i : mask) {
results[i] = col1[i];
@@ -131,7 +129,7 @@ class MixRGBFunction : public blender::fn::MultiFunction {
}
};
-static void sh_node_mix_rgb_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_mix_rgb_build_multi_function(NodeMultiFunctionBuilder &builder)
{
bNode &node = builder.node();
bool clamp = node.custom2 & SHD_MIXRGB_CLAMP;
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
index 2a88c10b61a..657f591a50c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
@@ -27,36 +27,34 @@ static int gpu_shader_seprgb(GPUMaterial *mat,
return GPU_stack_link(mat, node, "separate_rgb", in, out);
}
-class SeparateRGBFunction : public blender::fn::MultiFunction {
+class SeparateRGBFunction : public fn::MultiFunction {
public:
SeparateRGBFunction()
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Separate RGB"};
- signature.single_input<blender::ColorGeometry4f>("Color");
+ fn::MFSignatureBuilder signature{"Separate RGB"};
+ signature.single_input<ColorGeometry4f>("Color");
signature.single_output<float>("R");
signature.single_output<float>("G");
signature.single_output<float>("B");
return signature.build();
}
- void call(blender::IndexMask mask,
- blender::fn::MFParams params,
- blender::fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
- const blender::VArray<blender::ColorGeometry4f> &colors =
- params.readonly_single_input<blender::ColorGeometry4f>(0, "Color");
- blender::MutableSpan<float> rs = params.uninitialized_single_output<float>(1, "R");
- blender::MutableSpan<float> gs = params.uninitialized_single_output<float>(2, "G");
- blender::MutableSpan<float> bs = params.uninitialized_single_output<float>(3, "B");
+ const VArray<ColorGeometry4f> &colors = params.readonly_single_input<ColorGeometry4f>(0,
+ "Color");
+ MutableSpan<float> rs = params.uninitialized_single_output<float>(1, "R");
+ MutableSpan<float> gs = params.uninitialized_single_output<float>(2, "G");
+ MutableSpan<float> bs = params.uninitialized_single_output<float>(3, "B");
for (int64_t i : mask) {
- blender::ColorGeometry4f color = colors[i];
+ ColorGeometry4f color = colors[i];
rs[i] = color.r;
gs[i] = color.g;
bs[i] = color.b;
@@ -64,7 +62,7 @@ class SeparateRGBFunction : public blender::fn::MultiFunction {
}
};
-static void sh_node_seprgb_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_seprgb_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static SeparateRGBFunction fn;
builder.set_matching_fn(fn);
@@ -106,11 +104,10 @@ static int gpu_shader_combrgb(GPUMaterial *mat,
return GPU_stack_link(mat, node, "combine_rgb", in, out);
}
-static void sh_node_combrgb_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_combrgb_build_multi_function(NodeMultiFunctionBuilder &builder)
{
- static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, blender::ColorGeometry4f> fn{
- "Combine RGB",
- [](float r, float g, float b) { return blender::ColorGeometry4f(r, g, b, 1.0f); }};
+ static fn::CustomMF_SI_SI_SI_SO<float, float, float, ColorGeometry4f> fn{
+ "Combine RGB", [](float r, float g, float b) { return ColorGeometry4f(r, g, b, 1.0f); }};
builder.set_matching_fn(fn);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
index 94eb961c25d..0d751157817 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
@@ -27,36 +27,33 @@ static int gpu_shader_sepxyz(GPUMaterial *mat,
return GPU_stack_link(mat, node, "separate_xyz", in, out);
}
-class MF_SeparateXYZ : public blender::fn::MultiFunction {
+class MF_SeparateXYZ : public fn::MultiFunction {
public:
MF_SeparateXYZ()
{
- static blender::fn::MFSignature signature = create_signature();
+ static fn::MFSignature signature = create_signature();
this->set_signature(&signature);
}
- static blender::fn::MFSignature create_signature()
+ static fn::MFSignature create_signature()
{
- blender::fn::MFSignatureBuilder signature{"Separate XYZ"};
- signature.single_input<blender::float3>("XYZ");
+ fn::MFSignatureBuilder signature{"Separate XYZ"};
+ signature.single_input<float3>("XYZ");
signature.single_output<float>("X");
signature.single_output<float>("Y");
signature.single_output<float>("Z");
return signature.build();
}
- void call(blender::IndexMask mask,
- blender::fn::MFParams params,
- blender::fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
- const blender::VArray<blender::float3> &vectors =
- params.readonly_single_input<blender::float3>(0, "XYZ");
- blender::MutableSpan<float> xs = params.uninitialized_single_output<float>(1, "X");
- blender::MutableSpan<float> ys = params.uninitialized_single_output<float>(2, "Y");
- blender::MutableSpan<float> zs = params.uninitialized_single_output<float>(3, "Z");
+ const VArray<float3> &vectors = params.readonly_single_input<float3>(0, "XYZ");
+ MutableSpan<float> xs = params.uninitialized_single_output<float>(1, "X");
+ MutableSpan<float> ys = params.uninitialized_single_output<float>(2, "Y");
+ MutableSpan<float> zs = params.uninitialized_single_output<float>(3, "Z");
for (int64_t i : mask) {
- blender::float3 xyz = vectors[i];
+ float3 xyz = vectors[i];
xs[i] = xyz.x;
ys[i] = xyz.y;
zs[i] = xyz.z;
@@ -64,7 +61,7 @@ class MF_SeparateXYZ : public blender::fn::MultiFunction {
}
};
-static void sh_node_sepxyz_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_sepxyz_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static MF_SeparateXYZ separate_fn;
builder.set_matching_fn(separate_fn);
@@ -106,10 +103,10 @@ static int gpu_shader_combxyz(GPUMaterial *mat,
return GPU_stack_link(mat, node, "combine_xyz", in, out);
}
-static void sh_node_combxyz_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_combxyz_build_multi_function(NodeMultiFunctionBuilder &builder)
{
- static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, blender::float3> fn{
- "Combine Vector", [](float x, float y, float z) { return blender::float3(x, y, z); }};
+ static fn::CustomMF_SI_SI_SI_SO<float, float, float, float3> fn{
+ "Combine Vector", [](float x, float y, float z) { return float3(x, y, z); }};
builder.set_matching_fn(fn);
}
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 66d1ace2222..cad9e1b33f2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
@@ -259,7 +259,7 @@ class BrickFunction : public fn::MultiFunction {
}
};
-static void sh_node_brick_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_brick_build_multi_function(NodeMultiFunctionBuilder &builder)
{
bNode &node = builder.node();
NodeTexBrick *tex = (NodeTexBrick *)node.storage;
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 047ae303260..b0e5639c893 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
@@ -61,9 +61,7 @@ class NodeTexChecker : public fn::MultiFunction {
return signature.build();
}
- void call(blender::IndexMask mask,
- fn::MFParams params,
- fn::MFContext UNUSED(context)) const override
+ void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
{
const VArray<float3> &vector = params.readonly_single_input<float3>(0, "Vector");
const VArray<ColorGeometry4f> &color1 = params.readonly_single_input<ColorGeometry4f>(
@@ -94,8 +92,7 @@ class NodeTexChecker : public fn::MultiFunction {
}
};
-static void sh_node_tex_checker_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_tex_checker_build_multi_function(NodeMultiFunctionBuilder &builder)
{
static NodeTexChecker fn;
builder.set_matching_fn(fn);
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 f92ad4d9fd0..8478cbd406b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
@@ -137,8 +137,7 @@ class GradientFunction : public fn::MultiFunction {
}
};
-static void sh_node_gradient_tex_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_gradient_tex_build_multi_function(NodeMultiFunctionBuilder &builder)
{
bNode &node = builder.node();
NodeTexGradient *tex = (NodeTexGradient *)node.storage;
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 982d80811fb..95c4a8b8e46 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
@@ -159,8 +159,7 @@ class MagicFunction : public fn::MultiFunction {
}
};
-static void sh_node_magic_tex_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_magic_tex_build_multi_function(NodeMultiFunctionBuilder &builder)
{
bNode &node = builder.node();
NodeTexMagic *tex = (NodeTexMagic *)node.storage;
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 8a672063943..c13ce3c3df3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
@@ -514,8 +514,7 @@ class MusgraveFunction : public fn::MultiFunction {
}
};
-static void sh_node_musgrave_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_musgrave_build_multi_function(NodeMultiFunctionBuilder &builder)
{
bNode &node = builder.node();
NodeTexMusgrave *tex = (NodeTexMusgrave *)node.storage;
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 9b27c805a64..87fb1aeac29 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
@@ -232,7 +232,7 @@ class NoiseFunction : public fn::MultiFunction {
}
};
-static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const NodeTexNoise &storage = node_storage(builder.node());
builder.construct_and_set_matching_fn<NoiseFunction>(storage.dimensions);
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
index d4a0c092acd..f5a4d087dbd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
@@ -10,6 +10,8 @@
#include "UI_interface.h"
#include "UI_resources.h"
+#include "NOD_socket_search_link.hh"
+
namespace blender::nodes::node_shader_tex_sky_cc {
static void node_declare(NodeDeclarationBuilder &b)
@@ -229,6 +231,24 @@ static void node_shader_update_sky(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1));
}
+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());
+ return;
+ }
+ if (params.node_tree().typeinfo->validate_link(
+ static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
+ params.add_item(IFACE_("Vector"), [](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("ShaderNodeTexSky");
+ NodeTexSky *tex = (NodeTexSky *)node.storage;
+ tex->sun_disc = false;
+ params.update_and_connect_available_socket(node, "Vector");
+ });
+ }
+}
+
} // namespace blender::nodes::node_shader_tex_sky_cc
/* node type definition */
@@ -247,6 +267,7 @@ void register_node_type_sh_tex_sky()
node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_sky);
/* Remove vector input for Nishita sky model. */
node_type_update(&ntype, file_ns::node_shader_update_sky);
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
nodeRegisterType(&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 1d6d16fa5e1..fc6a5ef72b6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
@@ -1312,7 +1312,7 @@ class VoronoiEdgeFunction : public fn::MultiFunction {
}
};
-static void sh_node_voronoi_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_voronoi_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const NodeTexVoronoi &storage = node_storage(builder.node());
bool minowski =
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 68668fbe5be..ad24224dc7f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
@@ -204,8 +204,7 @@ class WaveFunction : public fn::MultiFunction {
}
};
-static void sh_node_wave_tex_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_wave_tex_build_multi_function(NodeMultiFunctionBuilder &builder)
{
bNode &node = builder.node();
NodeTexWave *tex = (NodeTexWave *)node.storage;
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 0e2321b9cf9..6d4c491046b 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
@@ -174,7 +174,7 @@ class WhiteNoiseFunction : public fn::MultiFunction {
}
};
-static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_noise_build_multi_function(NodeMultiFunctionBuilder &builder)
{
bNode &node = builder.node();
builder.construct_and_set_matching_fn<WhiteNoiseFunction>((int)node.custom1);
diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc
index a1e2565aec1..362cdf58052 100644
--- a/source/blender/nodes/shader/nodes/node_shader_value.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_value.cc
@@ -24,11 +24,11 @@ static int gpu_shader_value(GPUMaterial *mat,
return GPU_stack_link(mat, node, "set_value", in, out, link);
}
-static void sh_node_value_build_multi_function(blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_value_build_multi_function(NodeMultiFunctionBuilder &builder)
{
const bNodeSocket *bsocket = (bNodeSocket *)builder.node().outputs.first;
const bNodeSocketValueFloat *value = (const bNodeSocketValueFloat *)bsocket->default_value;
- builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value);
+ builder.construct_and_set_matching_fn<fn::CustomMF_Constant<float>>(value->value);
}
} // namespace blender::nodes::node_shader_value_cc
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 49765f797c5..02a3552704e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
@@ -225,27 +225,25 @@ static void node_shader_update_vector_math(bNodeTree *ntree, bNode *node)
}
}
-static const blender::fn::MultiFunction *get_multi_function(bNode &node)
+static const fn::MultiFunction *get_multi_function(bNode &node)
{
- using blender::float3;
-
NodeVectorMathOperation operation = NodeVectorMathOperation(node.custom1);
- const blender::fn::MultiFunction *multi_fn = nullptr;
+ const fn::MultiFunction *multi_fn = nullptr;
- 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.c_str(), function};
- multi_fn = &fn;
- });
+ try_dispatch_float_math_fl3_fl3_to_fl3(operation,
+ [&](auto function, const FloatMathOperationInfo &info) {
+ static fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{
+ info.title_case_name.c_str(), function};
+ multi_fn = &fn;
+ });
if (multi_fn != nullptr) {
return multi_fn;
}
- 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{
+ try_dispatch_float_math_fl3_fl3_fl3_to_fl3(
+ operation, [&](auto function, const FloatMathOperationInfo &info) {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
info.title_case_name.c_str(), function};
multi_fn = &fn;
});
@@ -253,9 +251,9 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
return multi_fn;
}
- 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{
+ try_dispatch_float_math_fl3_fl3_fl_to_fl3(
+ operation, [&](auto function, const FloatMathOperationInfo &info) {
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
info.title_case_name.c_str(), function};
multi_fn = &fn;
});
@@ -263,40 +261,38 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
return multi_fn;
}
- 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.c_str(), function};
- multi_fn = &fn;
- });
+ try_dispatch_float_math_fl3_fl3_to_fl(operation,
+ [&](auto function, const FloatMathOperationInfo &info) {
+ static fn::CustomMF_SI_SI_SO<float3, float3, float> fn{
+ info.title_case_name.c_str(), function};
+ multi_fn = &fn;
+ });
if (multi_fn != nullptr) {
return multi_fn;
}
- 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.c_str(), function};
- multi_fn = &fn;
- });
+ try_dispatch_float_math_fl3_fl_to_fl3(operation,
+ [&](auto function, const FloatMathOperationInfo &info) {
+ static fn::CustomMF_SI_SI_SO<float3, float, float3> fn{
+ info.title_case_name.c_str(), function};
+ multi_fn = &fn;
+ });
if (multi_fn != nullptr) {
return multi_fn;
}
- 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.c_str(),
- function};
+ try_dispatch_float_math_fl3_to_fl3(
+ operation, [&](auto function, const FloatMathOperationInfo &info) {
+ static fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
return multi_fn;
}
- 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.c_str(),
- function};
+ try_dispatch_float_math_fl3_to_fl(
+ operation, [&](auto function, const FloatMathOperationInfo &info) {
+ static fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name.c_str(), function};
multi_fn = &fn;
});
if (multi_fn != nullptr) {
@@ -306,10 +302,9 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
return nullptr;
}
-static void sh_node_vector_math_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_vector_math_build_multi_function(NodeMultiFunctionBuilder &builder)
{
- const blender::fn::MultiFunction *fn = get_multi_function(builder.node());
+ const fn::MultiFunction *fn = get_multi_function(builder.node());
builder.set_matching_fn(fn);
}
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 b8c44b527b5..a041492fb13 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
@@ -17,9 +17,15 @@ static void sh_node_vector_rotate_declare(NodeDeclarationBuilder &b)
b.is_function_node();
b.add_input<decl::Vector>(N_("Vector")).min(0.0f).max(1.0f).hide_value();
b.add_input<decl::Vector>(N_("Center"));
- b.add_input<decl::Vector>(N_("Axis")).min(-1.0f).max(1.0f).default_value({0.0f, 0.0f, 1.0f});
+ b.add_input<decl::Vector>(N_("Axis"))
+ .min(-1.0f)
+ .max(1.0f)
+ .default_value({0.0f, 0.0f, 1.0f})
+ .make_available([](bNode &node) { node.custom1 = NODE_VECTOR_ROTATE_TYPE_AXIS; });
b.add_input<decl::Float>(N_("Angle")).subtype(PROP_ANGLE);
- b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER);
+ b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).make_available([](bNode &node) {
+ node.custom1 = NODE_VECTOR_ROTATE_TYPE_EULER_XYZ;
+ });
b.add_output<decl::Vector>(N_("Vector"));
}
@@ -63,8 +69,6 @@ static int gpu_shader_vector_rotate(GPUMaterial *mat,
return 0;
}
-using blender::float3;
-
static float3 sh_node_vector_rotate_around_axis(const float3 vector,
const float3 center,
const float3 axis,
@@ -92,7 +96,7 @@ static float3 sh_node_vector_rotate_euler(const float3 vector,
return result + center;
}
-static const blender::fn::MultiFunction *get_multi_function(bNode &node)
+static const fn::MultiFunction *get_multi_function(bNode &node)
{
bool invert = node.custom2;
const int mode = node.custom1;
@@ -100,13 +104,13 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
switch (mode) {
case NODE_VECTOR_ROTATE_TYPE_AXIS: {
if (invert) {
- static blender::fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float3, float, float3> fn{
+ static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float3, float, float3> fn{
"Rotate Axis", [](float3 in, float3 center, float3 axis, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
}};
return &fn;
}
- static blender::fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float3, float, float3> fn{
+ static fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float3, float, float3> fn{
"Rotate Axis", [](float3 in, float3 center, float3 axis, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, angle);
}};
@@ -115,13 +119,13 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
case NODE_VECTOR_ROTATE_TYPE_AXIS_X: {
float3 axis = float3(1.0f, 0.0f, 0.0f);
if (invert) {
- static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
"Rotate X-Axis", [=](float3 in, float3 center, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
}};
return &fn;
}
- static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
"Rotate X-Axis", [=](float3 in, float3 center, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, angle);
}};
@@ -130,13 +134,13 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
case NODE_VECTOR_ROTATE_TYPE_AXIS_Y: {
float3 axis = float3(0.0f, 1.0f, 0.0f);
if (invert) {
- static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
"Rotate Y-Axis", [=](float3 in, float3 center, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
}};
return &fn;
}
- static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
"Rotate Y-Axis", [=](float3 in, float3 center, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, angle);
}};
@@ -145,13 +149,13 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
case NODE_VECTOR_ROTATE_TYPE_AXIS_Z: {
float3 axis = float3(0.0f, 0.0f, 1.0f);
if (invert) {
- static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
"Rotate Z-Axis", [=](float3 in, float3 center, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, -angle);
}};
return &fn;
}
- static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{
"Rotate Z-Axis", [=](float3 in, float3 center, float angle) {
return sh_node_vector_rotate_around_axis(in, center, axis, angle);
}};
@@ -159,13 +163,13 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
}
case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: {
if (invert) {
- static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
"Rotate Euler", [](float3 in, float3 center, float3 rotation) {
return sh_node_vector_rotate_euler(in, center, rotation, true);
}};
return &fn;
}
- static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
+ static fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{
"Rotate Euler", [](float3 in, float3 center, float3 rotation) {
return sh_node_vector_rotate_euler(in, center, rotation, false);
}};
@@ -177,10 +181,9 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node)
}
}
-static void sh_node_vector_rotate_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
+static void sh_node_vector_rotate_build_multi_function(NodeMultiFunctionBuilder &builder)
{
- const blender::fn::MultiFunction *fn = get_multi_function(builder.node());
+ const fn::MultiFunction *fn = get_multi_function(builder.node());
builder.set_matching_fn(fn);
}
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index ccd483083ef..9ceff9b84b6 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -1050,7 +1050,8 @@ static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
}
PyDoc_STRVAR(bpy_bmesh_from_object_doc,
- ".. method:: from_object(object, depsgraph, cage=False, face_normals=True)\n"
+ ".. method:: from_object(object, depsgraph, cage=False, face_normals=True, "
+ "vertex_normals=True)\n"
"\n"
" Initialize this bmesh from existing object data-block (only meshes are currently "
"supported).\n"
@@ -1060,10 +1061,12 @@ PyDoc_STRVAR(bpy_bmesh_from_object_doc,
" :arg cage: Get the mesh as a deformed cage.\n"
" :type cage: boolean\n"
" :arg face_normals: Calculate face normals.\n"
+ " :arg vertex_normals: Calculate vertex normals.\n"
" :type face_normals: boolean\n");
static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject *kw)
{
- static const char *kwlist[] = {"object", "depsgraph", "cage", "face_normals", NULL};
+ static const char *kwlist[] = {
+ "object", "depsgraph", "cage", "face_normals", "vertex_normals", NULL};
PyObject *py_object;
PyObject *py_depsgraph;
Object *ob, *ob_eval;
@@ -1073,6 +1076,7 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
BMesh *bm;
bool use_cage = false;
bool use_fnorm = true;
+ bool use_vert_normal = true;
const CustomData_MeshMasks data_masks = CD_MASK_BMESH;
BPY_BM_CHECK_OBJ(self);
@@ -1086,7 +1090,9 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
PyC_ParseBool,
&use_cage,
PyC_ParseBool,
- &use_fnorm) ||
+ &use_fnorm,
+ PyC_ParseBool,
+ &use_vert_normal) ||
!(ob = PyC_RNA_AsPointer(py_object, "Object")) ||
!(depsgraph = PyC_RNA_AsPointer(py_depsgraph, "Depsgraph"))) {
return NULL;
@@ -1137,6 +1143,7 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
me_eval,
(&(struct BMeshFromMeshParams){
.calc_face_normal = use_fnorm,
+ .calc_vert_normal = use_vert_normal,
}));
if (need_free) {
@@ -1148,7 +1155,8 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject
PyDoc_STRVAR(
bpy_bmesh_from_mesh_doc,
- ".. method:: from_mesh(mesh, face_normals=True, use_shape_key=False, shape_key_index=0)\n"
+ ".. method:: from_mesh(mesh, face_normals=True, vertex_normals=True, use_shape_key=False, "
+ "shape_key_index=0)\n"
"\n"
" Initialize this bmesh from existing mesh datablock.\n"
"\n"
@@ -1168,11 +1176,13 @@ PyDoc_STRVAR(
"mesh won't be added.\n");
static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw)
{
- static const char *kwlist[] = {"mesh", "face_normals", "use_shape_key", "shape_key_index", NULL};
+ static const char *kwlist[] = {
+ "mesh", "face_normals", "vertex_normals", "use_shape_key", "shape_key_index", NULL};
BMesh *bm;
PyObject *py_mesh;
Mesh *me;
bool use_fnorm = true;
+ bool use_vert_normal = true;
bool use_shape_key = false;
int shape_key_index = 0;
@@ -1186,6 +1196,8 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *
PyC_ParseBool,
&use_fnorm,
PyC_ParseBool,
+ &use_vert_normal,
+ PyC_ParseBool,
&use_shape_key,
&shape_key_index) ||
!(me = PyC_RNA_AsPointer(py_mesh, "Mesh"))) {
@@ -1198,6 +1210,7 @@ static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *
me,
(&(struct BMeshFromMeshParams){
.calc_face_normal = use_fnorm,
+ .calc_vert_normal = use_vert_normal,
.use_shapekey = use_shape_key,
.active_shapekey = shape_key_index + 1,
}));
diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c
index 3fbfd1655c5..9e45105d105 100644
--- a/source/blender/python/generic/blf_py_api.c
+++ b/source/blender/python/generic/blf_py_api.c
@@ -396,41 +396,41 @@ static PyObject *py_blf_shadow_offset(PyObject *UNUSED(self), PyObject *args)
}
PyDoc_STRVAR(py_blf_load_doc,
- ".. function:: load(filename)\n"
+ ".. function:: load(filepath)\n"
"\n"
" Load a new font.\n"
"\n"
- " :arg filename: the filename of the font.\n"
- " :type filename: string\n"
+ " :arg filepath: the filepath of the font.\n"
+ " :type filepath: string\n"
" :return: the new font's fontid or -1 if there was an error.\n"
" :rtype: integer\n");
static PyObject *py_blf_load(PyObject *UNUSED(self), PyObject *args)
{
- const char *filename;
+ const char *filepath;
- if (!PyArg_ParseTuple(args, "s:blf.load", &filename)) {
+ if (!PyArg_ParseTuple(args, "s:blf.load", &filepath)) {
return NULL;
}
- return PyLong_FromLong(BLF_load(filename));
+ return PyLong_FromLong(BLF_load(filepath));
}
PyDoc_STRVAR(py_blf_unload_doc,
- ".. function:: unload(filename)\n"
+ ".. function:: unload(filepath)\n"
"\n"
" Unload an existing font.\n"
"\n"
- " :arg filename: the filename of the font.\n"
- " :type filename: string\n");
+ " :arg filepath: the filepath of the font.\n"
+ " :type filepath: string\n");
static PyObject *py_blf_unload(PyObject *UNUSED(self), PyObject *args)
{
- const char *filename;
+ const char *filepath;
- if (!PyArg_ParseTuple(args, "s:blf.unload", &filename)) {
+ if (!PyArg_ParseTuple(args, "s:blf.unload", &filepath)) {
return NULL;
}
- BLF_unload(filename);
+ BLF_unload(filepath);
Py_RETURN_NONE;
}
diff --git a/source/blender/python/gpu/gpu_py_state.c b/source/blender/python/gpu/gpu_py_state.c
index e3ffd3cc823..fb69bb316c4 100644
--- a/source/blender/python/gpu/gpu_py_state.c
+++ b/source/blender/python/gpu/gpu_py_state.c
@@ -347,7 +347,7 @@ static PyObject *pygpu_state_program_point_size_set(PyObject *UNUSED(self), PyOb
PyDoc_STRVAR(pygpu_state_framebuffer_active_get_doc,
".. function:: framebuffer_active_get(enable)\n"
"\n"
- " Return the active framefuffer in context.\n");
+ " Return the active frame-buffer in context.\n");
static PyObject *pygpu_state_framebuffer_active_get(PyObject *UNUSED(self))
{
GPUFrameBuffer *fb = GPU_framebuffer_active_get();
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index a35f03f9872..f813a006c7e 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -224,6 +224,10 @@ if(WITH_IMAGE_TIFF)
add_definitions(-DWITH_TIFF)
endif()
+if(WITH_WEBP)
+ add_definitions(-DWITH_WEBP)
+endif()
+
if(WITH_INPUT_NDOF)
add_definitions(-DWITH_INPUT_NDOF)
endif()
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 85a477599cd..6f278c1c771 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -36,6 +36,11 @@
#include "../generic/py_capi_rna.h"
#include "../generic/py_capi_utils.h"
+/* Disabled duplicating strings because the array can still be freed and
+ * the strings from it referenced, for now we can't support dynamically
+ * created strings from Python. */
+// #define USE_ENUM_COPY_STRINGS
+
/* -------------------------------------------------------------------- */
/** \name Shared Enums & Doc-Strings
* \{ */
@@ -1855,7 +1860,7 @@ static bool py_long_as_int(PyObject *py_long, int *r_int)
return false;
}
-#if 0
+#ifdef USE_ENUM_COPY_STRINGS
/* copies orig to buf, then sets orig to buf, returns copy length */
static size_t strswapbufcpy(char *buf, const char **orig)
{
@@ -1897,8 +1902,10 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast,
PyObject *item;
const Py_ssize_t seq_len = PySequence_Fast_GET_SIZE(seq_fast);
PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast);
- Py_ssize_t totbuf = 0;
int i;
+#ifdef USE_ENUM_COPY_STRINGS
+ Py_ssize_t totbuf = 0;
+#endif
short default_used = 0;
const char *default_str_cmp = NULL;
int default_int_cmp = 0;
@@ -1988,8 +1995,10 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast,
items[i] = tmp;
- /* calculate combine string length */
+#ifdef USE_ENUM_COPY_STRINGS
+ /* Calculate combine string length. */
totbuf += id_str_size + name_str_size + desc_str_size + 3; /* 3 is for '\0's */
+#endif
}
else if (item == Py_None) {
/* Only set since the rest is cleared. */
@@ -2034,13 +2043,9 @@ static const EnumPropertyItem *enum_items_from_py(PyObject *seq_fast,
}
}
- /* disabled duplicating strings because the array can still be freed and
- * the strings from it referenced, for now we can't support dynamically
- * created strings from python. */
-#if 0
- /* this would all work perfectly _but_ the python strings may be freed
- * immediately after use, so we need to duplicate them, ugh.
- * annoying because it works most of the time without this. */
+#ifdef USE_ENUM_COPY_STRINGS
+ /* This would all work perfectly _but_ the python strings may be freed immediately after use,
+ * so we need to duplicate them, ugh. annoying because it works most of the time without this. */
{
EnumPropertyItem *items_dup = MEM_mallocN((sizeof(EnumPropertyItem) * (seq_len + 1)) +
(sizeof(char) * totbuf),
diff --git a/source/blender/render/RE_engine.h b/source/blender/render/RE_engine.h
index 578df1858c9..e56e7b8d2e4 100644
--- a/source/blender/render/RE_engine.h
+++ b/source/blender/render/RE_engine.h
@@ -169,10 +169,10 @@ void RE_engine_free(RenderEngine *engine);
* 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);
+ struct RenderLayer *layer, struct ReportList *reports, const char *filepath, int x, int y);
void RE_result_load_from_file(struct RenderResult *result,
struct ReportList *reports,
- const char *filename);
+ const char *filepath);
struct RenderResult *RE_engine_begin_result(
RenderEngine *engine, int x, int y, int w, int h, const char *layername, const char *viewname);
@@ -253,6 +253,7 @@ void RE_engine_render_context_disable(struct RenderEngine *engine);
/* Engine Types */
void RE_engines_init(void);
+void RE_engines_init_experimental(void);
void RE_engines_exit(void);
void RE_engines_register(RenderEngineType *render_type);
diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h
index f532c705534..0a8668221ad 100644
--- a/source/blender/render/RE_pipeline.h
+++ b/source/blender/render/RE_pipeline.h
@@ -62,8 +62,8 @@ typedef struct RenderView {
typedef struct RenderPass {
struct RenderPass *next, *prev;
int channels;
- char name[64]; /* amount defined in openexr_multi.h */
- char chan_id[8]; /* amount defined in openexr_multi.h */
+ char name[64]; /* amount defined in IMB_openexr.h */
+ char chan_id[8]; /* amount defined in IMB_openexr.h */
float *rect;
int rectx, recty;
@@ -123,8 +123,8 @@ typedef struct RenderResult {
ListBase views; /* RenderView */
/* allowing live updates: */
- volatile rcti renrect;
- volatile RenderLayer *renlay;
+ rcti renrect;
+ RenderLayer *renlay;
/* for render results in Image, verify validity for sequences */
int framenr;
@@ -242,15 +242,23 @@ void RE_AcquiredResultGet32(struct Render *re,
unsigned int *rect,
int view_id);
+void RE_render_result_full_channel_name(char *fullname,
+ const char *layname,
+ const char *passname,
+ const char *viewname,
+ const char *chan_id,
+ const int channel);
+
+struct ImBuf *RE_render_result_rect_to_ibuf(struct RenderResult *rr,
+ const struct ImageFormatData *imf,
+ const float dither,
+ const int view_id);
void RE_render_result_rect_from_ibuf(struct RenderResult *rr,
- struct RenderData *rd,
- struct ImBuf *ibuf,
- int view_id);
+ const struct ImBuf *ibuf,
+ const int view_id);
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
-float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl,
- const char *name,
- const char *viewname);
+float *RE_RenderLayerGetPass(struct RenderLayer *rl, const char *name, const char *viewname);
bool RE_HasSingleLayer(struct Render *re);
@@ -307,11 +315,6 @@ void RE_GetViewPlane(struct Render *re, rctf *r_viewplane, rcti *r_disprect);
*/
void RE_init_threadcount(Render *re);
-bool RE_WriteRenderViewsImage(struct ReportList *reports,
- struct RenderResult *rr,
- struct Scene *scene,
- bool stamp,
- char *name);
bool RE_WriteRenderViewsMovie(struct ReportList *reports,
struct RenderResult *rr,
struct Scene *scene,
@@ -336,6 +339,7 @@ void RE_RenderFrame(struct Render *re,
struct ViewLayer *single_layer,
struct Object *camera_override,
int frame,
+ float subframe,
bool write_still);
/**
* A version of #RE_RenderFrame that saves images to disk.
@@ -373,16 +377,7 @@ 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,
- struct ImageFormatData *imf,
- const char *view,
- int layer);
+
struct RenderResult *RE_MultilayerConvert(
void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty);
@@ -399,7 +394,7 @@ void RE_display_clear_cb(struct Render *re,
void (*f)(void *handle, RenderResult *rr));
void RE_display_update_cb(struct Render *re,
void *handle,
- void (*f)(void *handle, RenderResult *rr, volatile struct rcti *rect));
+ void (*f)(void *handle, RenderResult *rr, struct rcti *rect));
void RE_stats_draw_cb(struct Render *re, void *handle, void (*f)(void *handle, RenderStats *rs));
void RE_progress_cb(struct Render *re, void *handle, void (*f)(void *handle, float));
void RE_draw_lock_cb(struct Render *re, void *handle, void (*f)(void *handle, bool lock));
@@ -428,13 +423,13 @@ int RE_seq_render_active(struct Scene *scene, struct RenderData *rd);
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,
+struct RenderPass *RE_pass_find_by_name(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,
+struct RenderPass *RE_pass_find_by_type(struct RenderLayer *rl,
int passtype,
const char *viewname);
@@ -464,9 +459,9 @@ bool RE_allow_render_generic_object(struct Object *ob);
/******* defined in render_result.c *********/
-bool RE_HasCombinedLayer(RenderResult *res);
-bool RE_HasFloatPixels(RenderResult *res);
-bool RE_RenderResult_is_stereo(RenderResult *res);
+bool RE_HasCombinedLayer(const RenderResult *res);
+bool RE_HasFloatPixels(const RenderResult *res);
+bool RE_RenderResult_is_stereo(const RenderResult *res);
struct RenderView *RE_RenderViewGetById(struct RenderResult *rr, int view_id);
struct RenderView *RE_RenderViewGetByName(struct RenderResult *rr, const char *viewname);
diff --git a/source/blender/render/RE_texture_margin.h b/source/blender/render/RE_texture_margin.h
index d297ca19404..85bd06b9940 100644
--- a/source/blender/render/RE_texture_margin.h
+++ b/source/blender/render/RE_texture_margin.h
@@ -23,7 +23,7 @@ struct Mesh;
* \param mask: pixels with a mask value of 1 are not written to.
* \param margin: the size of the margin in pixels.
* \param me: the mesh to use the polygons of.
- * \param mloopuv: the uv data to use.
+ * \param uv_layer: The UV layer to use.
*/
void RE_generate_texturemargin_adjacentfaces(
struct ImBuf *ibuf, char *mask, const int margin, struct Mesh const *me, char const *uv_layer);
diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c
index ae5ffdfc232..3a7ac22dc1f 100644
--- a/source/blender/render/intern/engine.c
+++ b/source/blender/render/intern/engine.c
@@ -59,6 +59,11 @@ void RE_engines_init(void)
DRW_engines_register();
}
+void RE_engines_init_experimental()
+{
+ DRW_engines_register_experimental();
+}
+
void RE_engines_exit(void)
{
RenderEngineType *type, *next;
diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c
index a5c13c26590..c573d4feed1 100644
--- a/source/blender/render/intern/multires_bake.c
+++ b/source/blender/render/intern/multires_bake.c
@@ -66,7 +66,7 @@ typedef struct {
MLoopUV *mloopuv;
const MLoopTri *mlooptri;
float *pvtangent;
- const float *precomputed_normals;
+ const float (*precomputed_normals)[3];
int w, h;
int tri_index;
DerivedMesh *lores_dm, *hires_dm;
@@ -106,26 +106,26 @@ typedef struct BakeImBufuserData {
} BakeImBufuserData;
static void multiresbake_get_normal(const MResolvePixelData *data,
- float norm[],
const int tri_num,
- const int vert_index)
+ const int vert_index,
+ float r_normal[3])
{
const int poly_index = data->mlooptri[tri_num].poly;
const MPoly *mp = &data->mpoly[poly_index];
const bool smoothnormal = (mp->flag & ME_SMOOTH) != 0;
- if (!smoothnormal) { /* flat */
+ if (smoothnormal) {
+ const int vi = data->mloop[data->mlooptri[tri_num].tri[vert_index]].v;
+ copy_v3_v3(r_normal, data->vert_normals[vi]);
+ }
+ else {
if (data->precomputed_normals) {
- copy_v3_v3(norm, &data->precomputed_normals[poly_index]);
+ copy_v3_v3(r_normal, data->precomputed_normals[poly_index]);
}
else {
- BKE_mesh_calc_poly_normal(mp, &data->mloop[mp->loopstart], data->mvert, norm);
+ BKE_mesh_calc_poly_normal(mp, &data->mloop[mp->loopstart], data->mvert, r_normal);
}
}
- else {
- const int vi = data->mloop[data->mlooptri[tri_num].tri[vert_index]].v;
- copy_v3_v3(norm, data->vert_normals[vi]);
- }
}
static void init_bake_rast(MBakeRast *bake_rast,
@@ -160,9 +160,9 @@ static void flush_pixel(const MResolvePixelData *data, const int x, const int y)
st1 = data->mloopuv[data->mlooptri[data->tri_index].tri[1]].uv;
st2 = data->mloopuv[data->mlooptri[data->tri_index].tri[2]].uv;
- multiresbake_get_normal(data, no0, data->tri_index, 0); /* can optimize these 3 into one call */
- multiresbake_get_normal(data, no1, data->tri_index, 1);
- multiresbake_get_normal(data, no2, data->tri_index, 2);
+ multiresbake_get_normal(data, data->tri_index, 0, no0); /* can optimize these 3 into one call */
+ multiresbake_get_normal(data, data->tri_index, 1, no1);
+ multiresbake_get_normal(data, data->tri_index, 2, no2);
resolve_tri_uv_v2(fUV, st, st0, st1, st2);
@@ -542,7 +542,7 @@ static void do_multires_bake(MultiresBakeRender *bkr,
handle->data.mlooptri = mlooptri;
handle->data.mloop = mloop;
handle->data.pvtangent = pvtangent;
- handle->data.precomputed_normals = (float *)poly_normals; /* don't strictly need this */
+ handle->data.precomputed_normals = poly_normals; /* don't strictly need this */
handle->data.w = ibuf->x;
handle->data.h = ibuf->y;
handle->data.lores_dm = dm;
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index aa006713755..cf400bdfc77 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -44,6 +44,8 @@
#include "BKE_context.h" /* XXX needed by wm_window.h */
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
+#include "BKE_image_save.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_lib_remap.h"
@@ -166,7 +168,7 @@ static void result_nothing(void *UNUSED(arg), RenderResult *UNUSED(rr))
}
static void result_rcti_nothing(void *UNUSED(arg),
RenderResult *UNUSED(rr),
- volatile struct rcti *UNUSED(rect))
+ struct rcti *UNUSED(rect))
{
}
static void current_scene_nothing(void *UNUSED(arg), Scene *UNUSED(scene))
@@ -222,47 +224,12 @@ static void stats_background(void *UNUSED(arg), RenderStats *rs)
fflush(stdout);
}
-static void render_print_save_message(ReportList *reports, const char *name, int ok, int err)
-{
- if (ok) {
- /* no need to report, just some helpful console info */
- printf("Saved: '%s'\n", name);
- }
- else {
- /* report on error since users will want to know what failed */
- BKE_reportf(reports, RPT_ERROR, "Render error (%s) cannot save: '%s'", strerror(err), name);
- }
-}
-
-static int render_imbuf_write_stamp_test(ReportList *reports,
- Scene *scene,
- struct RenderResult *rr,
- ImBuf *ibuf,
- const char *name,
- const ImageFormatData *imf,
- bool stamp)
-{
- int ok;
-
- if (stamp) {
- /* writes the name of the individual cameras */
- ok = BKE_imbuf_write_stamp(scene, rr, ibuf, name, imf);
- }
- else {
- ok = BKE_imbuf_write(ibuf, name, imf);
- }
-
- render_print_save_message(reports, name, ok, errno);
-
- return ok;
-}
-
void RE_FreeRenderResult(RenderResult *rr)
{
render_result_free(rr);
}
-float *RE_RenderLayerGetPass(volatile RenderLayer *rl, const char *name, const char *viewname)
+float *RE_RenderLayerGetPass(RenderLayer *rl, const char *name, const char *viewname)
{
RenderPass *rpass = RE_pass_find_by_name(rl, name, viewname);
return rpass ? rpass->rect : NULL;
@@ -711,11 +678,9 @@ static void re_init_resolution(Render *re, Render *source, int winx, int winy, r
re->winx = winx;
re->winy = winy;
if (source && (source->r.mode & R_BORDER)) {
- /* eeh, doesn't seem original bordered disprect is storing anywhere
- * after insertion on black happening in do_render_engine(),
- * so for now simply re-calculate disprect using border from source
- * renderer (sergey)
- */
+ /* NOTE(@sergey): doesn't seem original bordered `disprect` is storing anywhere
+ * after insertion on black happening in #do_render_engine(),
+ * so for now simply re-calculate `disprect` using border from source renderer. */
re->disprect.xmin = source->r.border.xmin * winx;
re->disprect.xmax = source->r.border.xmax * winx;
@@ -890,7 +855,7 @@ void RE_display_clear_cb(Render *re, void *handle, void (*f)(void *handle, Rende
}
void RE_display_update_cb(Render *re,
void *handle,
- void (*f)(void *handle, RenderResult *rr, volatile rcti *rect))
+ void (*f)(void *handle, RenderResult *rr, rcti *rect))
{
re->display_update = f;
re->duh = handle;
@@ -1247,14 +1212,8 @@ static void do_render_compositor(Render *re)
RenderView *rv;
for (rv = re->result->views.first; rv; rv = rv->next) {
- ntreeCompositExecTree(re->pipeline_scene_eval,
- ntree,
- &re->r,
- true,
- G.background == 0,
- &re->scene->view_settings,
- &re->scene->display_settings,
- rv->name);
+ ntreeCompositExecTree(
+ re->pipeline_scene_eval, ntree, &re->r, true, G.background == 0, rv->name);
}
ntree->stats_draw = NULL;
@@ -1386,7 +1345,7 @@ static void do_render_sequencer(Render *re)
if (ibuf_arr[view_id]) {
/* copy ibuf into combined pixel rect */
- RE_render_result_rect_from_ibuf(rr, &re->r, ibuf_arr[view_id], view_id);
+ RE_render_result_rect_from_ibuf(rr, ibuf_arr[view_id], view_id);
if (ibuf_arr[view_id]->metadata && (re->r.stamp & R_STAMP_STRIPMETA)) {
/* ensure render stamp info first */
@@ -1844,7 +1803,8 @@ void RE_RenderFrame(Render *re,
Scene *scene,
ViewLayer *single_layer,
Object *camera_override,
- int frame,
+ const int frame,
+ const float subframe,
const bool write_still)
{
render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
@@ -1854,6 +1814,7 @@ void RE_RenderFrame(Render *re,
G.is_rendering = true;
scene->r.cfra = frame;
+ scene->r.subframe = subframe;
if (render_init_from_main(re, &scene->r, bmain, scene, single_layer, camera_override, 0, 0)) {
const RenderData rd = scene->r;
@@ -1978,129 +1939,6 @@ void RE_RenderFreestyleExternal(Render *re)
/** \name Read/Write Render Result (Images & Movies)
* \{ */
-bool RE_WriteRenderViewsImage(
- ReportList *reports, RenderResult *rr, Scene *scene, const bool stamp, char *name)
-{
- bool ok = true;
- RenderData *rd = &scene->r;
-
- if (!rr) {
- return false;
- }
-
- bool is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2;
- bool is_exr_rr = ELEM(rd->im_format.imtype, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER) &&
- RE_HasFloatPixels(rr);
-
- if (rd->im_format.views_format == R_IMF_VIEWS_MULTIVIEW && is_exr_rr) {
- ok = RE_WriteRenderResult(reports, rr, name, &rd->im_format, NULL, -1);
- render_print_save_message(reports, name, ok, errno);
- }
-
- /* mono, legacy code */
- else if (is_mono || (rd->im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
- RenderView *rv;
- int view_id;
- char filepath[FILE_MAX];
-
- BLI_strncpy(filepath, name, sizeof(filepath));
-
- for (view_id = 0, rv = rr->views.first; rv; rv = rv->next, view_id++) {
- if (!is_mono) {
- BKE_scene_multiview_view_filepath_get(&scene->r, filepath, rv->name, name);
- }
-
- if (is_exr_rr) {
- ok = RE_WriteRenderResult(reports, rr, name, &rd->im_format, rv->name, -1);
- render_print_save_message(reports, name, ok, errno);
-
- /* optional preview images for exr */
- if (ok && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
- ImageFormatData imf = rd->im_format;
- imf.imtype = R_IMF_IMTYPE_JPEG90;
-
- if (BLI_path_extension_check(name, ".exr")) {
- name[strlen(name) - 4] = 0;
- }
- BKE_image_path_ensure_ext_from_imformat(name, &imf);
-
- ImBuf *ibuf = render_result_rect_to_ibuf(rr, rd, view_id);
- ibuf->planes = 24;
- IMB_colormanagement_imbuf_for_write(
- ibuf, true, false, &scene->view_settings, &scene->display_settings, &imf);
-
- ok = render_imbuf_write_stamp_test(reports, scene, rr, ibuf, name, &imf, stamp);
-
- IMB_freeImBuf(ibuf);
- }
- }
- else {
- ImBuf *ibuf = render_result_rect_to_ibuf(rr, rd, view_id);
-
- IMB_colormanagement_imbuf_for_write(
- ibuf, true, false, &scene->view_settings, &scene->display_settings, &rd->im_format);
-
- ok = render_imbuf_write_stamp_test(reports, scene, rr, ibuf, name, &rd->im_format, stamp);
-
- /* imbuf knows which rects are not part of ibuf */
- IMB_freeImBuf(ibuf);
- }
- }
- }
- else { /* R_IMF_VIEWS_STEREO_3D */
- BLI_assert(scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D);
-
- if (rd->im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
- printf("Stereo 3D not supported for MultiLayer image: %s\n", name);
- }
- else {
- ImBuf *ibuf_arr[3] = {NULL};
- const char *names[2] = {STEREO_LEFT_NAME, STEREO_RIGHT_NAME};
- int i;
-
- for (i = 0; i < 2; i++) {
- int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
- ibuf_arr[i] = render_result_rect_to_ibuf(rr, rd, view_id);
- IMB_colormanagement_imbuf_for_write(ibuf_arr[i],
- true,
- false,
- &scene->view_settings,
- &scene->display_settings,
- &scene->r.im_format);
- IMB_prepare_write_ImBuf(IMB_isfloat(ibuf_arr[i]), ibuf_arr[i]);
- }
-
- ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]);
-
- ok = render_imbuf_write_stamp_test(
- reports, scene, rr, ibuf_arr[2], name, &rd->im_format, stamp);
-
- /* optional preview images for exr */
- if (ok && is_exr_rr && (rd->im_format.flag & R_IMF_FLAG_PREVIEW_JPG)) {
- ImageFormatData imf = rd->im_format;
- imf.imtype = R_IMF_IMTYPE_JPEG90;
-
- if (BLI_path_extension_check(name, ".exr")) {
- name[strlen(name) - 4] = 0;
- }
-
- BKE_image_path_ensure_ext_from_imformat(name, &imf);
- ibuf_arr[2]->planes = 24;
-
- ok = render_imbuf_write_stamp_test(
- reports, scene, rr, ibuf_arr[2], name, &rd->im_format, stamp);
- }
-
- /* imbuf knows which rects are not part of ibuf */
- for (i = 0; i < 3; i++) {
- IMB_freeImBuf(ibuf_arr[i]);
- }
- }
- }
-
- return ok;
-}
-
bool RE_WriteRenderViewsMovie(ReportList *reports,
RenderResult *rr,
Scene *scene,
@@ -2110,23 +1948,25 @@ bool RE_WriteRenderViewsMovie(ReportList *reports,
const int totvideos,
bool preview)
{
- bool is_mono;
bool ok = true;
if (!rr) {
return false;
}
- is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2;
+ ImageFormatData image_format;
+ BKE_image_format_init_for_write(&image_format, scene, NULL);
+
+ const bool is_mono = BLI_listbase_count_at_most(&rr->views, 2) < 2;
+ const float dither = scene->r.dither_intensity;
- if (is_mono || (scene->r.im_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
+ if (is_mono || (image_format.views_format == R_IMF_VIEWS_INDIVIDUAL)) {
int view_id;
for (view_id = 0; view_id < totvideos; view_id++) {
const char *suffix = BKE_scene_multiview_view_id_suffix_get(&scene->r, view_id);
- ImBuf *ibuf = render_result_rect_to_ibuf(rr, &scene->r, view_id);
+ ImBuf *ibuf = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id);
- IMB_colormanagement_imbuf_for_write(
- ibuf, true, false, &scene->view_settings, &scene->display_settings, &scene->r.im_format);
+ IMB_colormanagement_imbuf_for_write(ibuf, true, false, &image_format);
ok &= mh->append_movie(movie_ctx_arr[view_id],
rd,
@@ -2148,21 +1988,16 @@ bool RE_WriteRenderViewsMovie(ReportList *reports,
ImBuf *ibuf_arr[3] = {NULL};
int i;
- BLI_assert((totvideos == 1) && (scene->r.im_format.views_format == R_IMF_VIEWS_STEREO_3D));
+ BLI_assert((totvideos == 1) && (image_format.views_format == R_IMF_VIEWS_STEREO_3D));
for (i = 0; i < 2; i++) {
int view_id = BLI_findstringindex(&rr->views, names[i], offsetof(RenderView, name));
- ibuf_arr[i] = render_result_rect_to_ibuf(rr, &scene->r, view_id);
-
- IMB_colormanagement_imbuf_for_write(ibuf_arr[i],
- true,
- false,
- &scene->view_settings,
- &scene->display_settings,
- &scene->r.im_format);
+ ibuf_arr[i] = RE_render_result_rect_to_ibuf(rr, &rd->im_format, dither, view_id);
+
+ IMB_colormanagement_imbuf_for_write(ibuf_arr[i], true, false, &image_format);
}
- ibuf_arr[2] = IMB_stereo3d_ImBuf(&scene->r.im_format, ibuf_arr[0], ibuf_arr[1]);
+ ibuf_arr[2] = IMB_stereo3d_ImBuf(&image_format, ibuf_arr[0], ibuf_arr[1]);
ok = mh->append_movie(movie_ctx_arr[0],
rd,
@@ -2180,6 +2015,8 @@ bool RE_WriteRenderViewsMovie(ReportList *reports,
}
}
+ BKE_image_format_free(&image_format);
+
return ok;
}
@@ -2224,7 +2061,7 @@ static int do_write_image_or_movie(Render *re,
}
/* write images as individual images or stereo */
- ok = RE_WriteRenderViewsImage(re->reports, &rres, scene, true, name);
+ ok = BKE_image_render_write(re->reports, &rres, scene, true, name);
}
RE_ReleaseResultImageViews(re, &rres);
@@ -2305,7 +2142,8 @@ void RE_RenderAnim(Render *re,
const RenderData rd = scene->r;
bMovieHandle *mh = NULL;
- const int cfrao = rd.cfra;
+ const int cfra_old = rd.cfra;
+ const float subframe_old = rd.subframe;
int nfra, totrendered = 0, totskipped = 0;
const int totvideos = BKE_scene_multiview_num_videos_get(&rd);
const bool is_movie = BKE_imtype_is_movie(rd.im_format.imtype);
@@ -2373,6 +2211,7 @@ void RE_RenderAnim(Render *re,
re->flag |= R_ANIMATION;
{
+ scene->r.subframe = 0.0f;
for (nfra = sfra, scene->r.cfra = sfra; scene->r.cfra <= efra; scene->r.cfra++) {
char name[FILE_MAX];
@@ -2481,6 +2320,7 @@ void RE_RenderAnim(Render *re,
}
re->r.cfra = scene->r.cfra; /* weak.... */
+ re->r.subframe = scene->r.subframe;
/* run callbacks before rendering, before the scene is updated */
render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_PRE);
@@ -2549,7 +2389,8 @@ void RE_RenderAnim(Render *re,
BKE_report(re->reports, RPT_INFO, "No frames rendered, skipped to not overwrite");
}
- scene->r.cfra = cfrao;
+ scene->r.cfra = cfra_old;
+ scene->r.subframe = subframe_old;
re->flag &= ~R_ANIMATION;
@@ -2639,10 +2480,10 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
}
void RE_layer_load_from_file(
- RenderLayer *layer, ReportList *reports, const char *filename, int x, int y)
+ RenderLayer *layer, ReportList *reports, const char *filepath, int x, int y)
{
/* OCIO_TODO: assume layer was saved in default color space */
- ImBuf *ibuf = IMB_loadiffname(filename, IB_rect, NULL);
+ ImBuf *ibuf = IMB_loadiffname(filepath, IB_rect, NULL);
RenderPass *rpass = NULL;
/* multiview: since the API takes no 'view', we use the first combined pass found */
@@ -2657,7 +2498,7 @@ void RE_layer_load_from_file(
RPT_ERROR,
"%s: no Combined pass found in the render layer '%s'",
__func__,
- filename);
+ filepath);
}
if (ibuf && (ibuf->rect || ibuf->rect_float)) {
@@ -2686,7 +2527,7 @@ void RE_layer_load_from_file(
}
else {
BKE_reportf(
- reports, RPT_ERROR, "%s: failed to allocate clip buffer '%s'", __func__, filename);
+ reports, RPT_ERROR, "%s: failed to allocate clip buffer '%s'", __func__, filepath);
}
}
else {
@@ -2694,21 +2535,21 @@ void RE_layer_load_from_file(
RPT_ERROR,
"%s: incorrect dimensions for partial copy '%s'",
__func__,
- filename);
+ filepath);
}
}
IMB_freeImBuf(ibuf);
}
else {
- BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filename);
+ BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filepath);
}
}
-void RE_result_load_from_file(RenderResult *result, ReportList *reports, const char *filename)
+void RE_result_load_from_file(RenderResult *result, ReportList *reports, const char *filepath)
{
- if (!render_result_exr_file_read_path(result, NULL, filename)) {
- BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filename);
+ if (!render_result_exr_file_read_path(result, NULL, filepath)) {
+ BKE_reportf(reports, RPT_ERROR, "%s: failed to load '%s'", __func__, filepath);
return;
}
}
@@ -2737,7 +2578,7 @@ bool RE_passes_have_name(struct RenderLayer *rl)
return false;
}
-RenderPass *RE_pass_find_by_name(volatile RenderLayer *rl, const char *name, const char *viewname)
+RenderPass *RE_pass_find_by_name(RenderLayer *rl, const char *name, const char *viewname)
{
RenderPass *rp = NULL;
@@ -2754,7 +2595,7 @@ RenderPass *RE_pass_find_by_name(volatile RenderLayer *rl, const char *name, con
return rp;
}
-RenderPass *RE_pass_find_by_type(volatile RenderLayer *rl, int passtype, const char *viewname)
+RenderPass *RE_pass_find_by_type(RenderLayer *rl, int passtype, const char *viewname)
{
#define CHECK_PASS(NAME) \
if (passtype == SCE_PASS_##NAME) { \
diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c
index a3ba8e2f02b..ea7fa961f0d 100644
--- a/source/blender/render/intern/render_result.c
+++ b/source/blender/render/intern/render_result.c
@@ -26,14 +26,15 @@
#include "BKE_camera.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
+#include "BKE_image_save.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
-
-#include "intern/openexr/openexr_multi.h"
+#include "IMB_openexr.h"
#include "RE_engine.h"
@@ -161,37 +162,6 @@ void render_result_views_shallowdelete(RenderResult *rr)
}
}
-static char *set_pass_name(char *outname, const char *name, int channel, const char *chan_id)
-{
- const char *strings[2];
- int strings_len = 0;
- strings[strings_len++] = name;
- char token[2];
- if (channel >= 0) {
- ARRAY_SET_ITEMS(token, chan_id[channel], '\0');
- strings[strings_len++] = token;
- }
- BLI_string_join_array_by_sep_char(outname, EXR_PASS_MAXNAME, '.', strings, strings_len);
- return outname;
-}
-
-static void set_pass_full_name(
- char *fullname, const char *name, int channel, const char *view, const char *chan_id)
-{
- const char *strings[3];
- int strings_len = 0;
- strings[strings_len++] = name;
- if (view && view[0]) {
- strings[strings_len++] = view;
- }
- char token[2];
- if (channel >= 0) {
- ARRAY_SET_ITEMS(token, chan_id[channel], '\0');
- strings[strings_len++] = token;
- }
- BLI_string_join_array_by_sep_char(fullname, EXR_PASS_MAXNAME, '.', strings, strings_len);
-}
-
/********************************** New **************************************/
static void render_layer_allocate_pass(RenderResult *rr, RenderPass *rp)
@@ -237,20 +207,15 @@ RenderPass *render_layer_add_pass(RenderResult *rr,
BLI_strncpy(rpass->name, name, sizeof(rpass->name));
BLI_strncpy(rpass->chan_id, chan_id, sizeof(rpass->chan_id));
BLI_strncpy(rpass->view, viewname, sizeof(rpass->view));
- set_pass_full_name(rpass->fullname, rpass->name, -1, rpass->view, rpass->chan_id);
+ RE_render_result_full_channel_name(
+ rpass->fullname, NULL, rpass->name, rpass->view, rpass->chan_id, -1);
if (rl->exrhandle) {
int a;
for (a = 0; a < channels; a++) {
char passname[EXR_PASS_MAXNAME];
- IMB_exr_add_channel(rl->exrhandle,
- rl->name,
- set_pass_name(passname, rpass->name, a, rpass->chan_id),
- viewname,
- 0,
- 0,
- NULL,
- false);
+ RE_render_result_full_channel_name(passname, NULL, rpass->name, NULL, rpass->chan_id, a);
+ IMB_exr_add_channel(rl->exrhandle, rl->name, passname, viewname, 0, 0, NULL, false);
}
}
@@ -449,6 +414,11 @@ RenderResult *render_result_new(Render *re,
rr->xof = re->disprect.xmin + BLI_rcti_cent_x(&re->disprect) - (re->winx / 2);
rr->yof = re->disprect.ymin + BLI_rcti_cent_y(&re->disprect) - (re->winy / 2);
+ /* Preview does not support deferred render result allocation. */
+ if (re->r.scemode & R_BUTS_PREVIEW) {
+ render_result_passes_allocated_ensure(rr);
+ }
+
return rr;
}
@@ -543,6 +513,36 @@ void RE_create_render_pass(RenderResult *rr,
}
}
+void RE_render_result_full_channel_name(char *fullname,
+ const char *layname,
+ const char *passname,
+ const char *viewname,
+ const char *chan_id,
+ const int channel)
+{
+ /* OpenEXR compatible full channel name. */
+ const char *strings[4];
+ int strings_len = 0;
+
+ if (layname && layname[0]) {
+ strings[strings_len++] = layname;
+ }
+ if (passname && passname[0]) {
+ strings[strings_len++] = passname;
+ }
+ if (viewname && viewname[0]) {
+ strings[strings_len++] = viewname;
+ }
+
+ char token[2];
+ if (channel >= 0) {
+ ARRAY_SET_ITEMS(token, chan_id[channel], '\0');
+ strings[strings_len++] = token;
+ }
+
+ BLI_string_join_array_by_sep_char(fullname, EXR_PASS_MAXNAME, '.', strings, strings_len);
+}
+
static int passtype_from_name(const char *name)
{
const char delim[] = {'.', '\0'};
@@ -619,7 +619,7 @@ static void ml_addpass_cb(void *base,
rpass->rect = rect;
BLI_strncpy(rpass->name, name, EXR_PASS_MAXNAME);
BLI_strncpy(rpass->view, view, sizeof(rpass->view));
- set_pass_full_name(rpass->fullname, name, -1, view, rpass->chan_id);
+ RE_render_result_full_channel_name(rpass->fullname, NULL, name, view, rpass->chan_id, -1);
if (view[0] != '\0') {
rpass->view_id = BLI_findstringindex(&rr->views, view, offsetof(RenderView, name));
@@ -663,7 +663,7 @@ static void *ml_addview_cb(void *base, const char *str)
static int order_render_passes(const void *a, const void *b)
{
- // 1 if a is after b
+ /* 1 if `a` is after `b`. */
RenderPass *rpa = (RenderPass *)a;
RenderPass *rpb = (RenderPass *)b;
unsigned int passtype_a = passtype_from_name(rpa->name);
@@ -785,12 +785,6 @@ void render_result_views_new(RenderResult *rr, const RenderData *rd)
}
}
-bool render_result_has_views(const RenderResult *rr)
-{
- const RenderView *rv = rr->views.first;
- return (rv && (rv->next || rv->name[0]));
-}
-
/*********************************** Merge ***********************************/
static void do_merge_tile(
@@ -845,162 +839,6 @@ void render_result_merge(RenderResult *rr, RenderResult *rrpart)
}
}
-bool RE_WriteRenderResult(ReportList *reports,
- RenderResult *rr,
- const char *filename,
- ImageFormatData *imf,
- const char *view,
- int layer)
-{
- void *exrhandle = IMB_exr_get_handle();
- const bool half_float = (imf && imf->depth == R_IMF_CHAN_DEPTH_16);
- const bool multi_layer = !(imf && imf->imtype == R_IMF_IMTYPE_OPENEXR);
- const bool write_z = !multi_layer && (imf && (imf->flag & R_IMF_FLAG_ZBUF));
-
- /* Write first layer if not multilayer and no layer was specified. */
- if (!multi_layer && layer == -1) {
- layer = 0;
- }
-
- /* First add views since IMB_exr_add_channel checks number of views. */
- if (render_result_has_views(rr)) {
- LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
- if (!view || STREQ(view, rview->name)) {
- IMB_exr_add_view(exrhandle, rview->name);
- }
- }
- }
-
- /* Compositing result. */
- if (rr->have_combined) {
- LISTBASE_FOREACH (RenderView *, rview, &rr->views) {
- if (!rview->rectf) {
- continue;
- }
-
- const char *viewname = rview->name;
- if (view) {
- if (!STREQ(view, viewname)) {
- continue;
- }
-
- viewname = "";
- }
-
- /* Skip compositing if only a single other layer is requested. */
- if (!multi_layer && layer != 0) {
- continue;
- }
-
- for (int a = 0; a < 4; a++) {
- char passname[EXR_PASS_MAXNAME];
- char layname[EXR_PASS_MAXNAME];
- const char *chan_id = "RGBA";
-
- if (multi_layer) {
- set_pass_name(passname, "Combined", a, chan_id);
- BLI_strncpy(layname, "Composite", sizeof(layname));
- }
- else {
- passname[0] = chan_id[a];
- passname[1] = '\0';
- layname[0] = '\0';
- }
-
- IMB_exr_add_channel(exrhandle,
- layname,
- passname,
- viewname,
- 4,
- 4 * rr->rectx,
- rview->rectf + a,
- half_float);
- }
-
- if (write_z && rview->rectz) {
- const char *layname = (multi_layer) ? "Composite" : "";
- IMB_exr_add_channel(exrhandle, layname, "Z", viewname, 1, rr->rectx, rview->rectz, false);
- }
- }
- }
-
- /* Other render layers. */
- int nr = (rr->have_combined) ? 1 : 0;
- for (RenderLayer *rl = rr->layers.first; rl; rl = rl->next, nr++) {
- /* Skip other render layers if requested. */
- if (!multi_layer && nr != layer) {
- continue;
- }
-
- LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) {
- /* Skip non-RGBA and Z passes if not using multi layer. */
- if (!multi_layer && !(STREQ(rp->name, RE_PASSNAME_COMBINED) || STREQ(rp->name, "") ||
- (STREQ(rp->name, RE_PASSNAME_Z) && write_z))) {
- continue;
- }
-
- /* Skip pass if it does not match the requested view(s). */
- const char *viewname = rp->view;
- if (view) {
- if (!STREQ(view, viewname)) {
- continue;
- }
-
- viewname = "";
- }
-
- /* We only store RGBA passes as half float, for
- * others precision loss can be problematic. */
- bool pass_half_float = half_float &&
- (STR_ELEM(rp->chan_id, "RGB", "RGBA", "R", "G", "B", "A"));
-
- for (int a = 0; a < rp->channels; a++) {
- /* Save Combined as RGBA if single layer save. */
- char passname[EXR_PASS_MAXNAME];
- char layname[EXR_PASS_MAXNAME];
-
- if (multi_layer) {
- set_pass_name(passname, rp->name, a, rp->chan_id);
- BLI_strncpy(layname, rl->name, sizeof(layname));
- }
- else {
- passname[0] = rp->chan_id[a];
- passname[1] = '\0';
- layname[0] = '\0';
- }
-
- IMB_exr_add_channel(exrhandle,
- layname,
- passname,
- viewname,
- rp->channels,
- rp->channels * rr->rectx,
- rp->rect + a,
- pass_half_float);
- }
- }
- }
-
- errno = 0;
-
- BLI_make_existing_file(filename);
-
- int compress = (imf ? imf->exr_codec : 0);
- bool success = IMB_exr_begin_write(
- exrhandle, filename, rr->rectx, rr->recty, compress, rr->stamp_data);
- if (success) {
- IMB_exr_write_channels(exrhandle);
- }
- else {
- /* TODO: get the error from openexr's exception. */
- BKE_reportf(
- reports, RPT_ERROR, "Error writing render result, %s (see console)", strerror(errno));
- }
-
- IMB_exr_close(exrhandle);
- return success;
-}
-
/**************************** Single Layer Rendering *************************/
void render_result_single_layer_begin(Render *re)
@@ -1096,12 +934,14 @@ int render_result_exr_file_read_path(RenderResult *rr,
char fullname[EXR_PASS_MAXNAME];
for (a = 0; a < xstride; a++) {
- set_pass_full_name(fullname, rpass->name, a, rpass->view, rpass->chan_id);
+ RE_render_result_full_channel_name(
+ fullname, NULL, rpass->name, rpass->view, rpass->chan_id, a);
IMB_exr_set_channel(
exrhandle, rl->name, fullname, xstride, xstride * rectx, rpass->rect + a);
}
- set_pass_full_name(rpass->fullname, rpass->name, -1, rpass->view, rpass->chan_id);
+ RE_render_result_full_channel_name(
+ rpass->fullname, NULL, rpass->name, rpass->view, rpass->chan_id, -1);
}
}
@@ -1153,7 +993,7 @@ void render_result_exr_file_cache_write(Render *re)
render_result_exr_file_cache_path(re->scene, root, str);
printf("Caching exr file, %dx%d, %s\n", rr->rectx, rr->recty, str);
- RE_WriteRenderResult(NULL, rr, str, NULL, NULL, -1);
+ BKE_image_render_write_exr(NULL, rr, str, NULL, true, NULL, -1);
}
bool render_result_exr_file_cache_read(Render *re)
@@ -1189,9 +1029,12 @@ bool render_result_exr_file_cache_read(Render *re)
/*************************** Combined Pixel Rect *****************************/
-ImBuf *render_result_rect_to_ibuf(RenderResult *rr, const RenderData *rd, const int view_id)
+ImBuf *RE_render_result_rect_to_ibuf(RenderResult *rr,
+ const ImageFormatData *imf,
+ const float dither,
+ const int view_id)
{
- ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, rd->im_format.planes, 0);
+ ImBuf *ibuf = IMB_allocImBuf(rr->rectx, rr->recty, imf->planes, 0);
RenderView *rv = RE_RenderViewGetById(rr, view_id);
/* if not exists, BKE_imbuf_write makes one */
@@ -1200,15 +1043,15 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, const RenderData *rd, const
ibuf->zbuf_float = rv->rectz;
/* float factor for random dither, imbuf takes care of it */
- ibuf->dither = rd->dither_intensity;
+ ibuf->dither = dither;
/* prepare to gamma correct to sRGB color space
* note that sequence editor can generate 8bpc render buffers
*/
if (ibuf->rect) {
- if (BKE_imtype_valid_depths(rd->im_format.imtype) &
+ if (BKE_imtype_valid_depths(imf->imtype) &
(R_IMF_CHAN_DEPTH_12 | R_IMF_CHAN_DEPTH_16 | R_IMF_CHAN_DEPTH_24 | R_IMF_CHAN_DEPTH_32)) {
- if (rd->im_format.depth == R_IMF_CHAN_DEPTH_8) {
+ if (imf->depth == R_IMF_CHAN_DEPTH_8) {
/* Higher depth bits are supported but not needed for current file output. */
ibuf->rect_float = NULL;
}
@@ -1224,7 +1067,7 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, const RenderData *rd, const
/* Color -> gray-scale. */
/* editing directly would alter the render view */
- if (rd->im_format.planes == R_IMF_PLANES_BW) {
+ if (imf->planes == R_IMF_PLANES_BW) {
ImBuf *ibuf_bw = IMB_dupImBuf(ibuf);
IMB_color_to_bw(ibuf_bw);
IMB_freeImBuf(ibuf);
@@ -1234,10 +1077,7 @@ ImBuf *render_result_rect_to_ibuf(RenderResult *rr, const RenderData *rd, const
return ibuf;
}
-void RE_render_result_rect_from_ibuf(RenderResult *rr,
- RenderData *UNUSED(rd),
- ImBuf *ibuf,
- const int view_id)
+void RE_render_result_rect_from_ibuf(RenderResult *rr, const ImBuf *ibuf, const int view_id)
{
RenderView *rv = RE_RenderViewGetById(rr, view_id);
@@ -1314,15 +1154,13 @@ void render_result_rect_get_pixels(RenderResult *rr,
/*************************** multiview functions *****************************/
-bool RE_HasCombinedLayer(RenderResult *rr)
+bool RE_HasCombinedLayer(const RenderResult *rr)
{
- RenderView *rv;
-
if (rr == NULL) {
return false;
}
- rv = rr->views.first;
+ const RenderView *rv = rr->views.first;
if (rv == NULL) {
return false;
}
@@ -1330,11 +1168,9 @@ bool RE_HasCombinedLayer(RenderResult *rr)
return (rv->rect32 || rv->rectf);
}
-bool RE_HasFloatPixels(RenderResult *rr)
+bool RE_HasFloatPixels(const RenderResult *rr)
{
- RenderView *rview;
-
- for (rview = rr->views.first; rview; rview = rview->next) {
+ for (const RenderView *rview = rr->views.first; rview; rview = rview->next) {
if (rview->rect32 && !rview->rectf) {
return false;
}
@@ -1343,7 +1179,7 @@ bool RE_HasFloatPixels(RenderResult *rr)
return true;
}
-bool RE_RenderResult_is_stereo(RenderResult *rr)
+bool RE_RenderResult_is_stereo(const RenderResult *rr)
{
if (!BLI_findstring(&rr->views, STEREO_LEFT_NAME, offsetof(RenderView, name))) {
return false;
diff --git a/source/blender/render/intern/render_result.h b/source/blender/render/intern/render_result.h
index 07929f4351f..30f49775562 100644
--- a/source/blender/render/intern/render_result.h
+++ b/source/blender/render/intern/render_result.h
@@ -131,7 +131,6 @@ void render_result_views_shallowcopy(struct RenderResult *dst, struct RenderResu
* Free the views created temporarily.
*/
void render_result_views_shallowdelete(struct RenderResult *rr);
-bool render_result_has_views(const struct RenderResult *rr);
#define FOREACH_VIEW_LAYER_TO_RENDER_BEGIN(re_, iter_) \
{ \
diff --git a/source/blender/render/intern/render_types.h b/source/blender/render/intern/render_types.h
index b3c80f7dded..27b014ac289 100644
--- a/source/blender/render/intern/render_types.h
+++ b/source/blender/render/intern/render_types.h
@@ -99,7 +99,7 @@ struct Render {
void *dih;
void (*display_clear)(void *handle, RenderResult *rr);
void *dch;
- void (*display_update)(void *handle, RenderResult *rr, volatile rcti *rect);
+ void (*display_update)(void *handle, RenderResult *rr, rcti *rect);
void *duh;
void (*current_scene_update)(void *handle, struct Scene *scene);
void *suh;
diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc
index adc11cd925e..d01c0dbea71 100644
--- a/source/blender/render/intern/texture_margin.cc
+++ b/source/blender/render/intern/texture_margin.cc
@@ -331,7 +331,7 @@ class TextureMarginMap {
float destx, desty;
int foundpoly;
- float mindist = -1.f;
+ float mindist = -1.0f;
/* Loop over all adjacent polygons and determine which edge is closest.
* This could be optimized by only inspecting neighbors which are on the edge of an island.
@@ -356,7 +356,7 @@ class TextureMarginMap {
}
}
- return mindist >= 0.f;
+ return mindist >= 0.0f;
}
/**
diff --git a/source/blender/sequencer/intern/disk_cache.c b/source/blender/sequencer/intern/disk_cache.c
index 9216383d274..0fdaef61b65 100644
--- a/source/blender/sequencer/intern/disk_cache.c
+++ b/source/blender/sequencer/intern/disk_cache.c
@@ -160,10 +160,11 @@ static DiskCacheFile *seq_disk_cache_add_file_to_list(SeqDiskCache *disk_cache,
static void seq_disk_cache_get_files(SeqDiskCache *disk_cache, char *path)
{
struct direntry *filelist, *fl;
- uint nbr, i;
+ uint i;
disk_cache->size_total = 0;
- i = nbr = BLI_filelist_dir_contents(path, &filelist);
+ const int filelist_num = BLI_filelist_dir_contents(path, &filelist);
+ i = filelist_num;
fl = filelist;
while (i--) {
/* Don't follow links. */
@@ -194,7 +195,7 @@ static void seq_disk_cache_get_files(SeqDiskCache *disk_cache, char *path)
}
fl++;
}
- BLI_filelist_free(filelist, nbr);
+ BLI_filelist_free(filelist, filelist_num);
}
static DiskCacheFile *seq_disk_cache_get_oldest_file(SeqDiskCache *disk_cache)
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index a77b34ae66d..8f7088b0c4b 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -3737,9 +3737,9 @@ int SEQ_effect_get_num_inputs(int seq_type)
{
struct SeqEffectHandle rval = get_sequence_effect_impl(seq_type);
- int cnt = rval.num_inputs();
+ int count = rval.num_inputs();
if (rval.execute || (rval.execute_slice && rval.init_execution)) {
- return cnt;
+ return count;
}
return 0;
}
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index e53ef34603d..3f4d1e875f3 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -1501,7 +1501,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
}
RE_RenderFrame(
- re, context->bmain, scene, have_comp ? NULL : view_layer, camera, frame, false);
+ re, context->bmain, scene, have_comp ? NULL : view_layer, camera, frame, 0.0f, false);
/* restore previous state after it was toggled on & off by RE_RenderFrame */
G.is_rendering = is_rendering;
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index 8849b029d46..ddf75f3d664 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -298,7 +298,7 @@ static int shuffle_seq_time_offset_test(SeqCollection *strips_to_shuffle,
}
if (UNLIKELY(SEQ_collection_has_strip(seq_other, strips_to_shuffle))) {
CLOG_WARN(&LOG,
- "Strip overlaps with itself or another strip, that is to be shuffled."
+ "Strip overlaps with itself or another strip, that is to be shuffled. "
"This should never happen.");
continue;
}
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 9edbafafdd3..6df65f2a2a3 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -1167,25 +1167,28 @@ typedef struct wmDropBox {
struct wmDropBox *next, *prev;
/** Test if the dropbox is active. */
- bool (*poll)(struct bContext *, struct wmDrag *, const wmEvent *);
+ bool (*poll)(struct bContext *C, struct wmDrag *drag, const wmEvent *event);
/** Before exec, this copies drag info to #wmDrop properties. */
- void (*copy)(struct wmDrag *, struct wmDropBox *);
+ void (*copy)(struct wmDrag *drag, struct wmDropBox *drop);
/**
- * If the operator is cancelled (returns `OPERATOR_CANCELLED`), this can be used for cleanup of
+ * If the operator is canceled (returns `OPERATOR_CANCELLED`), this can be used for cleanup of
* `copy()` resources.
*/
- void (*cancel)(struct Main *, struct wmDrag *, struct wmDropBox *);
+ void (*cancel)(struct Main *bmain, struct wmDrag *drag, struct wmDropBox *drop);
- /** Override the default drawing function. */
- void (*draw)(struct bContext *, struct wmWindow *, struct wmDrag *, const int *);
+ /**
+ * Override the default drawing function.
+ * \param xy: Cursor location in window coordinates (#wmEvent.xy compatible).
+ */
+ void (*draw)(struct bContext *C, struct wmWindow *win, struct wmDrag *drag, const int xy[2]);
/** Called when pool returns true the first time. */
- void (*draw_activate)(struct wmDropBox *, struct wmDrag *drag);
+ void (*draw_activate)(struct wmDropBox *drop, struct wmDrag *drag);
/** Called when pool returns false the first time or when the drag event ends. */
- void (*draw_deactivate)(struct wmDropBox *, struct wmDrag *drag);
+ void (*draw_deactivate)(struct wmDropBox *drop, struct wmDrag *drag);
/** Custom data for drawing. */
void *draw_data;
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 46f7b67c2ba..3c8474b1b6c 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -1037,6 +1037,10 @@ void wm_draw_update(bContext *C)
wmWindowManager *wm = CTX_wm_manager(C);
GPU_context_main_lock();
+
+ GPU_render_begin();
+ GPU_render_step();
+
BKE_image_free_unused_gpu_textures();
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
@@ -1075,6 +1079,7 @@ void wm_draw_update(bContext *C)
/* Draw non-windows (surfaces) */
wm_surfaces_iter(C, wm_draw_surface);
+ GPU_render_end();
GPU_context_main_unlock();
}
diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c
index 9a7d31f8bb8..503dae53122 100644
--- a/source/blender/windowmanager/intern/wm_event_query.c
+++ b/source/blender/windowmanager/intern/wm_event_query.c
@@ -38,6 +38,30 @@
/** \name Event Printing
* \{ */
+struct FlagIdentifierPair {
+ const char *id;
+ uint flag;
+};
+
+static void event_ids_from_flag(char *str,
+ const int str_maxlen,
+ const struct FlagIdentifierPair *flag_data,
+ const int flag_data_len,
+ const uint flag)
+{
+ int ofs = 0;
+ ofs += BLI_strncpy_rlen(str + ofs, "{", str_maxlen - ofs);
+ for (int i = 0; i < flag_data_len; i++) {
+ if (flag & flag_data[i].flag) {
+ if (ofs != 1) {
+ ofs += BLI_strncpy_rlen(str + ofs, "|", str_maxlen - ofs);
+ }
+ ofs += BLI_strncpy_rlen(str + ofs, flag_data[i].id, str_maxlen - ofs);
+ }
+ }
+ ofs += BLI_strncpy_rlen(str + ofs, "}", str_maxlen - ofs);
+}
+
static void event_ids_from_type_and_value(const short type,
const short val,
const char **r_type_id,
@@ -62,11 +86,33 @@ void WM_event_print(const wmEvent *event)
event_ids_from_type_and_value(event->type, event->val, &type_id, &val_id);
event_ids_from_type_and_value(event->prev_type, event->prev_val, &prev_type_id, &prev_val_id);
+ char modifier_id[128];
+ {
+ struct FlagIdentifierPair flag_data[] = {
+ {"SHIFT", KM_SHIFT},
+ {"CTRL", KM_CTRL},
+ {"ALT", KM_ALT},
+ {"OS", KM_OSKEY},
+ };
+ event_ids_from_flag(
+ modifier_id, sizeof(modifier_id), flag_data, ARRAY_SIZE(flag_data), event->modifier);
+ }
+
+ char flag_id[128];
+ {
+ struct FlagIdentifierPair flag_data[] = {
+ {"SCROLL_INVERT", WM_EVENT_SCROLL_INVERT},
+ {"IS_REPEAT", WM_EVENT_IS_REPEAT},
+ {"FORCE_DRAG_THRESHOLD", WM_EVENT_FORCE_DRAG_THRESHOLD},
+ };
+ event_ids_from_flag(flag_id, sizeof(flag_id), flag_data, ARRAY_SIZE(flag_data), event->flag);
+ }
+
printf(
- "wmEvent type:%d / %s, val:%d / %s,\n"
- " prev_type:%d / %s, prev_val:%d / %s,\n"
- " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, is_repeat:%d,\n"
- " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p\n",
+ "wmEvent type:%d/%s, val:%d/%s, "
+ "prev_type:%d/%s, prev_val:%d/%s, "
+ "modifier=%s, keymodifier:%d, flag:%s, "
+ "mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p",
event->type,
type_id,
event->val,
@@ -75,12 +121,9 @@ void WM_event_print(const wmEvent *event)
prev_type_id,
event->prev_val,
prev_val_id,
- (event->modifier & KM_SHIFT) != 0,
- (event->modifier & KM_CTRL) != 0,
- (event->modifier & KM_ALT) != 0,
- (event->modifier & KM_OSKEY) != 0,
+ modifier_id,
event->keymodifier,
- (event->flag & WM_EVENT_IS_REPEAT) != 0,
+ flag_id,
event->xy[0],
event->xy[1],
event->ascii,
@@ -92,7 +135,7 @@ void WM_event_print(const wmEvent *event)
if (ISNDOF(event->type)) {
const wmNDOFMotionData *ndof = event->customdata;
if (event->type == NDOF_MOTION) {
- printf(" ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %u\n",
+ printf(", ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %u",
UNPACK3(ndof->rvec),
UNPACK3(ndof->tvec),
ndof->dt,
@@ -106,12 +149,13 @@ void WM_event_print(const wmEvent *event)
if (event->tablet.active != EVT_TABLET_NONE) {
const wmTabletData *wmtab = &event->tablet;
- printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n",
+ printf(", tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)",
wmtab->active,
wmtab->pressure,
wmtab->x_tilt,
wmtab->y_tilt);
}
+ printf("\n");
}
else {
printf("wmEvent - NULL\n");
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 669d8a9b4f0..60ae4eccbbe 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -194,6 +194,10 @@ void wm_event_free(wmEvent *event)
printf("%s: 'is_repeat=true' for non-keyboard event, this should not happen.\n", __func__);
WM_event_print(event);
}
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) && (event->val != KM_NOTHING)) {
+ printf("%s: 'val != NOTHING' for a cursor motion event, this should not happen.\n", __func__);
+ WM_event_print(event);
+ }
#endif
wm_event_custom_free(event);
@@ -3879,6 +3883,7 @@ void wm_event_do_handlers(bContext *C)
wmEvent tevent = *(win->eventstate);
// printf("adding MOUSEMOVE %d %d\n", tevent.xy[0], tevent.xy[1]);
tevent.type = MOUSEMOVE;
+ tevent.val = KM_NOTHING;
tevent.prev_xy[0] = tevent.xy[0];
tevent.prev_xy[1] = tevent.xy[1];
tevent.flag = 0;
@@ -4423,6 +4428,9 @@ void WM_event_add_mousemove(wmWindow *win)
/** \name Ghost Event Conversion
* \{ */
+/**
+ * \return The WM enum for key or #EVENT_NONE (which should be ignored).
+ */
static int convert_key(GHOST_TKey key)
{
if (key >= GHOST_kKeyA && key <= GHOST_kKeyZ) {
@@ -4446,7 +4454,7 @@ static int convert_key(GHOST_TKey key)
case GHOST_kKeyLinefeed:
return EVT_LINEFEEDKEY;
case GHOST_kKeyClear:
- return 0;
+ return EVENT_NONE;
case GHOST_kKeyEnter:
return EVT_RETKEY;
@@ -4501,9 +4509,9 @@ static int convert_key(GHOST_TKey key)
case GHOST_kKeyCapsLock:
return EVT_CAPSLOCKKEY;
case GHOST_kKeyNumLock:
- return 0;
+ return EVENT_NONE;
case GHOST_kKeyScrollLock:
- return 0;
+ return EVENT_NONE;
case GHOST_kKeyLeftArrow:
return EVT_LEFTARROWKEY;
@@ -4515,7 +4523,7 @@ static int convert_key(GHOST_TKey key)
return EVT_DOWNARROWKEY;
case GHOST_kKeyPrintScreen:
- return 0;
+ return EVENT_NONE;
case GHOST_kKeyPause:
return EVT_PAUSEKEY;
@@ -4557,9 +4565,28 @@ static int convert_key(GHOST_TKey key)
case GHOST_kKeyMediaLast:
return EVT_MEDIALAST;
- default:
- return EVT_UNKNOWNKEY; /* #GHOST_kKeyUnknown (this could be asserted). */
+ case GHOST_kKeyUnknown:
+ return EVT_UNKNOWNKEY;
+
+#if defined(__GNUC__) || defined(__clang__)
+ /* Ensure all members of this enum are handled, otherwise generate a compiler warning.
+ * Note that these members have been handled, these ranges are to satisfy the compiler. */
+ case GHOST_kKeyF1 ... GHOST_kKeyF24:
+ case GHOST_kKeyA ... GHOST_kKeyZ:
+ case GHOST_kKeyNumpad0 ... GHOST_kKeyNumpad9:
+ case GHOST_kKey0 ... GHOST_kKey9: {
+ BLI_assert_unreachable();
+ break;
+ }
+#else
+ default: {
+ break;
+ }
+#endif
}
+
+ CLOG_WARN(WM_LOG_EVENTS, "unknown event type %d from ghost", (int)key);
+ return EVENT_NONE;
}
static void wm_eventemulation(wmEvent *event, bool test_only)
@@ -4822,6 +4849,7 @@ static wmEvent *wm_event_add_mousemove_to_head(wmWindow *win)
}
tevent.type = MOUSEMOVE;
+ tevent.val = KM_NOTHING;
copy_v2_v2_int(tevent.prev_xy, tevent.xy);
wmEvent *event_new = wm_event_add(win, &tevent);
@@ -4956,6 +4984,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
wm_tablet_data_from_ghost(&cd->tablet, &event.tablet);
event.type = MOUSEMOVE;
+ event.val = KM_NOTHING;
{
wmEvent *event_new = wm_event_add_mousemove(win, &event);
copy_v2_v2_int(event_state->xy, event_new->xy);
@@ -4974,6 +5003,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
copy_v2_v2_int(event_other.xy, event.xy);
event_other.type = MOUSEMOVE;
+ event_other.val = KM_NOTHING;
{
wmEvent *event_new = wm_event_add_mousemove(win_other, &event_other);
copy_v2_v2_int(win_other->eventstate->xy, event_new->xy);
@@ -5079,6 +5109,10 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void
case GHOST_kEventKeyUp: {
GHOST_TEventKeyData *kd = customdata;
event.type = convert_key(kd->key);
+ if (UNLIKELY(event.type == EVENT_NONE)) {
+ break;
+ }
+
event.ascii = kd->ascii;
/* Might be not NULL terminated. */
memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf));
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index edce3914666..1369ee99cd2 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -2005,20 +2005,20 @@ void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt))
void wm_autosave_delete(void)
{
- char filename[FILE_MAX];
+ char filepath[FILE_MAX];
- wm_autosave_location(filename);
+ wm_autosave_location(filepath);
- if (BLI_exists(filename)) {
+ if (BLI_exists(filepath)) {
char str[FILE_MAX];
BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), BLENDER_QUIT_FILE);
/* if global undo; remove tempsave, otherwise rename */
if (U.uiflag & USER_GLOBALUNDO) {
- BLI_delete(filename, false, false);
+ BLI_delete(filepath, false, false);
}
else {
- BLI_rename(filename, str);
+ BLI_rename(filepath, str);
}
}
}
@@ -2965,10 +2965,10 @@ static int wm_recover_auto_save_exec(bContext *C, wmOperator *op)
static int wm_recover_auto_save_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- char filename[FILE_MAX];
+ char filepath[FILE_MAX];
- wm_autosave_location(filename);
- RNA_string_set(op->ptr, "filepath", filename);
+ wm_autosave_location(filepath);
+ RNA_string_set(op->ptr, "filepath", filepath);
wm_open_init_use_scripts(op, true);
WM_event_add_fileselect(C, op);
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 6a9776c6933..8d6741dcfb6 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -440,19 +440,19 @@ void WM_exit_ex(bContext *C, const bool do_python)
if (undo_memfile != NULL) {
/* save the undo state as quit.blend */
Main *bmain = CTX_data_main(C);
- char filename[FILE_MAX];
+ char filepath[FILE_MAX];
bool has_edited;
const int fileflags = G.fileflags & ~G_FILE_COMPRESS;
- BLI_join_dirfile(filename, sizeof(filename), BKE_tempdir_base(), BLENDER_QUIT_FILE);
+ BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE);
has_edited = ED_editors_flush_edits(bmain);
if ((has_edited &&
BLO_write_file(
- bmain, filename, fileflags, &(const struct BlendFileWriteParams){0}, NULL)) ||
- (BLO_memfile_write_file(undo_memfile, filename))) {
- printf("Saved session recovery to '%s'\n", filename);
+ bmain, filepath, fileflags, &(const struct BlendFileWriteParams){0}, NULL)) ||
+ (BLO_memfile_write_file(undo_memfile, filepath))) {
+ printf("Saved session recovery to '%s'\n", filepath);
}
}
}
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index 1c7e63749f8..dacc17c2c1e 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -518,6 +518,14 @@ void WM_operator_properties_mouse_select(wmOperatorType *ot)
"Deselect On Nothing",
"Deselect all when nothing under the cursor");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ /* TODO: currently only used for the 3D viewport. */
+ prop = RNA_def_boolean(ot->srna,
+ "select_passthrough",
+ false,
+ "Only Select Unselected",
+ "Ignore the select action when the element is already selected");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
void WM_operator_properties_checker_interval(wmOperatorType *ot, bool nth_can_disable)
diff --git a/source/blender/windowmanager/intern/wm_operator_utils.c b/source/blender/windowmanager/intern/wm_operator_utils.c
index 5a817075cd5..bde072bf000 100644
--- a/source/blender/windowmanager/intern/wm_operator_utils.c
+++ b/source/blender/windowmanager/intern/wm_operator_utils.c
@@ -32,9 +32,15 @@
int WM_operator_flag_only_pass_through_on_press(int retval, const struct wmEvent *event)
{
- if ((event->val != KM_PRESS) &&
- ((retval & OPERATOR_PASS_THROUGH) && (retval & OPERATOR_FINISHED))) {
- retval &= ~OPERATOR_PASS_THROUGH;
+ if (event->val != KM_PRESS) {
+ if (retval & OPERATOR_PASS_THROUGH) {
+ /* Operators that use this function should either finish or cancel,
+ * otherwise non-press events will be passed through to other key-map items. */
+ BLI_assert((retval & ~OPERATOR_PASS_THROUGH) != 0);
+ if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
+ retval &= ~OPERATOR_PASS_THROUGH;
+ }
+ }
}
return retval;
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 896139796ee..b45c638d7b9 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -51,6 +51,7 @@
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
+#include "BKE_image_format.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
@@ -1990,7 +1991,7 @@ static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot)
{
ot->name = "Toggle Window Fullscreen";
ot->idname = "WM_OT_window_fullscreen_toggle";
- ot->description = "Toggle the current window fullscreen";
+ ot->description = "Toggle the current window full-screen";
ot->exec = wm_window_fullscreen_toggle_exec;
ot->poll = WM_operator_winactive;
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index cbccc525f0f..ea4f4987190 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -1215,6 +1215,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
wmEvent event;
wm_event_init_from_window(win, &event);
event.type = MOUSEMOVE;
+ event.val = KM_NOTHING;
copy_v2_v2_int(event.prev_xy, event.xy);
event.flag = 0;
@@ -1346,6 +1347,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
/* activate region */
event.type = MOUSEMOVE;
+ event.val = KM_NOTHING;
copy_v2_v2_int(event.prev_xy, event.xy);
event.flag = 0;
diff --git a/source/blender/windowmanager/message_bus/wm_message_bus.h b/source/blender/windowmanager/message_bus/wm_message_bus.h
index ccb9b92349a..1bc983f20ad 100644
--- a/source/blender/windowmanager/message_bus/wm_message_bus.h
+++ b/source/blender/windowmanager/message_bus/wm_message_bus.h
@@ -195,16 +195,6 @@ typedef struct wmMsgSubscribeKey_RNA {
wmMsg_RNA msg;
} wmMsgSubscribeKey_RNA;
-#ifdef __GNUC__
-# define _WM_MESSAGE_EXTERN_BEGIN \
- _Pragma("GCC diagnostic push"); \
- _Pragma("GCC diagnostic ignored \"-Wredundant-decls\"");
-# define _WM_MESSAGE_EXTERN_END _Pragma("GCC diagnostic pop");
-#else
-# define _WM_MESSAGE_EXTERN_BEGIN
-# define _WM_MESSAGE_EXTERN_END
-#endif
-
void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msgtype_info);
wmMsgSubscribeKey_RNA *WM_msg_lookup_rna(struct wmMsgBus *mbus,
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c
index 4321e0f673e..7c6caaa876e 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_session.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c
@@ -1352,7 +1352,7 @@ static void wm_xr_session_surface_draw(bContext *C)
GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data);
- /* There's no active framebuffer if the session was cancelled (exception while drawing views). */
+ /* There's no active frame-buffer if the session was canceled (exception while drawing views). */
if (GPU_framebuffer_active_get()) {
GPU_framebuffer_restore();
}
diff --git a/source/creator/creator.c b/source/creator/creator.c
index ec85786c7a4..6c95ee3e490 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -488,6 +488,9 @@ int main(int argc,
WM_init(C, argc, (const char **)argv);
+ /* Need to be after WM init so that userpref are loaded. */
+ RE_engines_init_experimental();
+
#ifndef WITH_PYTHON
printf(
"\n* WARNING * - Blender compiled without Python!\n"
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 6651aa77725..e1f5bb6377d 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -35,7 +35,7 @@
# include "BKE_context.h"
# include "BKE_global.h"
-# include "BKE_image.h"
+# include "BKE_image_format.h"
# include "BKE_lib_id.h"
# include "BKE_main.h"
# include "BKE_report.h"
@@ -828,7 +828,7 @@ static int arg_handle_log_show_timestamp_set(int UNUSED(argc),
}
static const char arg_handle_log_file_set_doc[] =
- "<filename>\n"
+ "<filepath>\n"
"\tSet a file to output the log to.";
static int arg_handle_log_file_set(int argc, const char **argv, void *UNUSED(data))
{
@@ -1432,7 +1432,7 @@ static const char arg_handle_image_type_set_doc[] =
"\t'TGA' 'RAWTGA' 'JPEG' 'IRIS' 'IRIZ' 'AVIRAW' 'AVIJPEG' 'PNG' 'BMP'\n"
"\n"
"\tFormats that can be compiled into Blender, not available on all systems:\n"
- "\t'HDR' 'TIFF' 'OPEN_EXR' 'OPEN_EXR_MULTILAYER' 'MPEG' 'CINEON' 'DPX' 'DDS' 'JP2'";
+ "\t'HDR' 'TIFF' 'OPEN_EXR' 'OPEN_EXR_MULTILAYER' 'MPEG' 'CINEON' 'DPX' 'DDS' 'JP2' 'WEBP'";
static int arg_handle_image_type_set(int argc, const char **argv, void *data)
{
bContext *C = data;
@@ -1752,7 +1752,7 @@ static int arg_handle_frame_skip_set(int argc, const char **argv, void *data)
}
static const char arg_handle_python_file_run_doc[] =
- "<filename>\n"
+ "<filepath>\n"
"\tRun the given Python script file.";
static int arg_handle_python_file_run(int argc, const char **argv, void *data)
{
@@ -1762,12 +1762,12 @@ static int arg_handle_python_file_run(int argc, const char **argv, void *data)
/* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
if (argc > 1) {
/* Make the path absolute because its needed for relative linked blends to be found */
- char filename[FILE_MAX];
- BLI_strncpy(filename, argv[1], sizeof(filename));
- BLI_path_abs_from_cwd(filename, sizeof(filename));
+ char filepath[FILE_MAX];
+ BLI_strncpy(filepath, argv[1], sizeof(filepath));
+ BLI_path_abs_from_cwd(filepath, sizeof(filepath));
bool ok;
- BPY_CTX_SETUP(ok = BPY_run_filepath(C, filename, NULL));
+ BPY_CTX_SETUP(ok = BPY_run_filepath(C, filepath, NULL));
if (!ok && app_state.exit_code_on_error.python) {
printf("\nError: script failed, file: '%s', exiting.\n", argv[1]);
BPY_python_end();
@@ -1952,22 +1952,22 @@ static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data)
bool success;
/* Make the path absolute because its needed for relative linked blends to be found */
- char filename[FILE_MAX];
+ char filepath[FILE_MAX];
/* NOTE: we could skip these, but so far we always tried to load these files. */
if (argv[0][0] == '-') {
fprintf(stderr, "unknown argument, loading as file: %s\n", argv[0]);
}
- BLI_strncpy(filename, argv[0], sizeof(filename));
- BLI_path_slash_native(filename);
- BLI_path_abs_from_cwd(filename, sizeof(filename));
- BLI_path_normalize(NULL, filename);
+ BLI_strncpy(filepath, argv[0], sizeof(filepath));
+ BLI_path_slash_native(filepath);
+ BLI_path_abs_from_cwd(filepath, sizeof(filepath));
+ BLI_path_normalize(NULL, filepath);
/* load the file */
BKE_reports_init(&reports, RPT_PRINT);
- WM_file_autoexec_init(filename);
- success = WM_file_read(C, filename, &reports);
+ WM_file_autoexec_init(filepath);
+ success = WM_file_read(C, filepath, &reports);
BKE_reports_clear(&reports);
if (success) {
@@ -1988,16 +1988,16 @@ static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data)
return -1;
}
- if (BLO_has_bfile_extension(filename)) {
+ if (BLO_has_bfile_extension(filepath)) {
/* Just pretend a file was loaded, so the user can press Save and it'll
- * save at the filename from the CLI. */
- STRNCPY(G_MAIN->filepath, filename);
- printf("... opened default scene instead; saving will write to: %s\n", filename);
+ * save at the filepath from the CLI. */
+ STRNCPY(G_MAIN->filepath, filepath);
+ printf("... opened default scene instead; saving will write to: %s\n", filepath);
}
else {
printf(
"Error: argument has no '.blend' file extension, not using as new file, exiting! %s\n",
- filename);
+ filepath);
G.is_break = true;
WM_exit(C);
}