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:
authorMichael Kowalski <makowalski@nvidia.com>2022-01-07 02:02:02 +0300
committerMichael Kowalski <makowalski@nvidia.com>2022-01-07 02:02:02 +0300
commit442b8e3dcdbe200d9ac449a07a89726a3329ac14 (patch)
tree10af735a2d0c6aee1c321a372940387bc590f391
parent18bf798dc6032f67c247f0b64e246e94a88f3f5f (diff)
parent3e92b4ed2408eacd126c0deb7790891025b2c075 (diff)
Merge remote-tracking branch 'origin/master' into temp-usd-preview-surf-export
-rwxr-xr-xbuild_files/build_environment/install_deps.sh14
-rw-r--r--build_files/build_environment/patches/usd.diff35
-rw-r--r--intern/cycles/blender/mesh.cpp36
-rw-r--r--intern/cycles/blender/pointcloud.cpp60
-rw-r--r--intern/cycles/blender/python.cpp34
-rw-r--r--intern/cycles/blender/shader.cpp4
-rw-r--r--intern/cycles/blender/sync.h2
-rw-r--r--intern/cycles/blender/util.h54
-rw-r--r--intern/cycles/bvh/build.cpp14
-rw-r--r--intern/cycles/bvh/bvh2.cpp12
-rw-r--r--intern/cycles/bvh/embree.cpp2
-rw-r--r--intern/cycles/bvh/split.cpp6
-rw-r--r--intern/cycles/bvh/unaligned.cpp4
-rw-r--r--intern/cycles/device/denoise.cpp2
-rw-r--r--intern/cycles/device/denoise.h6
-rw-r--r--intern/cycles/device/optix/device_impl.cpp81
-rw-r--r--intern/cycles/device/optix/device_impl.h1
-rw-r--r--intern/cycles/device/queue.h5
-rw-r--r--intern/cycles/kernel/bvh/shadow_all.h6
-rw-r--r--intern/cycles/kernel/bvh/traversal.h4
-rw-r--r--intern/cycles/kernel/bvh/util.h12
-rw-r--r--intern/cycles/kernel/closure/bsdf.h2
-rw-r--r--intern/cycles/kernel/closure/bsdf_hair_principled.h4
-rw-r--r--intern/cycles/kernel/device/gpu/kernel.h14
-rw-r--r--intern/cycles/kernel/device/metal/kernel.metal6
-rw-r--r--intern/cycles/kernel/device/optix/kernel.cu12
-rw-r--r--intern/cycles/kernel/geom/attribute.h2
-rw-r--r--intern/cycles/kernel/geom/curve.h6
-rw-r--r--intern/cycles/kernel/geom/curve_intersect.h24
-rw-r--r--intern/cycles/kernel/geom/point.h23
-rw-r--r--intern/cycles/kernel/geom/point_intersect.h21
-rw-r--r--intern/cycles/kernel/geom/primitive.h34
-rw-r--r--intern/cycles/kernel/geom/shader_data.h62
-rw-r--r--intern/cycles/kernel/integrator/shade_surface.h2
-rw-r--r--intern/cycles/kernel/light/sample.h2
-rw-r--r--intern/cycles/kernel/osl/services.cpp16
-rw-r--r--intern/cycles/kernel/svm/bevel.h8
-rw-r--r--intern/cycles/kernel/svm/closure.h6
-rw-r--r--intern/cycles/kernel/svm/geometry.h2
-rw-r--r--intern/cycles/kernel/svm/tex_coord.h2
-rw-r--r--intern/cycles/kernel/svm/wireframe.h10
-rw-r--r--intern/cycles/kernel/types.h54
-rw-r--r--intern/cycles/scene/geometry.cpp32
-rw-r--r--intern/cycles/scene/geometry.h2
-rw-r--r--intern/cycles/scene/image.cpp7
-rw-r--r--intern/cycles/scene/object.cpp2
-rw-r--r--intern/cycles/scene/object.h2
-rw-r--r--intern/cycles/scene/pass.cpp5
-rw-r--r--intern/cycles/scene/shader_nodes.cpp2
-rw-r--r--intern/cycles/session/denoising.cpp569
-rw-r--r--intern/cycles/session/denoising.h76
-rw-r--r--intern/ghost/intern/GHOST_Window.h4
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h74
-rw-r--r--intern/iksolver/intern/IK_QJacobian.cpp6
-rw-r--r--intern/libmv/intern/utildefines.h18
-rw-r--r--intern/libmv/libmv/autotrack/autotrack.cc2
-rw-r--r--intern/libmv/libmv/build/build_config.h2
-rw-r--r--intern/libmv/libmv/image/tuple.h2
-rw-r--r--intern/libmv/libmv/multiview/panography.h2
-rw-r--r--intern/libmv/libmv/numeric/numeric.h2
-rw-r--r--intern/libmv/libmv/numeric/poly.h2
-rw-r--r--intern/memutil/MEM_RefCounted.h2
-rw-r--r--intern/numaapi/source/build_config.h2
-rw-r--r--intern/opencolorio/fallback_impl.cc4
-rw-r--r--intern/opencolorio/gpu_shader_display_transform.glsl2
-rw-r--r--intern/opencolorio/ocio_impl.cc42
-rw-r--r--intern/opensubdiv/CMakeLists.txt11
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output.cc35
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output.h582
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output_cpu.cc23
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output_cpu.h66
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output_gpu.cc120
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output_gpu.h71
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_cache_impl.cc47
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_cache_impl.h38
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_capi.cc122
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_impl.cc649
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_impl.h69
-rw-r--r--intern/opensubdiv/internal/evaluator/patch_map.cc213
-rw-r--r--intern/opensubdiv/internal/evaluator/patch_map.h264
-rw-r--r--intern/opensubdiv/internal/topology/mesh_topology.cc2
-rw-r--r--intern/opensubdiv/internal/topology/mesh_topology.h4
-rw-r--r--intern/opensubdiv/internal/topology/topology_refiner_capi.cc4
-rw-r--r--intern/opensubdiv/opensubdiv_converter_capi.h2
-rw-r--r--intern/opensubdiv/opensubdiv_evaluator_capi.h101
-rw-r--r--intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc18
-rw-r--r--intern/utfconv/utfconv.c2
-rw-r--r--release/datafiles/fonts/droidsans.ttfbin5704060 -> 5342868 bytes
m---------release/datafiles/locale0
-rw-r--r--release/datafiles/userdef/userdef_default.c2
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/modules/bl_i18n_utils/settings.py1
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils.py1
-rw-r--r--release/scripts/modules/rna_manual_reference.py171
-rw-r--r--release/scripts/startup/bl_operators/presets.py2
-rw-r--r--release/scripts/startup/bl_operators/sequencer.py8
-rw-r--r--release/scripts/startup/bl_ui/properties_constraint.py80
-rw-r--r--release/scripts/startup/bl_ui/space_filebrowser.py2
-rw-r--r--release/scripts/startup/bl_ui/space_graph.py12
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py3
-rw-r--r--release/scripts/startup/bl_ui/space_userpref.py12
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py2
-rw-r--r--release/scripts/startup/nodeitems_builtins.py2
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h8
-rw-r--r--source/blender/blenkernel/BKE_action.h22
-rw-r--r--source/blender/blenkernel/BKE_animsys.h5
-rw-r--r--source/blender/blenkernel/BKE_attribute.h4
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh46
-rw-r--r--source/blender/blenkernel/BKE_bpath.h2
-rw-r--r--source/blender/blenkernel/BKE_collection.h14
-rw-r--r--source/blender/blenkernel/BKE_context.h5
-rw-r--r--source/blender/blenkernel/BKE_fcurve_driver.h7
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh121
-rw-r--r--source/blender/blenkernel/BKE_image.h51
-rw-r--r--source/blender/blenkernel/BKE_mesh.h7
-rw-r--r--source/blender/blenkernel/BKE_mesh_wrapper.h3
-rw-r--r--source/blender/blenkernel/BKE_node.h89
-rw-r--r--source/blender/blenkernel/BKE_node_tree_update.h110
-rw-r--r--source/blender/blenkernel/BKE_object.h11
-rw-r--r--source/blender/blenkernel/BKE_pointcloud.h2
-rw-r--r--source/blender/blenkernel/BKE_scene.h2
-rw-r--r--source/blender/blenkernel/BKE_screen.h19
-rw-r--r--source/blender/blenkernel/BKE_spline.hh26
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h14
-rw-r--r--source/blender/blenkernel/BKE_subdiv_eval.h14
-rw-r--r--source/blender/blenkernel/BKE_subdiv_foreach.h3
-rw-r--r--source/blender/blenkernel/BKE_subdiv_modifier.h71
-rw-r--r--source/blender/blenkernel/BKE_undo_system.h2
-rw-r--r--source/blender/blenkernel/CMakeLists.txt8
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc142
-rw-r--r--source/blender/blenkernel/intern/action.c20
-rw-r--r--source/blender/blenkernel/intern/anim_data.c35
-rw-r--r--source/blender/blenkernel/intern/asset_catalog.cc16
-rw-r--r--source/blender/blenkernel/intern/asset_catalog_test.cc38
-rw-r--r--source/blender/blenkernel/intern/blendfile_link_append.c34
-rw-r--r--source/blender/blenkernel/intern/bpath.c6
-rw-r--r--source/blender/blenkernel/intern/bvhutils.cc2
-rw-r--r--source/blender/blenkernel/intern/collection.c94
-rw-r--r--source/blender/blenkernel/intern/cryptomatte.cc4
-rw-r--r--source/blender/blenkernel/intern/curve.cc75
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc10
-rw-r--r--source/blender/blenkernel/intern/curve_to_mesh_convert.cc15
-rw-r--r--source/blender/blenkernel/intern/curveprofile.cc2
-rw-r--r--source/blender/blenkernel/intern/customdata.cc (renamed from source/blender/blenkernel/intern/customdata.c)970
-rw-r--r--source/blender/blenkernel/intern/data_transfer_intern.h8
-rw-r--r--source/blender/blenkernel/intern/displist.cc26
-rw-r--r--source/blender/blenkernel/intern/fcurve.c4
-rw-r--r--source/blender/blenkernel/intern/fcurve_driver.c7
-rw-r--r--source/blender/blenkernel/intern/geometry_component_instances.cc60
-rw-r--r--source/blender/blenkernel/intern/geometry_set.cc12
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc20
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc18
-rw-r--r--source/blender/blenkernel/intern/hair.cc (renamed from source/blender/blenkernel/intern/hair.c)114
-rw-r--r--source/blender/blenkernel/intern/image.c354
-rw-r--r--source/blender/blenkernel/intern/image_gpu.cc2
-rw-r--r--source/blender/blenkernel/intern/image_save.c53
-rw-r--r--source/blender/blenkernel/intern/layer.c33
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c3
-rw-r--r--source/blender/blenkernel/intern/lib_override.c54
-rw-r--r--source/blender/blenkernel/intern/lib_query.c2
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c8
-rw-r--r--source/blender/blenkernel/intern/linestyle.c3
-rw-r--r--source/blender/blenkernel/intern/mesh.cc39
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc35
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc1
-rw-r--r--source/blender/blenkernel/intern/mesh_wrapper.c88
-rw-r--r--source/blender/blenkernel/intern/modifier.c1
-rw-r--r--source/blender/blenkernel/intern/movieclip.c13
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_smooth.c5
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_util.c2
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_vertcos.c3
-rw-r--r--source/blender/blenkernel/intern/multires_versioning.c2
-rw-r--r--source/blender/blenkernel/intern/node.cc1262
-rw-r--r--source/blender/blenkernel/intern/node_tree_update.cc1669
-rw-r--r--source/blender/blenkernel/intern/object.cc56
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc4
-rw-r--r--source/blender/blenkernel/intern/pointcache.c5
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc75
-rw-r--r--source/blender/blenkernel/intern/screen.c26
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc4
-rw-r--r--source/blender/blenkernel/intern/spline_bezier.cc18
-rw-r--r--source/blender/blenkernel/intern/spline_nurbs.cc17
-rw-r--r--source/blender/blenkernel/intern/spline_poly.cc8
-rw-r--r--source/blender/blenkernel/intern/subdiv.c12
-rw-r--r--source/blender/blenkernel/intern/subdiv_ccg.c3
-rw-r--r--source/blender/blenkernel/intern/subdiv_deform.c6
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c112
-rw-r--r--source/blender/blenkernel/intern/subdiv_foreach.c3
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c6
-rw-r--r--source/blender/blenkernel/intern/subdiv_modifier.c162
-rw-r--r--source/blender/blenkernel/intern/volume.cc15
-rw-r--r--source/blender/blenlib/BLI_assert.h1
-rw-r--r--source/blender/blenlib/BLI_color.hh19
-rw-r--r--source/blender/blenlib/BLI_compiler_compat.h2
-rw-r--r--source/blender/blenlib/BLI_delaunay_2d.h2
-rw-r--r--source/blender/blenlib/BLI_dlrbTree.h6
-rw-r--r--source/blender/blenlib/BLI_endian_switch.h2
-rw-r--r--source/blender/blenlib/BLI_endian_switch_inline.h3
-rw-r--r--source/blender/blenlib/BLI_fileops.hh52
-rw-r--r--source/blender/blenlib/BLI_filereader.h12
-rw-r--r--source/blender/blenlib/BLI_float3.hh16
-rw-r--r--source/blender/blenlib/BLI_ghash.h2
-rw-r--r--source/blender/blenlib/BLI_hash.hh10
-rw-r--r--source/blender/blenlib/BLI_kdtree_impl.h2
-rw-r--r--source/blender/blenlib/BLI_linklist_lockfree.h11
-rw-r--r--source/blender/blenlib/BLI_listbase.h29
-rw-r--r--source/blender/blenlib/BLI_math_base.h6
-rw-r--r--source/blender/blenlib/BLI_math_bits.h5
-rw-r--r--source/blender/blenlib/BLI_math_geom.h6
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h21
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h30
-rw-r--r--source/blender/blenlib/BLI_math_vector.h2
-rw-r--r--source/blender/blenlib/BLI_memory_utils.hh6
-rw-r--r--source/blender/blenlib/BLI_mempool.h4
-rw-r--r--source/blender/blenlib/BLI_path_util.h6
-rw-r--r--source/blender/blenlib/BLI_quadric.h9
-rw-r--r--source/blender/blenlib/BLI_scanfill.h1
-rw-r--r--source/blender/blenlib/BLI_serialize.hh25
-rw-r--r--source/blender/blenlib/BLI_session_uuid.h7
-rw-r--r--source/blender/blenlib/BLI_sort.h2
-rw-r--r--source/blender/blenlib/BLI_span.hh5
-rw-r--r--source/blender/blenlib/BLI_sys_types.h2
-rw-r--r--source/blender/blenlib/BLI_system.h10
-rw-r--r--source/blender/blenlib/BLI_task.h2
-rw-r--r--source/blender/blenlib/BLI_threads.h2
-rw-r--r--source/blender/blenlib/BLI_timer.h11
-rw-r--r--source/blender/blenlib/BLI_vector.hh2
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh10
-rw-r--r--source/blender/blenlib/BLI_virtual_vector_array.hh2
-rw-r--r--source/blender/blenlib/BLI_winstuff.h5
-rw-r--r--source/blender/blenlib/CMakeLists.txt3
-rw-r--r--source/blender/blenlib/intern/fileops.cc51
-rw-r--r--source/blender/blenlib/intern/listbase.c20
-rw-r--r--source/blender/blenlib/intern/math_color_blend_inline.c16
-rw-r--r--source/blender/blenlib/intern/mesh_intersect.cc4
-rw-r--r--source/blender/blenlib/intern/path_util.c22
-rw-r--r--source/blender/blenlib/intern/serialize.cc23
-rw-r--r--source/blender/blenlib/intern/string_cursor_utf8.c2
-rw-r--r--source/blender/blenlib/intern/task_graph.cc2
-rw-r--r--source/blender/blenlib/intern/task_scheduler.cc6
-rw-r--r--source/blender/blenlib/tests/BLI_fileops_test.cc40
-rw-r--r--source/blender/blenlib/tests/BLI_listbase_test.cc25
-rw-r--r--source/blender/blenlib/tests/BLI_memory_utils_test.cc7
-rw-r--r--source/blender/blenlib/tests/BLI_serialize_test.cc4
-rw-r--r--source/blender/blenlib/tests/BLI_task_test.cc4
-rw-r--r--source/blender/blenlib/tests/BLI_vector_test.cc11
-rw-r--r--source/blender/blenloader/CMakeLists.txt1
-rw-r--r--source/blender/blenloader/intern/versioning_250.c10
-rw-r--r--source/blender/blenloader/intern/versioning_280.c3
-rw-r--r--source/blender/blenloader/intern/versioning_300.c91
-rw-r--r--source/blender/blenloader/intern/versioning_common.cc20
-rw-r--r--source/blender/blenloader/intern/versioning_common.h2
-rw-r--r--source/blender/blenloader/intern/versioning_cycles.c29
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c5
-rw-r--r--source/blender/blenloader/tests/blendfile_loading_base_test.cc8
-rw-r--r--source/blender/compositor/intern/COM_Debug.cc6
-rw-r--r--source/blender/compositor/intern/COM_compositor.cc2
-rw-r--r--source/blender/compositor/operations/COM_CropOperation.cc30
-rw-r--r--source/blender/compositor/operations/COM_KeyingScreenOperation.cc5
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h6
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc61
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.h17
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc17
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc78
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc2
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc1
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc14
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query_iter.cc9
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc6
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.cc4
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.h6
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.cc2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.h1
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.cc3
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_operation.h3
-rw-r--r--source/blender/draw/CMakeLists.txt18
-rw-r--r--source/blender/draw/DRW_engine.h4
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightcache.h8
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader_fx.c7
-rw-r--r--source/blender/draw/engines/overlay/overlay_armature.c2
-rw-r--r--source/blender/draw/intern/draw_cache.c24
-rw-r--r--source/blender/draw/intern/draw_cache_extract.h24
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc102
-rw-r--r--source/blender/draw/intern/draw_cache_impl_gpencil.c2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_hair.cc (renamed from source/blender/draw/intern/draw_cache_impl_hair.c)43
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c30
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc1932
-rw-r--r--source/blender/draw/intern/draw_manager.c4
-rw-r--r--source/blender/draw/intern/draw_manager_data.c7
-rw-r--r--source/blender/draw/intern/draw_subdivision.h231
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.h24
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc156
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc31
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc72
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc72
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc30
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc93
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc83
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc97
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc67
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc59
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc65
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc48
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc27
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc122
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc109
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc97
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc89
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc111
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc48
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl230
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl57
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl43
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_lib.glsl176
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl56
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl34
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl416
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl97
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl80
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl31
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl52
-rw-r--r--source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl47
-rw-r--r--source/blender/editors/animation/drivers.c20
-rw-r--r--source/blender/editors/animation/keyframes_general.c78
-rw-r--r--source/blender/editors/armature/pose_edit.c2
-rw-r--r--source/blender/editors/armature/pose_lib.c2
-rw-r--r--source/blender/editors/armature/pose_select.c2
-rw-r--r--source/blender/editors/asset/intern/asset_indexer.cc49
-rw-r--r--source/blender/editors/asset/intern/asset_ops.cc8
-rw-r--r--source/blender/editors/asset/intern/asset_temp_id_consumer.cc5
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c14
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c55
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c13
-rw-r--r--source/blender/editors/gpencil/gpencil_mesh.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c101
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c60
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c10
-rw-r--r--source/blender/editors/include/ED_gpencil.h2
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h11
-rw-r--r--source/blender/editors/include/ED_node.h22
-rw-r--r--source/blender/editors/include/ED_render.h4
-rw-r--r--source/blender/editors/include/UI_interface.h184
-rw-r--r--source/blender/editors/interface/interface.c362
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c8
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c20
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_driver.c2
-rw-r--r--source/blender/editors/interface/interface_handlers.c13
-rw-r--r--source/blender/editors/interface/interface_layout.c5
-rw-r--r--source/blender/editors/interface/interface_ops.c28
-rw-r--r--source/blender/editors/interface/interface_region_search.cc4
-rw-r--r--source/blender/editors/interface/interface_templates.c166
-rw-r--r--source/blender/editors/interface/interface_view.cc4
-rw-r--r--source/blender/editors/io/CMakeLists.txt16
-rw-r--r--source/blender/editors/io/io_obj.c369
-rw-r--r--source/blender/editors/io/io_obj.h25
-rw-r--r--source/blender/editors/io/io_ops.c2
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c12
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c3
-rw-r--r--source/blender/editors/object/object_constraint.c8
-rw-r--r--source/blender/editors/object/object_edit.c10
-rw-r--r--source/blender/editors/object/object_gpencil_modifier.c15
-rw-r--r--source/blender/editors/object/object_hook.c2
-rw-r--r--source/blender/editors/object/object_relations.c7
-rw-r--r--source/blender/editors/object/object_remesh.cc4
-rw-r--r--source/blender/editors/object/object_transform.c13
-rw-r--r--source/blender/editors/object/object_utils.c2
-rw-r--r--source/blender/editors/physics/particle_object.c15
-rw-r--r--source/blender/editors/render/CMakeLists.txt16
-rw-r--r--source/blender/editors/render/render_intern.hh (renamed from source/blender/editors/render/render_intern.h)0
-rw-r--r--source/blender/editors/render/render_internal.cc (renamed from source/blender/editors/render/render_internal.c)134
-rw-r--r--source/blender/editors/render/render_opengl.cc (renamed from source/blender/editors/render/render_opengl.c)178
-rw-r--r--source/blender/editors/render/render_ops.cc (renamed from source/blender/editors/render/render_ops.c)6
-rw-r--r--source/blender/editors/render/render_preview.cc (renamed from source/blender/editors/render/render_preview.c)346
-rw-r--r--source/blender/editors/render/render_shading.cc (renamed from source/blender/editors/render/render_shading.c)187
-rw-r--r--source/blender/editors/render/render_update.cc (renamed from source/blender/editors/render/render_update.c)62
-rw-r--r--source/blender/editors/render/render_view.cc (renamed from source/blender/editors/render/render_view.c)52
-rw-r--r--source/blender/editors/screen/area.c2
-rw-r--r--source/blender/editors/screen/screen_context.c2
-rw-r--r--source/blender/editors/screen/screen_ops.c25
-rw-r--r--source/blender/editors/screen/screendump.c3
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h59
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c45
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c3868
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_brushes.c2847
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h123
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_ops.c1141
-rw-r--r--source/blender/editors/space_clip/space_clip.c6
-rw-r--r--source/blender/editors/space_file/asset_catalog_tree_view.cc5
-rw-r--r--source/blender/editors/space_file/file_ops.c3
-rw-r--r--source/blender/editors/space_file/filesel.c7
-rw-r--r--source/blender/editors/space_graph/graph_intern.h2
-rw-r--r--source/blender/editors/space_graph/graph_ops.c2
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c256
-rw-r--r--source/blender/editors/space_image/image_ops.c32
-rw-r--r--source/blender/editors/space_image/image_sequence.c68
-rw-r--r--source/blender/editors/space_info/info_stats.cc3
-rw-r--r--source/blender/editors/space_node/drawnode.cc29
-rw-r--r--source/blender/editors/space_node/link_drag_search.cc46
-rw-r--r--source/blender/editors/space_node/node_add.cc52
-rw-r--r--source/blender/editors/space_node/node_draw.cc51
-rw-r--r--source/blender/editors/space_node/node_edit.cc319
-rw-r--r--source/blender/editors/space_node/node_geometry_attribute_search.cc4
-rw-r--r--source/blender/editors/space_node/node_group.cc89
-rw-r--r--source/blender/editors/space_node/node_intern.hh5
-rw-r--r--source/blender/editors/space_node/node_relationships.cc248
-rw-r--r--source/blender/editors/space_node/node_templates.cc25
-rw-r--r--source/blender/editors/space_node/node_view.cc4
-rw-r--r--source/blender/editors/space_node/space_node.cc48
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c38
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c12
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c15
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc41
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_column.cc6
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_context.cc9
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_panels.cc2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc3
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc4
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c55
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_armature.c6
-rw-r--r--source/blender/editors/transform/transform_convert.c4
-rw-r--r--source/blender/editors/transform/transform_convert.h1
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c2
-rw-r--r--source/blender/editors/transform/transform_convert_mask.c7
-rw-r--r--source/blender/editors/transform/transform_convert_node.c3
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c45
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c10
-rw-r--r--source/blender/editors/transform/transform_mode.c2
-rw-r--r--source/blender/editors/transform/transform_mode_timetranslate.c15
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c7
-rw-r--r--source/blender/editors/transform/transform_orientations.c4
-rw-r--r--source/blender/editors/transform/transform_snap.c13
-rw-r--r--source/blender/editors/transform/transform_snap_object.c2
-rw-r--r--source/blender/editors/undo/ed_undo.c87
-rw-r--r--source/blender/editors/util/ed_util_imbuf.c28
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c2
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp3
-rw-r--r--source/blender/freestyle/intern/image/GaussianFilter.h4
-rw-r--r--source/blender/freestyle/intern/stroke/Operators.cpp6
-rw-r--r--source/blender/functions/FN_field.hh46
-rw-r--r--source/blender/functions/FN_generic_virtual_array.hh3
-rw-r--r--source/blender/functions/FN_multi_function_procedure.hh13
-rw-r--r--source/blender/functions/intern/field.cc209
-rw-r--r--source/blender/geometry/intern/mesh_to_curve_convert.cc108
-rw-r--r--source/blender/geometry/intern/realize_instances.cc2
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c15
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h2
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h8
-rw-r--r--source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c46
-rw-r--r--source/blender/gpu/GPU_context.h2
-rw-r--r--source/blender/gpu/GPU_index_buffer.h12
-rw-r--r--source/blender/gpu/GPU_material.h4
-rw-r--r--source/blender/gpu/GPU_state.h4
-rw-r--r--source/blender/gpu/GPU_vertex_buffer.h7
-rw-r--r--source/blender/gpu/intern/gpu_context.cc9
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.cc2
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer.cc19
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer_private.hh4
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c5
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc2
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.cc2
-rw-r--r--source/blender/gpu/intern/gpu_texture.cc8
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.cc18
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer_private.hh4
-rw-r--r--source/blender/gpu/opengl/gl_index_buffer.cc10
-rw-r--r--source/blender/gpu/opengl/gl_index_buffer.hh4
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc4
-rw-r--r--source/blender/gpu/opengl/gl_state.hh6
-rw-r--r--source/blender/gpu/opengl/gl_vertex_buffer.cc16
-rw-r--r--source/blender/gpu/opengl/gl_vertex_buffer.hh7
-rw-r--r--source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl14
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp4
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp8
-rw-r--r--source/blender/imbuf/intern/transform.cc13
-rw-r--r--source/blender/io/CMakeLists.txt1
-rw-r--r--source/blender/io/collada/AnimationImporter.cpp4
-rw-r--r--source/blender/io/collada/Materials.cpp4
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc2
-rw-r--r--source/blender/io/gpencil/intern/gpencil_io_export_svg.cc2
-rw-r--r--source/blender/io/usd/intern/usd_reader_material.cc3
-rw-r--r--source/blender/io/wavefront_obj/CMakeLists.txt84
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.cc34
-rw-r--r--source/blender/io/wavefront_obj/IO_wavefront_obj.h97
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc626
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh132
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_io.hh340
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc489
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh131
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc362
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh104
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc122
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh57
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_exporter.cc302
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_exporter.hh88
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc417
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh149
-rw-r--r--source/blender/makesdna/DNA_ID.h3
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h5
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h28
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h287
-rw-r--r--source/blender/makesdna/DNA_movieclip_types.h10
-rw-r--r--source/blender/makesdna/DNA_nla_types.h4
-rw-r--r--source/blender/makesdna/DNA_node_types.h129
-rw-r--r--source/blender/makesdna/DNA_object_force_types.h2
-rw-r--r--source/blender/makesdna/DNA_object_types.h55
-rw-r--r--source/blender/makesdna/DNA_particle_types.h47
-rw-r--r--source/blender/makesdna/DNA_pointcloud_types.h2
-rw-r--r--source/blender/makesdna/DNA_rigidbody_types.h16
-rw-r--r--source/blender/makesdna/DNA_scene_types.h55
-rw-r--r--source/blender/makesdna/DNA_screen_types.h8
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h71
-rw-r--r--source/blender/makesdna/DNA_shader_fx_types.h2
-rw-r--r--source/blender/makesdna/DNA_simulation_types.h2
-rw-r--r--source/blender/makesdna/DNA_space_types.h148
-rw-r--r--source/blender/makesdna/DNA_texture_types.h14
-rw-r--r--source/blender/makesdna/DNA_tracking_types.h40
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h14
-rw-r--r--source/blender/makesdna/DNA_view2d_types.h18
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h2
-rw-r--r--source/blender/makesdna/DNA_volume_types.h22
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h30
-rw-r--r--source/blender/makesdna/DNA_workspace_types.h4
-rw-r--r--source/blender/makesdna/intern/dna_utils.h4
-rw-r--r--source/blender/makesrna/intern/rna_access_compare_override.c8
-rw-r--r--source/blender/makesrna/intern/rna_cloth.c19
-rw-r--r--source/blender/makesrna/intern/rna_color.c2
-rw-r--r--source/blender/makesrna/intern/rna_dynamicpaint.c1
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c1
-rw-r--r--source/blender/makesrna/intern/rna_fluid.c1
-rw-r--r--source/blender/makesrna/intern/rna_image.c2
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c185
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c30
-rw-r--r--source/blender/makesrna/intern/rna_particle.c3
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c1
-rw-r--r--source/blender/makesrna/intern/rna_scene.c6
-rw-r--r--source/blender/makesrna/intern/rna_texture.c2
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c6
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c52
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c27
-rw-r--r--source/blender/modifiers/CMakeLists.txt2
-rw-r--r--source/blender/modifiers/intern/MOD_array.c18
-rw-r--r--source/blender/modifiers/intern/MOD_mask.cc2
-rw-r--r--source/blender/modifiers/intern/MOD_meshsequencecache.c73
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc7
-rw-r--r--source/blender/modifiers/intern/MOD_nodes_evaluator.cc165
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c87
-rw-r--r--source/blender/modifiers/intern/MOD_volume_displace.cc7
-rw-r--r--source/blender/modifiers/intern/MOD_weld.cc (renamed from source/blender/modifiers/intern/MOD_weld.c)1451
-rw-r--r--source/blender/nodes/CMakeLists.txt121
-rw-r--r--source/blender/nodes/NOD_geometry.h4
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh8
-rw-r--r--source/blender/nodes/NOD_node_declaration.hh21
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh11
-rw-r--r--source/blender/nodes/NOD_socket_declarations.hh2
-rw-r--r--source/blender/nodes/NOD_static_types.h6
-rw-r--r--source/blender/nodes/composite/CMakeLists.txt150
-rw-r--r--source/blender/nodes/composite/node_composite_tree.cc54
-rw-r--r--source/blender/nodes/composite/node_composite_util.cc4
-rw-r--r--source/blender/nodes/composite/node_composite_util.hh3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_alphaOver.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_antialiasing.cc7
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_blur.cc5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehblur.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehimage.cc7
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_boxmask.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_brightness.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_channelMatte.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorMatte.cc5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorSpill.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorbalance.cc5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_common.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_composite.cc3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cornerpin.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_crop.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc13
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_curves.cc8
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_defocus.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_denoise.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_despeckle.cc3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_diffMatte.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_dilate.cc5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_directionalblur.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_displace.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc7
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_exposure.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_filter.cc3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_flip.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_gamma.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_glare.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_huecorrect.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_idMask.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.cc14
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_inpaint.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_invert.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_keying.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_lensdist.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_levels.cc3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapRange.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapUV.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mapValue.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mask.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_math.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_mixrgb.cc3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_movieclip.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normal.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_normalize.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_outputFile.cc9
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_pixelate.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_posterize.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_premulkey.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rgb.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_rotate.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_scale.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_setalpha.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_splitViewer.cc6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sunbeams.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switch.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_switchview.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_texture.cc3
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_tonemap.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_trackpos.cc5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_transform.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_translate.cc5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_valToRgb.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_value.cc2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_vecBlur.cc4
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_viewer.cc5
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_zcombine.cc2
-rw-r--r--source/blender/nodes/function/CMakeLists.txt75
-rw-r--r--source/blender/nodes/function/node_function_util.cc4
-rw-r--r--source/blender/nodes/function/node_function_util.hh3
-rw-r--r--source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc14
-rw-r--r--source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc14
-rw-r--r--source/blender/nodes/function/nodes/node_fn_boolean_math.cc18
-rw-r--r--source/blender/nodes/function/nodes/node_fn_compare.cc47
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_to_int.cc16
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_bool.cc18
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_color.cc18
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_int.cc18
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_special_characters.cc13
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_string.cc22
-rw-r--r--source/blender/nodes/function/nodes/node_fn_input_vector.cc19
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_value.cc26
-rw-r--r--source/blender/nodes/function/nodes/node_fn_replace_string.cc12
-rw-r--r--source/blender/nodes/function/nodes/node_fn_rotate_euler.cc17
-rw-r--r--source/blender/nodes/function/nodes/node_fn_slice_string.cc12
-rw-r--r--source/blender/nodes/function/nodes/node_fn_string_length.cc12
-rw-r--r--source/blender/nodes/function/nodes/node_fn_value_to_string.cc12
-rw-r--r--source/blender/nodes/geometry/CMakeLists.txt4
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc4
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc4
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc430
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc35
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_boolean.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_collection_info.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_common.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_length.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc53
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc19
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc34
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc41
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc86
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_image_texture.cc5
-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_curve_tilt.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_id.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_index.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc128
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_normal.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_position.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_radius.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_replace.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_material_selection.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc144
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_object_info.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_proximity.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_components.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc52
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_id.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_position.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_join.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_switch.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_viewer.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc5
-rw-r--r--source/blender/nodes/intern/derived_node_tree.cc3
-rw-r--r--source/blender/nodes/intern/node_common.cc34
-rw-r--r--source/blender/nodes/intern/node_declaration.cc4
-rw-r--r--source/blender/nodes/intern/node_exec.cc7
-rw-r--r--source/blender/nodes/intern/node_socket.cc50
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc18
-rw-r--r--source/blender/nodes/intern/node_util.c183
-rw-r--r--source/blender/nodes/shader/CMakeLists.txt149
-rw-r--r--source/blender/nodes/shader/node_shader_tree.cc (renamed from source/blender/nodes/shader/node_shader_tree.c)257
-rw-r--r--source/blender/nodes/shader/node_shader_util.cc11
-rw-r--r--source/blender/nodes/shader/node_shader_util.hh (renamed from source/blender/nodes/shader/node_shader_util.h)74
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_add_shader.cc (renamed from source/blender/nodes/shader/nodes/node_shader_add_shader.c)34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc (renamed from source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c)39
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_attribute.cc (renamed from source/blender/nodes/shader/nodes/node_shader_attribute.c)22
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_background.cc (renamed from source/blender/nodes/shader/nodes/node_shader_background.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bevel.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bevel.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_blackbody.cc (renamed from source/blender/nodes/shader/nodes/node_shader_blackbody.c)33
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_brightness.cc (renamed from source/blender/nodes/shader/nodes/node_shader_brightness.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c)20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c)22
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c)20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c)22
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c)30
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c)20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bump.cc (renamed from source/blender/nodes/shader/nodes/node_shader_bump.c)47
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_camera.cc (renamed from source/blender/nodes/shader/nodes/node_shader_camera.c)17
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.cc22
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_color_ramp.cc189
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_common.cc (renamed from source/blender/nodes/shader/nodes/node_shader_common.c)74
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_curves.cc62
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_displacement.cc (renamed from source/blender/nodes/shader/nodes/node_shader_displacement.c)20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc (renamed from source/blender/nodes/shader/nodes/node_shader_eevee_specular.c)21
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_emission.cc (renamed from source/blender/nodes/shader/nodes/node_shader_emission.c)18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_fresnel.cc (renamed from source/blender/nodes/shader/nodes/node_shader_fresnel.c)20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_gamma.cc (renamed from source/blender/nodes/shader/nodes/node_shader_gamma.c)20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geometry.cc (renamed from source/blender/nodes/shader/nodes/node_shader_geometry.c)20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hair_info.cc (renamed from source/blender/nodes/shader/nodes/node_shader_hair_info.c)18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_holdout.cc (renamed from source/blender/nodes/shader/nodes/node_shader_holdout.c)18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc (renamed from source/blender/nodes/shader/nodes/node_shader_hueSatVal.c)18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_ies_light.cc (renamed from source/blender/nodes/shader/nodes/node_shader_ies_light.c)18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_invert.cc (renamed from source/blender/nodes/shader/nodes/node_shader_invert.c)18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_layer_weight.cc (renamed from source/blender/nodes/shader/nodes/node_shader_layer_weight.c)21
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_falloff.cc (renamed from source/blender/nodes/shader/nodes/node_shader_light_falloff.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_light_path.cc (renamed from source/blender/nodes/shader/nodes/node_shader_light_path.c)18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.cc92
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.cc (renamed from source/blender/nodes/shader/nodes/node_shader_mapping.c)44
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.cc58
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mix_shader.cc (renamed from source/blender/nodes/shader/nodes/node_shader_mix_shader.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal.cc (renamed from source/blender/nodes/shader/nodes/node_shader_normal.c)18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal_map.cc (renamed from source/blender/nodes/shader/nodes/node_shader_normal_map.c)34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_object_info.cc (renamed from source/blender/nodes/shader/nodes/node_shader_object_info.c)16
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_aov.cc (renamed from source/blender/nodes/shader/nodes/node_shader_output_aov.c)20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_light.cc (renamed from source/blender/nodes/shader/nodes/node_shader_output_light.c)16
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc (renamed from source/blender/nodes/shader/nodes/node_shader_output_linestyle.c)15
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_material.cc (renamed from source/blender/nodes/shader/nodes/node_shader_output_material.c)18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_world.cc (renamed from source/blender/nodes/shader/nodes/node_shader_output_world.c)18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_particle_info.cc (renamed from source/blender/nodes/shader/nodes/node_shader_particle_info.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_rgb.cc (renamed from source/blender/nodes/shader/nodes/node_shader_rgb.c)25
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc181
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_script.cc (renamed from source/blender/nodes/shader/nodes/node_shader_script.c)27
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc (renamed from source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c)34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc38
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc (renamed from source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_squeeze.cc (renamed from source/blender/nodes/shader/nodes/node_shader_squeeze.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc (renamed from source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c)32
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tangent.cc (renamed from source/blender/nodes/shader/nodes/node_shader_tangent.c)22
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_brick.cc24
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_checker.cc24
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_coord.cc (renamed from source/blender/nodes/shader/nodes/node_shader_tex_coord.c)27
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.cc (renamed from source/blender/nodes/shader/nodes/node_shader_tex_environment.c)25
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc25
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.cc21
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_magic.cc24
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc31
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.cc29
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.cc (renamed from source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c)28
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_sky.cc (renamed from source/blender/nodes/shader/nodes/node_shader_tex_sky.c)26
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc28
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_wave.cc24
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc25
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc (renamed from source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c)15
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uvmap.cc (renamed from source/blender/nodes/shader/nodes/node_shader_uvmap.c)22
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_value.cc18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc (renamed from source/blender/nodes/shader/nodes/node_shader_vector_displacement.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_math.cc65
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc20
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vector_transform.cc (renamed from source/blender/nodes/shader/nodes/node_shader_vector_transform.c)34
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vertex_color.cc (renamed from source/blender/nodes/shader/nodes/node_shader_vertex_color.c)21
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc (renamed from source/blender/nodes/shader/nodes/node_shader_volume_absorption.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_info.cc (renamed from source/blender/nodes/shader/nodes/node_shader_volume_info.c)16
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_principled.cc (renamed from source/blender/nodes/shader/nodes/node_shader_volume_principled.c)28
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc (renamed from source/blender/nodes/shader/nodes/node_shader_volume_scatter.c)19
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_wavelength.cc (renamed from source/blender/nodes/shader/nodes/node_shader_wavelength.c)33
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_wireframe.cc (renamed from source/blender/nodes/shader/nodes/node_shader_wireframe.c)19
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c21
-rw-r--r--source/blender/nodes/texture/node_texture_util.c22
-rw-r--r--source/blender/nodes/texture/node_texture_util.h7
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_at.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_bricks.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_checker.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_common.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_compose.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_coord.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_curves.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_decompose.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_distance.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_hueSatVal.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_image.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_invert.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_math.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_mixRgb.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_output.c6
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_proc.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_rotate.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_scale.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_texture.c3
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_translate.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_valToNor.c2
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_valToRgb.c4
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_viewer.c6
-rw-r--r--source/blender/python/gpu/gpu_py_offscreen.c29
-rw-r--r--source/blender/render/intern/pipeline.c8
-rw-r--r--source/blender/render/intern/render_result.c6
-rw-r--r--source/blender/sequencer/SEQ_effects.h12
-rw-r--r--source/blender/sequencer/intern/effects.c1400
-rw-r--r--source/blender/sequencer/intern/render.c47
-rw-r--r--source/blender/sequencer/intern/render.h3
-rw-r--r--source/blender/sequencer/intern/sequencer.c5
-rw-r--r--source/blender/sequencer/intern/strip_add.c9
-rw-r--r--source/blender/sequencer/intern/strip_edit.c36
-rw-r--r--source/blender/sequencer/intern/strip_time.c4
-rw-r--r--source/blender/sequencer/intern/utils.c2
-rw-r--r--source/blender/simulation/intern/SIM_mass_spring.cpp3
-rw-r--r--source/blender/simulation/intern/hair_volume.cpp2
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c2
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c3
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c7
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c3
m---------source/tools0
974 files changed, 29442 insertions, 15564 deletions
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
index 24294df14ed..c38973b274f 100755
--- a/build_files/build_environment/install_deps.sh
+++ b/build_files/build_environment/install_deps.sh
@@ -2083,9 +2083,9 @@ compile_OIIO() {
cmake_d="$cmake_d -D OPENEXR_VERSION=$OPENEXR_VERSION"
if [ "$_with_built_openexr" = true ]; then
- cmake_d="$cmake_d -D ILMBASE_HOME=$INST/openexr"
- cmake_d="$cmake_d -D OPENEXR_HOME=$INST/openexr"
- INFO "ILMBASE_HOME=$INST/openexr"
+ cmake_d="$cmake_d -D ILMBASE_ROOT=$INST/openexr"
+ cmake_d="$cmake_d -D OPENEXR_ROOT=$INST/openexr"
+ INFO "Ilmbase_ROOT=$INST/openexr"
fi
# ptex is only needed when nicholas bishop is ready
@@ -2374,9 +2374,9 @@ compile_OSL() {
#~ cmake_d="$cmake_d -D ILMBASE_VERSION=$ILMBASE_VERSION"
if [ "$_with_built_openexr" = true ]; then
- INFO "ILMBASE_HOME=$INST/openexr"
- cmake_d="$cmake_d -D OPENEXR_ROOT_DIR=$INST/openexr"
- cmake_d="$cmake_d -D ILMBASE_ROOT_DIR=$INST/openexr"
+ cmake_d="$cmake_d -D ILMBASE_ROOT=$INST/openexr"
+ cmake_d="$cmake_d -D OPENEXR_ROOT=$INST/openexr"
+ INFO "Ilmbase_ROOT=$INST/openexr"
# XXX Temp workaround... sigh, ILMBase really messed the things up by defining their custom names ON by default :(
fi
@@ -5801,7 +5801,7 @@ print_info() {
PRINT "If you're using CMake add this to your configuration flags:"
_buildargs="-U *SNDFILE* -U PYTHON* -U *BOOST* -U *Boost* -U *TBB*"
- _buildargs="$_buildargs -U *OPENCOLORIO* -U *OPENEXR* -U *OPENIMAGEIO* -U *LLVM* -U *CYCLES*"
+ _buildargs="$_buildargs -U *OPENCOLORIO* -U *OPENEXR* -U *OPENIMAGEIO* -U *LLVM* -U *CLANG* -U *CYCLES*"
_buildargs="$_buildargs -U *OPENSUBDIV* -U *OPENVDB* -U *BLOSC* -U *COLLADA* -U *FFMPEG* -U *ALEMBIC* -U *USD*"
_buildargs="$_buildargs -U *EMBREE* -U *OPENIMAGEDENOISE* -U *OPENXR*"
diff --git a/build_files/build_environment/patches/usd.diff b/build_files/build_environment/patches/usd.diff
index dc4982ad114..8ea1e2054c1 100644
--- a/build_files/build_environment/patches/usd.diff
+++ b/build_files/build_environment/patches/usd.diff
@@ -197,3 +197,38 @@ index 67ec0d15f..6dc3e85a0 100644
#else
#error Unknown architecture.
#endif
+
+diff --git a/pxr/base/arch/demangle.cpp b/pxr/base/arch/demangle.cpp
+index 67ec0d15f..6dc3e85a0 100644
+--- a/pxr/base/arch/demangle.cpp
++++ b/pxr/base/arch/demangle.cpp
+@@ -36,6 +36,7 @@
+ #if (ARCH_COMPILER_GCC_MAJOR == 3 && ARCH_COMPILER_GCC_MINOR >= 1) || \
+ ARCH_COMPILER_GCC_MAJOR > 3 || defined(ARCH_COMPILER_CLANG)
+ #define _AT_LEAST_GCC_THREE_ONE_OR_CLANG
++#include <cxxabi.h>
+ #endif
+
+ PXR_NAMESPACE_OPEN_SCOPE
+@@ -138,7 +139,6 @@
+ #endif
+
+ #if defined(_AT_LEAST_GCC_THREE_ONE_OR_CLANG)
+-#include <cxxabi.h>
+
+ /*
+ * This routine doesn't work when you get to gcc3.4.
+
+diff --git a/pxr/base/work/singularTask.h b/pxr/base/work/singularTask.h
+index 67ec0d15f..6dc3e85a0 100644
+--- a/pxr/base/work/singularTask.h
++++ b/pxr/base/work/singularTask.h
+@@ -120,7 +120,7 @@
+ // case we go again to ensure the task can do whatever it
+ // was awakened to do. Once we successfully take the count
+ // to zero, we stop.
+- size_t old = count;
++ std::size_t old = count;
+ do { _fn(); } while (
+ !count.compare_exchange_strong(old, 0));
+ });
diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp
index bb17cfdcb45..5e2b700427a 100644
--- a/intern/cycles/blender/mesh.cpp
+++ b/intern/cycles/blender/mesh.cpp
@@ -1086,40 +1086,6 @@ static void create_subd_mesh(Scene *scene,
/* Sync */
-/* Check whether some of "built-in" motion-related attributes are needed to be exported (includes
- * things like velocity from cache modifier, fluid simulation).
- *
- * NOTE: This code is run prior to object motion blur initialization. so can not access properties
- * set by `sync_object_motion_init()`. */
-static bool mesh_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
-{
- const Scene::MotionType need_motion = scene->need_motion();
- if (need_motion == Scene::MOTION_NONE) {
- /* Simple case: neither motion pass nor motion blur is needed, no need in the motion related
- * attributes. */
- return false;
- }
-
- if (need_motion == Scene::MOTION_BLUR) {
- /* A bit tricky and implicit case:
- * - Motion blur is enabled in the scene, which implies specific number of time steps for
- * objects.
- * - If the object has motion blur disabled on it, it will have 0 time steps.
- * - Motion attribute expects non-zero time steps.
- *
- * Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */
- PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles");
- const bool use_motion = get_boolean(cobject, "use_motion_blur");
- if (!use_motion) {
- return false;
- }
- }
-
- /* Motion pass which implies 3 motion steps, or motion blur which is not disabled on object
- * level. */
- return true;
-}
-
void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh)
{
/* make a copy of the shaders as the caller in the main thread still need them for syncing the
@@ -1144,7 +1110,7 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, M
if (b_mesh) {
/* Motion blur attribute is relative to seconds, we need it relative to frames. */
- const bool need_motion = mesh_need_motion_attribute(b_ob_info, scene);
+ const bool need_motion = object_need_motion_attribute(b_ob_info, scene);
const float motion_scale = (need_motion) ?
scene->motion_shutter_time() /
(b_scene.render().fps() / b_scene.render().fps_base()) :
diff --git a/intern/cycles/blender/pointcloud.cpp b/intern/cycles/blender/pointcloud.cpp
index a9e616a468f..a69c4f6eca3 100644
--- a/intern/cycles/blender/pointcloud.cpp
+++ b/intern/cycles/blender/pointcloud.cpp
@@ -37,12 +37,52 @@ static void fill_generic_attribute(BL::PointCloud &b_pointcloud,
}
}
-static void copy_attributes(PointCloud *pointcloud, BL::PointCloud b_pointcloud)
+static void attr_create_motion(PointCloud *pointcloud,
+ BL::Attribute &b_attribute,
+ const float motion_scale)
+{
+ if (!(b_attribute.domain() == BL::Attribute::domain_POINT) &&
+ (b_attribute.data_type() == BL::Attribute::data_type_FLOAT_VECTOR)) {
+ return;
+ }
+
+ BL::FloatVectorAttribute b_vector_attribute(b_attribute);
+ const int num_points = pointcloud->get_points().size();
+
+ /* Find or add attribute */
+ float3 *P = &pointcloud->get_points()[0];
+ Attribute *attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
+
+ if (!attr_mP) {
+ attr_mP = pointcloud->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION);
+ }
+
+ /* Only export previous and next frame, we don't have any in between data. */
+ float motion_times[2] = {-1.0f, 1.0f};
+ for (int step = 0; step < 2; step++) {
+ const float relative_time = motion_times[step] * 0.5f * motion_scale;
+ float3 *mP = attr_mP->data_float3() + step * num_points;
+
+ for (int i = 0; i < num_points; i++) {
+ mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time;
+ }
+ }
+}
+
+static void copy_attributes(PointCloud *pointcloud,
+ BL::PointCloud b_pointcloud,
+ const bool need_motion,
+ const float motion_scale)
{
AttributeSet &attributes = pointcloud->attributes;
+ static const ustring u_velocity("velocity");
for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
const ustring name{b_attribute.name().c_str()};
+ if (need_motion && name == u_velocity) {
+ attr_create_motion(pointcloud, b_attribute, motion_scale);
+ }
+
if (attributes.find(name)) {
continue;
}
@@ -111,7 +151,11 @@ static void copy_attributes(PointCloud *pointcloud, BL::PointCloud b_pointcloud)
}
}
-static void export_pointcloud(Scene *scene, PointCloud *pointcloud, BL::PointCloud b_pointcloud)
+static void export_pointcloud(Scene *scene,
+ PointCloud *pointcloud,
+ BL::PointCloud b_pointcloud,
+ const bool need_motion,
+ const float motion_scale)
{
/* TODO: optimize so we can straight memcpy arrays from Blender? */
@@ -141,7 +185,7 @@ static void export_pointcloud(Scene *scene, PointCloud *pointcloud, BL::PointClo
}
/* Export attributes */
- copy_attributes(pointcloud, b_pointcloud);
+ copy_attributes(pointcloud, b_pointcloud, need_motion, motion_scale);
}
static void export_pointcloud_motion(PointCloud *pointcloud,
@@ -193,7 +237,7 @@ static void export_pointcloud_motion(PointCloud *pointcloud,
}
/* Export attributes */
- copy_attributes(pointcloud, b_pointcloud);
+ copy_attributes(pointcloud, b_pointcloud, false, 0.0f);
}
void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info)
@@ -207,7 +251,13 @@ void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info
/* TODO: add option to filter out points in the view layer. */
BL::PointCloud b_pointcloud(b_ob_info.object_data);
- export_pointcloud(scene, &new_pointcloud, b_pointcloud);
+ /* Motion blur attribute is relative to seconds, we need it relative to frames. */
+ const bool need_motion = object_need_motion_attribute(b_ob_info, scene);
+ const float motion_scale = (need_motion) ?
+ scene->motion_shutter_time() /
+ (b_scene.render().fps() / b_scene.render().fps_base()) :
+ 0.0f;
+ export_pointcloud(scene, &new_pointcloud, b_pointcloud, need_motion, motion_scale);
/* update original sockets */
for (const SocketType &socket : new_pointcloud.type->inputs) {
diff --git a/intern/cycles/blender/python.cpp b/intern/cycles/blender/python.cpp
index 024dae306b0..f509d5c2eeb 100644
--- a/intern/cycles/blender/python.cpp
+++ b/intern/cycles/blender/python.cpp
@@ -735,27 +735,20 @@ static bool image_parse_filepaths(PyObject *pyfilepaths, vector<string> &filepat
static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
{
-#if 1
- (void)args;
- (void)keywords;
-#else
static const char *keyword_list[] = {
- "preferences", "scene", "view_layer", "input", "output", "tile_size", "samples", NULL};
+ "preferences", "scene", "view_layer", "input", "output", NULL};
PyObject *pypreferences, *pyscene, *pyviewlayer;
PyObject *pyinput, *pyoutput = NULL;
- int tile_size = 0, samples = 0;
if (!PyArg_ParseTupleAndKeywords(args,
keywords,
- "OOOO|Oii",
+ "OOOO|O",
(char **)keyword_list,
&pypreferences,
&pyscene,
&pyviewlayer,
&pyinput,
- &pyoutput,
- &tile_size,
- &samples)) {
+ &pyoutput)) {
return NULL;
}
@@ -777,14 +770,10 @@ static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *key
&RNA_ViewLayer,
PyLong_AsVoidPtr(pyviewlayer),
&viewlayerptr);
- PointerRNA cviewlayer = RNA_pointer_get(&viewlayerptr, "cycles");
+ BL::ViewLayer b_view_layer(viewlayerptr);
- DenoiseParams params;
- params.radius = get_int(cviewlayer, "denoising_radius");
- params.strength = get_float(cviewlayer, "denoising_strength");
- params.feature_strength = get_float(cviewlayer, "denoising_feature_strength");
- params.relative_pca = get_boolean(cviewlayer, "denoising_relative_pca");
- params.neighbor_frames = get_int(cviewlayer, "denoising_neighbor_frames");
+ DenoiseParams params = BlenderSync::get_denoise_params(b_scene, b_view_layer, true);
+ params.use = true;
/* Parse file paths list. */
vector<string> input, output;
@@ -812,24 +801,15 @@ static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *key
}
/* Create denoiser. */
- DenoiserPipeline denoiser(device);
- denoiser.params = params;
+ DenoiserPipeline denoiser(device, params);
denoiser.input = input;
denoiser.output = output;
- if (tile_size > 0) {
- denoiser.tile_size = make_int2(tile_size, tile_size);
- }
- if (samples > 0) {
- denoiser.samples_override = samples;
- }
-
/* Run denoiser. */
if (!denoiser.run()) {
PyErr_SetString(PyExc_ValueError, denoiser.error.c_str());
return NULL;
}
-#endif
Py_RETURN_NONE;
}
diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp
index 70acfce6891..5604c2989fd 100644
--- a/intern/cycles/blender/shader.cpp
+++ b/intern/cycles/blender/shader.cpp
@@ -776,7 +776,7 @@ static ShaderNode *add_node(Scene *scene,
}
else {
ustring filename = ustring(
- image_user_file_path(b_image_user, b_image, b_scene.frame_current(), true));
+ image_user_file_path(b_image_user, b_image, b_scene.frame_current()));
image->set_filename(filename);
}
}
@@ -813,7 +813,7 @@ static ShaderNode *add_node(Scene *scene,
}
else {
env->set_filename(
- ustring(image_user_file_path(b_image_user, b_image, b_scene.frame_current(), false)));
+ ustring(image_user_file_path(b_image_user, b_image, b_scene.frame_current())));
}
}
node = env;
diff --git a/intern/cycles/blender/sync.h b/intern/cycles/blender/sync.h
index d074f90bb1b..3722b938863 100644
--- a/intern/cycles/blender/sync.h
+++ b/intern/cycles/blender/sync.h
@@ -105,11 +105,11 @@ class BlenderSync {
static BufferParams get_buffer_params(
BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, int height);
- private:
static DenoiseParams get_denoise_params(BL::Scene &b_scene,
BL::ViewLayer &b_view_layer,
bool background);
+ private:
/* sync */
void sync_lights(BL::Depsgraph &b_depsgraph, bool update_all);
void sync_materials(BL::Depsgraph &b_depsgraph, bool update_all);
diff --git a/intern/cycles/blender/util.h b/intern/cycles/blender/util.h
index be36bcdaaa8..59520b94d6f 100644
--- a/intern/cycles/blender/util.h
+++ b/intern/cycles/blender/util.h
@@ -18,6 +18,7 @@
#define __BLENDER_UTIL_H__
#include "scene/mesh.h"
+#include "scene/scene.h"
#include "util/algorithm.h"
#include "util/array.h"
@@ -33,7 +34,7 @@
extern "C" {
void BKE_image_user_frame_calc(void *ima, void *iuser, int cfra);
-void BKE_image_user_file_path(void *iuser, void *ima, char *path);
+void BKE_image_user_file_path_ex(void *iuser, void *ima, char *path, bool resolve_udim);
unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame, int tile);
float *BKE_image_get_float_pixels_for_frame(void *image, int frame, int tile);
}
@@ -290,25 +291,14 @@ static inline int render_resolution_y(BL::RenderSettings &b_render)
return b_render.resolution_y() * b_render.resolution_percentage() / 100;
}
-static inline string image_user_file_path(BL::ImageUser &iuser,
- BL::Image &ima,
- int cfra,
- bool load_tiled)
+static inline string image_user_file_path(BL::ImageUser &iuser, BL::Image &ima, int cfra)
{
char filepath[1024];
iuser.tile(0);
BKE_image_user_frame_calc(ima.ptr.data, iuser.ptr.data, cfra);
- BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath);
+ BKE_image_user_file_path_ex(iuser.ptr.data, ima.ptr.data, filepath, false);
- string filepath_str = string(filepath);
- if (load_tiled && ima.source() == BL::Image::source_TILED) {
- string udim;
- if (!ima.tiles.empty()) {
- udim = to_string(ima.tiles[0].number());
- }
- string_replace(filepath_str, udim, "<UDIM>");
- }
- return filepath_str;
+ return string(filepath);
}
static inline int image_user_frame_number(BL::ImageUser &iuser, BL::Image &ima, int cfra)
@@ -681,6 +671,40 @@ static inline uint object_ray_visibility(BL::Object &b_ob)
return flag;
}
+/* Check whether some of "built-in" motion-related attributes are needed to be exported (includes
+ * things like velocity from cache modifier, fluid simulation).
+ *
+ * NOTE: This code is run prior to object motion blur initialization. so can not access properties
+ * set by `sync_object_motion_init()`. */
+static inline bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
+{
+ const Scene::MotionType need_motion = scene->need_motion();
+ if (need_motion == Scene::MOTION_NONE) {
+ /* Simple case: neither motion pass nor motion blur is needed, no need in the motion related
+ * attributes. */
+ return false;
+ }
+
+ if (need_motion == Scene::MOTION_BLUR) {
+ /* A bit tricky and implicit case:
+ * - Motion blur is enabled in the scene, which implies specific number of time steps for
+ * objects.
+ * - If the object has motion blur disabled on it, it will have 0 time steps.
+ * - Motion attribute expects non-zero time steps.
+ *
+ * Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */
+ PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles");
+ const bool use_motion = get_boolean(cobject, "use_motion_blur");
+ if (!use_motion) {
+ return false;
+ }
+ }
+
+ /* Motion pass which implies 3 motion steps, or motion blur which is not disabled on object
+ * level. */
+ return true;
+}
+
class EdgeMap {
public:
EdgeMap()
diff --git a/intern/cycles/bvh/build.cpp b/intern/cycles/bvh/build.cpp
index 91198e4e2a2..242595bee4c 100644
--- a/intern/cycles/bvh/build.cpp
+++ b/intern/cycles/bvh/build.cpp
@@ -656,24 +656,24 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange &range,
for (int i = 0; i < size; i++) {
const BVHReference &ref = references[range.start() + i];
- if (ref.prim_type() & PRIMITIVE_ALL_CURVE) {
- if (ref.prim_type() & PRIMITIVE_ALL_MOTION) {
+ if (ref.prim_type() & PRIMITIVE_CURVE) {
+ if (ref.prim_type() & PRIMITIVE_MOTION) {
num_motion_curves++;
}
else {
num_curves++;
}
}
- else if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
- if (ref.prim_type() & PRIMITIVE_ALL_MOTION) {
+ else if (ref.prim_type() & PRIMITIVE_TRIANGLE) {
+ if (ref.prim_type() & PRIMITIVE_MOTION) {
num_motion_triangles++;
}
else {
num_triangles++;
}
}
- else if (ref.prim_type() & PRIMITIVE_ALL_POINT) {
- if (ref.prim_type() & PRIMITIVE_ALL_MOTION) {
+ else if (ref.prim_type() & PRIMITIVE_POINT) {
+ if (ref.prim_type() & PRIMITIVE_MOTION) {
num_motion_points++;
}
else {
@@ -973,7 +973,7 @@ BVHNode *BVHBuild::create_leaf_node(const BVHRange &range, const vector<BVHRefer
for (int i = 0; i < range.size(); i++) {
const BVHReference &ref = references[range.start() + i];
if (ref.prim_index() != -1) {
- uint32_t type_index = bitscan((uint32_t)(ref.prim_type() & PRIMITIVE_ALL));
+ uint32_t type_index = PRIMITIVE_INDEX(ref.prim_type() & PRIMITIVE_ALL);
p_ref[type_index].push_back(ref);
p_type[type_index].push_back(ref.prim_type());
p_index[type_index].push_back(ref.prim_index());
diff --git a/intern/cycles/bvh/bvh2.cpp b/intern/cycles/bvh/bvh2.cpp
index 744e7fa9898..f1ea43da1d9 100644
--- a/intern/cycles/bvh/bvh2.cpp
+++ b/intern/cycles/bvh/bvh2.cpp
@@ -387,7 +387,7 @@ void BVH2::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility
}
else {
/* Primitives. */
- if (pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) {
+ if (pack.prim_type[prim] & PRIMITIVE_CURVE) {
/* Curves. */
const Hair *hair = static_cast<const Hair *>(ob->get_geometry());
int prim_offset = (params.top_level) ? hair->prim_offset : 0;
@@ -410,7 +410,7 @@ void BVH2::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility
}
}
}
- else if (pack.prim_type[prim] & PRIMITIVE_ALL_POINT) {
+ else if (pack.prim_type[prim] & PRIMITIVE_POINT) {
/* Points. */
const PointCloud *pointcloud = static_cast<const PointCloud *>(ob->get_geometry());
int prim_offset = (params.top_level) ? pointcloud->prim_offset : 0;
@@ -590,13 +590,7 @@ void BVH2::pack_instances(size_t nodes_size, size_t leaf_nodes_size)
float2 *bvh_prim_time = bvh->pack.prim_time.size() ? &bvh->pack.prim_time[0] : NULL;
for (size_t i = 0; i < bvh_prim_index_size; i++) {
- if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) {
- pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
- }
- else {
- pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
- }
-
+ pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset;
pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i];
pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i];
pack_prim_object[pack_prim_index_offset] = 0; // unused for instances
diff --git a/intern/cycles/bvh/embree.cpp b/intern/cycles/bvh/embree.cpp
index eab193f45cb..618dd9438d5 100644
--- a/intern/cycles/bvh/embree.cpp
+++ b/intern/cycles/bvh/embree.cpp
@@ -91,7 +91,7 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args)
++ctx->num_hits;
/* Always use baked shadow transparency for curves. */
- if (current_isect.type & PRIMITIVE_ALL_CURVE) {
+ if (current_isect.type & PRIMITIVE_CURVE) {
ctx->throughput *= intersection_curve_shadow_transparency(
kg, current_isect.object, current_isect.prim, current_isect.u);
diff --git a/intern/cycles/bvh/split.cpp b/intern/cycles/bvh/split.cpp
index 34d12de97c0..e126b6f18bc 100644
--- a/intern/cycles/bvh/split.cpp
+++ b/intern/cycles/bvh/split.cpp
@@ -535,15 +535,15 @@ void BVHSpatialSplit::split_reference(const BVHBuild &builder,
/* loop over vertices/edges. */
const Object *ob = builder.objects[ref.prim_object()];
- if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) {
+ if (ref.prim_type() & PRIMITIVE_TRIANGLE) {
Mesh *mesh = static_cast<Mesh *>(ob->get_geometry());
split_triangle_reference(ref, mesh, dim, pos, left_bounds, right_bounds);
}
- else if (ref.prim_type() & PRIMITIVE_ALL_CURVE) {
+ else if (ref.prim_type() & PRIMITIVE_CURVE) {
Hair *hair = static_cast<Hair *>(ob->get_geometry());
split_curve_reference(ref, hair, dim, pos, left_bounds, right_bounds);
}
- else if (ref.prim_type() & PRIMITIVE_ALL_POINT) {
+ else if (ref.prim_type() & PRIMITIVE_POINT) {
PointCloud *pointcloud = static_cast<PointCloud *>(ob->get_geometry());
split_point_reference(ref, pointcloud, dim, pos, left_bounds, right_bounds);
}
diff --git a/intern/cycles/bvh/unaligned.cpp b/intern/cycles/bvh/unaligned.cpp
index 3c4a600fe58..a8db6efb597 100644
--- a/intern/cycles/bvh/unaligned.cpp
+++ b/intern/cycles/bvh/unaligned.cpp
@@ -69,7 +69,7 @@ bool BVHUnaligned::compute_aligned_space(const BVHReference &ref, Transform *ali
const int packed_type = ref.prim_type();
const int type = (packed_type & PRIMITIVE_ALL);
/* No motion blur curves here, we can't fit them to aligned boxes well. */
- if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_CURVE_THICK)) {
+ if ((type & PRIMITIVE_CURVE) && !(type & PRIMITIVE_MOTION)) {
const int curve_index = ref.prim_index();
const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
const Hair *hair = static_cast<const Hair *>(object->get_geometry());
@@ -95,7 +95,7 @@ BoundBox BVHUnaligned::compute_aligned_prim_boundbox(const BVHReference &prim,
const int packed_type = prim.prim_type();
const int type = (packed_type & PRIMITIVE_ALL);
/* No motion blur curves here, we can't fit them to aligned boxes well. */
- if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_CURVE_THICK)) {
+ if ((type & PRIMITIVE_CURVE) && !(type & PRIMITIVE_MOTION)) {
const int curve_index = prim.prim_index();
const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type);
const Hair *hair = static_cast<const Hair *>(object->get_geometry());
diff --git a/intern/cycles/device/denoise.cpp b/intern/cycles/device/denoise.cpp
index c291a7a0adb..8ae2bb213e4 100644
--- a/intern/cycles/device/denoise.cpp
+++ b/intern/cycles/device/denoise.cpp
@@ -76,6 +76,8 @@ NODE_DEFINE(DenoiseParams)
SOCKET_BOOLEAN(use_pass_albedo, "Use Pass Albedo", true);
SOCKET_BOOLEAN(use_pass_normal, "Use Pass Normal", false);
+ SOCKET_BOOLEAN(temporally_stable, "Temporally Stable", false);
+
SOCKET_ENUM(prefilter, "Prefilter", *prefilter_enum, DENOISER_PREFILTER_FAST);
return type;
diff --git a/intern/cycles/device/denoise.h b/intern/cycles/device/denoise.h
index 3f30506ae06..07868527fc5 100644
--- a/intern/cycles/device/denoise.h
+++ b/intern/cycles/device/denoise.h
@@ -72,6 +72,9 @@ class DenoiseParams : public Node {
bool use_pass_albedo = true;
bool use_pass_normal = true;
+ /* Configure the denoiser to use motion vectors, previous image and a temporally stable model. */
+ bool temporally_stable = false;
+
DenoiserPrefilter prefilter = DENOISER_PREFILTER_FAST;
static const NodeEnum *get_type_enum();
@@ -83,7 +86,8 @@ class DenoiseParams : public Node {
{
return !(use == other.use && type == other.type && start_sample == other.start_sample &&
use_pass_albedo == other.use_pass_albedo &&
- use_pass_normal == other.use_pass_normal && prefilter == other.prefilter);
+ use_pass_normal == other.use_pass_normal &&
+ temporally_stable == other.temporally_stable && prefilter == other.prefilter);
}
};
diff --git a/intern/cycles/device/optix/device_impl.cpp b/intern/cycles/device/optix/device_impl.cpp
index 38cc3330ebd..009661b2dec 100644
--- a/intern/cycles/device/optix/device_impl.cpp
+++ b/intern/cycles/device/optix/device_impl.cpp
@@ -566,6 +566,19 @@ class OptiXDevice::DenoiseContext {
}
}
+ if (denoise_params.temporally_stable) {
+ prev_output.device_pointer = render_buffers->buffer.device_pointer;
+
+ prev_output.offset = buffer_params.get_pass_offset(PASS_DENOISING_PREVIOUS);
+
+ prev_output.stride = buffer_params.stride;
+ prev_output.pass_stride = buffer_params.pass_stride;
+
+ num_input_passes += 1;
+ use_pass_flow = true;
+ pass_motion = buffer_params.get_pass_offset(PASS_MOTION);
+ }
+
use_guiding_passes = (num_input_passes - 1) > 0;
if (use_guiding_passes) {
@@ -574,6 +587,7 @@ class OptiXDevice::DenoiseContext {
guiding_params.pass_albedo = pass_denoising_albedo;
guiding_params.pass_normal = pass_denoising_normal;
+ guiding_params.pass_flow = pass_motion;
guiding_params.stride = buffer_params.stride;
guiding_params.pass_stride = buffer_params.pass_stride;
@@ -588,6 +602,10 @@ class OptiXDevice::DenoiseContext {
guiding_params.pass_normal = guiding_params.pass_stride;
guiding_params.pass_stride += 3;
}
+ if (use_pass_flow) {
+ guiding_params.pass_flow = guiding_params.pass_stride;
+ guiding_params.pass_stride += 2;
+ }
guiding_params.stride = buffer_params.width;
@@ -605,6 +623,16 @@ class OptiXDevice::DenoiseContext {
RenderBuffers *render_buffers = nullptr;
const BufferParams &buffer_params;
+ /* Previous output. */
+ struct {
+ device_ptr device_pointer = 0;
+
+ int offset = PASS_UNUSED;
+
+ int stride = -1;
+ int pass_stride = -1;
+ } prev_output;
+
/* Device-side storage of the guiding passes. */
device_only_memory<float> guiding_buffer;
@@ -614,6 +642,7 @@ class OptiXDevice::DenoiseContext {
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_albedo = PASS_UNUSED;
int pass_normal = PASS_UNUSED;
+ int pass_flow = PASS_UNUSED;
int stride = -1;
int pass_stride = -1;
@@ -624,6 +653,7 @@ class OptiXDevice::DenoiseContext {
bool use_guiding_passes = false;
bool use_pass_albedo = false;
bool use_pass_normal = false;
+ bool use_pass_flow = false;
int num_samples = 0;
@@ -632,6 +662,7 @@ class OptiXDevice::DenoiseContext {
/* NOTE: Are only initialized when the corresponding guiding pass is enabled. */
int pass_denoising_albedo = PASS_UNUSED;
int pass_denoising_normal = PASS_UNUSED;
+ int pass_motion = PASS_UNUSED;
/* For passes which don't need albedo channel for denoising we replace the actual albedo with
* the (0.5, 0.5, 0.5). This flag indicates that the real albedo pass has been replaced with
@@ -702,6 +733,7 @@ bool OptiXDevice::denoise_filter_guiding_preprocess(DenoiseContext &context)
&context.guiding_params.pass_stride,
&context.guiding_params.pass_albedo,
&context.guiding_params.pass_normal,
+ &context.guiding_params.pass_flow,
&context.render_buffers->buffer.device_pointer,
&buffer_params.offset,
&buffer_params.stride,
@@ -709,6 +741,7 @@ bool OptiXDevice::denoise_filter_guiding_preprocess(DenoiseContext &context)
&context.pass_sample_count,
&context.pass_denoising_albedo,
&context.pass_denoising_normal,
+ &context.pass_motion,
&buffer_params.full_x,
&buffer_params.full_y,
&buffer_params.width,
@@ -881,7 +914,8 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context)
{
const bool recreate_denoiser = (denoiser_.optix_denoiser == nullptr) ||
(denoiser_.use_pass_albedo != context.use_pass_albedo) ||
- (denoiser_.use_pass_normal != context.use_pass_normal);
+ (denoiser_.use_pass_normal != context.use_pass_normal) ||
+ (denoiser_.use_pass_flow != context.use_pass_flow);
if (!recreate_denoiser) {
return true;
}
@@ -895,8 +929,14 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context)
OptixDenoiserOptions denoiser_options = {};
denoiser_options.guideAlbedo = context.use_pass_albedo;
denoiser_options.guideNormal = context.use_pass_normal;
+
+ OptixDenoiserModelKind model = OPTIX_DENOISER_MODEL_KIND_HDR;
+ if (context.use_pass_flow) {
+ model = OPTIX_DENOISER_MODEL_KIND_TEMPORAL;
+ }
+
const OptixResult result = optixDenoiserCreate(
- this->context, OPTIX_DENOISER_MODEL_KIND_HDR, &denoiser_options, &denoiser_.optix_denoiser);
+ this->context, model, &denoiser_options, &denoiser_.optix_denoiser);
if (result != OPTIX_SUCCESS) {
set_error("Failed to create OptiX denoiser");
@@ -906,6 +946,7 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context)
/* OptiX denoiser handle was created with the requested number of input passes. */
denoiser_.use_pass_albedo = context.use_pass_albedo;
denoiser_.use_pass_normal = context.use_pass_normal;
+ denoiser_.use_pass_flow = context.use_pass_flow;
/* OptiX denoiser has been created, but it needs configuration. */
denoiser_.is_configured = false;
@@ -965,8 +1006,10 @@ bool OptiXDevice::denoise_run(DenoiseContext &context, const DenoisePass &pass)
OptixImage2D color_layer = {0};
OptixImage2D albedo_layer = {0};
OptixImage2D normal_layer = {0};
+ OptixImage2D flow_layer = {0};
OptixImage2D output_layer = {0};
+ OptixImage2D prev_output_layer = {0};
/* Color pass. */
{
@@ -982,6 +1025,19 @@ bool OptiXDevice::denoise_run(DenoiseContext &context, const DenoisePass &pass)
color_layer.format = OPTIX_PIXEL_FORMAT_FLOAT3;
}
+ /* Previous output. */
+ if (context.prev_output.offset != PASS_UNUSED) {
+ const int64_t pass_stride_in_bytes = context.prev_output.pass_stride * sizeof(float);
+
+ prev_output_layer.data = context.prev_output.device_pointer +
+ context.prev_output.offset * sizeof(float);
+ prev_output_layer.width = width;
+ prev_output_layer.height = height;
+ prev_output_layer.rowStrideInBytes = pass_stride_in_bytes * context.prev_output.stride;
+ prev_output_layer.pixelStrideInBytes = pass_stride_in_bytes;
+ prev_output_layer.format = OPTIX_PIXEL_FORMAT_FLOAT3;
+ }
+
/* Optional albedo and color passes. */
if (context.num_input_passes > 1) {
const device_ptr d_guiding_buffer = context.guiding_params.device_pointer;
@@ -1005,21 +1061,32 @@ bool OptiXDevice::denoise_run(DenoiseContext &context, const DenoisePass &pass)
normal_layer.pixelStrideInBytes = pixel_stride_in_bytes;
normal_layer.format = OPTIX_PIXEL_FORMAT_FLOAT3;
}
+
+ if (context.use_pass_flow) {
+ flow_layer.data = d_guiding_buffer + context.guiding_params.pass_flow * sizeof(float);
+ flow_layer.width = width;
+ flow_layer.height = height;
+ flow_layer.rowStrideInBytes = row_stride_in_bytes;
+ flow_layer.pixelStrideInBytes = pixel_stride_in_bytes;
+ flow_layer.format = OPTIX_PIXEL_FORMAT_FLOAT2;
+ }
}
/* Denoise in-place of the noisy input in the render buffers. */
output_layer = color_layer;
- /* Finally run denoising. */
- OptixDenoiserParams params = {}; /* All parameters are disabled/zero. */
+ OptixDenoiserGuideLayer guide_layers = {};
+ guide_layers.albedo = albedo_layer;
+ guide_layers.normal = normal_layer;
+ guide_layers.flow = flow_layer;
OptixDenoiserLayer image_layers = {};
image_layers.input = color_layer;
+ image_layers.previousOutput = prev_output_layer;
image_layers.output = output_layer;
- OptixDenoiserGuideLayer guide_layers = {};
- guide_layers.albedo = albedo_layer;
- guide_layers.normal = normal_layer;
+ /* Finally run denoising. */
+ OptixDenoiserParams params = {}; /* All parameters are disabled/zero. */
optix_assert(optixUtilDenoiserInvokeTiled(denoiser_.optix_denoiser,
denoiser_.queue.stream(),
diff --git a/intern/cycles/device/optix/device_impl.h b/intern/cycles/device/optix/device_impl.h
index 25073c60e69..a1865527c2d 100644
--- a/intern/cycles/device/optix/device_impl.h
+++ b/intern/cycles/device/optix/device_impl.h
@@ -104,6 +104,7 @@ class OptiXDevice : public CUDADevice {
bool use_pass_albedo = false;
bool use_pass_normal = false;
+ bool use_pass_flow = false;
};
Denoiser denoiser_;
diff --git a/intern/cycles/device/queue.h b/intern/cycles/device/queue.h
index 4e9f41f7875..926b7cba78a 100644
--- a/intern/cycles/device/queue.h
+++ b/intern/cycles/device/queue.h
@@ -19,6 +19,7 @@
#include "device/kernel.h"
#include "device/graphics_interop.h"
+#include "util/debug.h"
#include "util/log.h"
#include "util/map.h"
#include "util/string.h"
@@ -42,7 +43,7 @@ struct DeviceKernelArguments {
KERNEL_FILM_CONVERT,
};
- static const int MAX_ARGS = 16;
+ static const int MAX_ARGS = 18;
Type types[MAX_ARGS];
void *values[MAX_ARGS];
size_t sizes[MAX_ARGS];
@@ -85,6 +86,8 @@ struct DeviceKernelArguments {
}
void add(const Type type, const void *value, size_t size)
{
+ assert(count < MAX_ARGS);
+
types[count] = type;
values[count] = (void *)value;
sizes[count] = size;
diff --git a/intern/cycles/kernel/bvh/shadow_all.h b/intern/cycles/kernel/bvh/shadow_all.h
index caca85aac1a..b0e799675e0 100644
--- a/intern/cycles/kernel/bvh/shadow_all.h
+++ b/intern/cycles/kernel/bvh/shadow_all.h
@@ -174,7 +174,7 @@ ccl_device_inline
case PRIMITIVE_MOTION_CURVE_THICK:
case PRIMITIVE_CURVE_RIBBON:
case PRIMITIVE_MOTION_CURVE_RIBBON: {
- if ((type & PRIMITIVE_ALL_MOTION) && kernel_data.bvh.use_bvh_steps) {
+ if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
if (ray->time < prim_time.x || ray->time > prim_time.y) {
hit = false;
@@ -203,7 +203,7 @@ ccl_device_inline
#if BVH_FEATURE(BVH_POINTCLOUD)
case PRIMITIVE_POINT:
case PRIMITIVE_MOTION_POINT: {
- if ((type & PRIMITIVE_ALL_MOTION) && kernel_data.bvh.use_bvh_steps) {
+ if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
if (ray->time < prim_time.x || ray->time > prim_time.y) {
hit = false;
@@ -255,7 +255,7 @@ ccl_device_inline
bool record_intersection = true;
/* Always use baked shadow transparency for curves. */
- if (isect.type & PRIMITIVE_ALL_CURVE) {
+ if (isect.type & PRIMITIVE_CURVE) {
*throughput *= intersection_curve_shadow_transparency(
kg, isect.object, isect.prim, isect.u);
diff --git a/intern/cycles/kernel/bvh/traversal.h b/intern/cycles/kernel/bvh/traversal.h
index 180f19d11c5..e4bff1a8a80 100644
--- a/intern/cycles/kernel/bvh/traversal.h
+++ b/intern/cycles/kernel/bvh/traversal.h
@@ -166,7 +166,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
case PRIMITIVE_CURVE_RIBBON:
case PRIMITIVE_MOTION_CURVE_RIBBON: {
for (; prim_addr < prim_addr2; prim_addr++) {
- if ((type & PRIMITIVE_ALL_MOTION) && kernel_data.bvh.use_bvh_steps) {
+ if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
if (ray->time < prim_time.x || ray->time > prim_time.y) {
continue;
@@ -193,7 +193,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg,
case PRIMITIVE_POINT:
case PRIMITIVE_MOTION_POINT: {
for (; prim_addr < prim_addr2; prim_addr++) {
- if ((type & PRIMITIVE_ALL_MOTION) && kernel_data.bvh.use_bvh_steps) {
+ if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr);
if (ray->time < prim_time.x || ray->time > prim_time.y) {
continue;
diff --git a/intern/cycles/kernel/bvh/util.h b/intern/cycles/kernel/bvh/util.h
index 57593e42a88..bd79c6e19c6 100644
--- a/intern/cycles/kernel/bvh/util.h
+++ b/intern/cycles/kernel/bvh/util.h
@@ -118,16 +118,16 @@ ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals kg,
{
int shader = 0;
- if (type & PRIMITIVE_ALL_TRIANGLE) {
+ if (type & PRIMITIVE_TRIANGLE) {
shader = kernel_tex_fetch(__tri_shader, prim);
}
#ifdef __POINTCLOUD__
- else if (type & PRIMITIVE_ALL_POINT) {
+ else if (type & PRIMITIVE_POINT) {
shader = kernel_tex_fetch(__points_shader, prim);
}
#endif
#ifdef __HAIR__
- else if (type & PRIMITIVE_ALL_CURVE) {
+ else if (type & PRIMITIVE_CURVE) {
shader = kernel_tex_fetch(__curves, prim).shader_id;
}
#endif
@@ -141,16 +141,16 @@ ccl_device_forceinline int intersection_get_shader_from_isect_prim(KernelGlobals
{
int shader = 0;
- if (isect_type & PRIMITIVE_ALL_TRIANGLE) {
+ if (isect_type & PRIMITIVE_TRIANGLE) {
shader = kernel_tex_fetch(__tri_shader, prim);
}
#ifdef __POINTCLOUD__
- else if (isect_type & PRIMITIVE_ALL_POINT) {
+ else if (isect_type & PRIMITIVE_POINT) {
shader = kernel_tex_fetch(__points_shader, prim);
}
#endif
#ifdef __HAIR__
- else if (isect_type & PRIMITIVE_ALL_CURVE) {
+ else if (isect_type & PRIMITIVE_CURVE) {
shader = kernel_tex_fetch(__curves, prim).shader_id;
}
#endif
diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h
index f0ce45d1c2c..2c8ef858270 100644
--- a/intern/cycles/kernel/closure/bsdf.h
+++ b/intern/cycles/kernel/closure/bsdf.h
@@ -124,7 +124,7 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg,
/* For curves use the smooth normal, particularly for ribbons the geometric
* normal gives too much darkening otherwise. */
int label;
- const float3 Ng = (sd->type & PRIMITIVE_ALL_CURVE) ? sc->N : sd->Ng;
+ const float3 Ng = (sd->type & PRIMITIVE_CURVE) ? sc->N : sd->Ng;
switch (sc->type) {
case CLOSURE_BSDF_DIFFUSE_ID:
diff --git a/intern/cycles/kernel/closure/bsdf_hair_principled.h b/intern/cycles/kernel/closure/bsdf_hair_principled.h
index f55ea0f6a2e..c68314889f1 100644
--- a/intern/cycles/kernel/closure/bsdf_hair_principled.h
+++ b/intern/cycles/kernel/closure/bsdf_hair_principled.h
@@ -213,9 +213,7 @@ ccl_device int bsdf_principled_hair_setup(ccl_private ShaderData *sd,
/* TODO: we convert this value to a cosine later and discard the sign, so
* we could probably save some operations. */
- float h = (sd->type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) ?
- -sd->v :
- dot(cross(sd->Ng, X), Z);
+ float h = (sd->type & PRIMITIVE_CURVE_RIBBON) ? -sd->v : dot(cross(sd->Ng, X), Z);
kernel_assert(fabsf(h) < 1.0f + 1e-4f);
kernel_assert(isfinite3_safe(Y));
diff --git a/intern/cycles/kernel/device/gpu/kernel.h b/intern/cycles/kernel/device/gpu/kernel.h
index b50f492e8c7..027b2a7a8c7 100644
--- a/intern/cycles/kernel/device/gpu/kernel.h
+++ b/intern/cycles/kernel/device/gpu/kernel.h
@@ -756,6 +756,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
int guiding_pass_stride,
int guiding_pass_albedo,
int guiding_pass_normal,
+ int guiding_pass_flow,
ccl_global const float *render_buffer,
int render_offset,
int render_stride,
@@ -763,6 +764,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
int render_pass_sample_count,
int render_pass_denoising_albedo,
int render_pass_denoising_normal,
+ int render_pass_motion,
int full_x,
int full_y,
int width,
@@ -814,6 +816,17 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
normal_out[1] = normal_in[1] * pixel_scale;
normal_out[2] = normal_in[2] * pixel_scale;
}
+
+ /* Flow pass. */
+ if (guiding_pass_flow != PASS_UNUSED) {
+ kernel_assert(render_pass_motion != PASS_UNUSED);
+
+ const float *motion_in = buffer + render_pass_motion;
+ float *flow_out = guiding_pixel + guiding_pass_flow;
+
+ flow_out[0] = -motion_in[0] * pixel_scale;
+ flow_out[1] = -motion_in[1] * pixel_scale;
+ }
}
ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
@@ -899,7 +912,6 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
else {
/* Assigning to zero since this is a default alpha value for 3-component passes, and it
* is an opaque pixel for 4 component passes. */
-
denoised_pixel[3] = 0;
}
}
diff --git a/intern/cycles/kernel/device/metal/kernel.metal b/intern/cycles/kernel/device/metal/kernel.metal
index 27dc1f44c6f..deb7dafe55e 100644
--- a/intern/cycles/kernel/device/metal/kernel.metal
+++ b/intern/cycles/kernel/device/metal/kernel.metal
@@ -211,7 +211,7 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal,
}
/* Always use baked shadow transparency for curves. */
- if (type & PRIMITIVE_ALL_CURVE) {
+ if (type & PRIMITIVE_CURVE) {
float throughput = payload.throughput;
throughput *= context.intersection_curve_shadow_transparency(nullptr, object, prim, u);
payload.throughput = throughput;
@@ -476,7 +476,7 @@ __intersection__curve_ribbon(constant KernelParamsMetal &launch_params_metal [[b
result.continue_search = true;
result.distance = ray_tmax;
- if (segment.type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
+ if (segment.type & PRIMITIVE_CURVE_RIBBON) {
metalrt_intersection_curve(launch_params_metal, payload, object, segment.prim, segment.type, ray_origin, ray_direction,
# if defined(__METALRT_MOTION__)
payload.time,
@@ -507,7 +507,7 @@ __intersection__curve_ribbon_shadow(constant KernelParamsMetal &launch_params_me
result.continue_search = true;
result.distance = ray_tmax;
- if (segment.type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
+ if (segment.type & PRIMITIVE_CURVE_RIBBON) {
metalrt_intersection_curve_shadow(launch_params_metal, payload, object, segment.prim, segment.type, ray_origin, ray_direction,
# if defined(__METALRT_MOTION__)
payload.time,
diff --git a/intern/cycles/kernel/device/optix/kernel.cu b/intern/cycles/kernel/device/optix/kernel.cu
index c639dc87f35..aa210b31a95 100644
--- a/intern/cycles/kernel/device/optix/kernel.cu
+++ b/intern/cycles/kernel/device/optix/kernel.cu
@@ -194,7 +194,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
type = kernel_tex_fetch(__objects, object).primitive_type;
}
# ifdef __HAIR__
- else if (optixGetHitKind() & PRIMITIVE_ALL_CURVE) {
+ else if ((optixGetHitKind() & (~PRIMITIVE_MOTION)) != PRIMITIVE_POINT) {
u = __uint_as_float(optixGetAttribute_0());
v = __uint_as_float(optixGetAttribute_1());
@@ -234,7 +234,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit()
}
/* Always use baked shadow transparency for curves. */
- if (type & PRIMITIVE_ALL_CURVE) {
+ if (type & PRIMITIVE_CURVE) {
float throughput = __uint_as_float(optixGetPayload_1());
throughput *= intersection_curve_shadow_transparency(nullptr, object, prim, u);
optixSetPayload_1(__float_as_uint(throughput));
@@ -320,7 +320,7 @@ extern "C" __global__ void __anyhit__kernel_optix_visibility_test()
{
#ifdef __HAIR__
# if OPTIX_ABI_VERSION < 55
- if (optixGetHitKind() & PRIMITIVE_ALL_CURVE) {
+ if (optixGetPrimitiveType() == OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE) {
/* Filter out curve endcaps. */
const float u = __uint_as_float(optixGetAttribute_0());
if (u == 0.0f || u == 1.0f) {
@@ -359,7 +359,7 @@ extern "C" __global__ void __closesthit__kernel_optix_hit()
optixSetPayload_3(prim);
optixSetPayload_5(kernel_tex_fetch(__objects, object).primitive_type);
}
- else if (optixGetHitKind() & PRIMITIVE_ALL_CURVE) {
+ else if ((optixGetHitKind() & (~PRIMITIVE_MOTION)) != PRIMITIVE_POINT) {
const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim);
optixSetPayload_1(optixGetAttribute_0()); /* Same as 'optixGetCurveParameter()' */
optixSetPayload_2(optixGetAttribute_1());
@@ -406,6 +406,7 @@ ccl_device_inline void optix_intersection_curve(const int prim, const int type)
isect.t *= len;
if (curve_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ static_assert(PRIMITIVE_ALL < 128, "Values >= 128 are reserved for OptiX internal use");
optixReportIntersection(isect.t / len,
type & PRIMITIVE_ALL,
__float_as_int(isect.u), /* Attribute_0 */
@@ -418,7 +419,7 @@ extern "C" __global__ void __intersection__curve_ribbon()
const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, optixGetPrimitiveIndex());
const int prim = segment.prim;
const int type = segment.type;
- if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
+ if (type & PRIMITIVE_CURVE_RIBBON) {
optix_intersection_curve(prim, type);
}
}
@@ -460,6 +461,7 @@ extern "C" __global__ void __intersection__point()
}
if (point_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) {
+ static_assert(PRIMITIVE_ALL < 128, "Values >= 128 are reserved for OptiX internal use");
optixReportIntersection(isect.t / len, type & PRIMITIVE_ALL);
}
}
diff --git a/intern/cycles/kernel/geom/attribute.h b/intern/cycles/kernel/geom/attribute.h
index a7ac2bd926f..8b3524beb5d 100644
--- a/intern/cycles/kernel/geom/attribute.h
+++ b/intern/cycles/kernel/geom/attribute.h
@@ -36,7 +36,7 @@ ccl_device_inline uint subd_triangle_patch(KernelGlobals kg, ccl_private const S
ccl_device_inline uint attribute_primitive_type(KernelGlobals kg, ccl_private const ShaderData *sd)
{
- if ((sd->type & PRIMITIVE_ALL_TRIANGLE) && subd_triangle_patch(kg, sd) != ~0) {
+ if ((sd->type & PRIMITIVE_TRIANGLE) && subd_triangle_patch(kg, sd) != ~0) {
return ATTR_PRIM_SUBD;
}
else {
diff --git a/intern/cycles/kernel/geom/curve.h b/intern/cycles/kernel/geom/curve.h
index 4b6eecf9640..8a63f01643b 100644
--- a/intern/cycles/kernel/geom/curve.h
+++ b/intern/cycles/kernel/geom/curve.h
@@ -205,14 +205,14 @@ ccl_device float curve_thickness(KernelGlobals kg, ccl_private const ShaderData
{
float r = 0.0f;
- if (sd->type & PRIMITIVE_ALL_CURVE) {
+ if (sd->type & PRIMITIVE_CURVE) {
KernelCurve curve = kernel_tex_fetch(__curves, sd->prim);
int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
int k1 = k0 + 1;
float4 P_curve[2];
- if (!(sd->type & PRIMITIVE_ALL_MOTION)) {
+ if (!(sd->type & PRIMITIVE_MOTION)) {
P_curve[0] = kernel_tex_fetch(__curve_keys, k0);
P_curve[1] = kernel_tex_fetch(__curve_keys, k1);
}
@@ -249,7 +249,7 @@ ccl_device float3 curve_tangent_normal(KernelGlobals kg, ccl_private const Shade
{
float3 tgN = make_float3(0.0f, 0.0f, 0.0f);
- if (sd->type & PRIMITIVE_ALL_CURVE) {
+ if (sd->type & PRIMITIVE_CURVE) {
tgN = -(-sd->I - sd->dPdu * (dot(sd->dPdu, -sd->I) / len_squared(sd->dPdu)));
tgN = normalize(tgN);
diff --git a/intern/cycles/kernel/geom/curve_intersect.h b/intern/cycles/kernel/geom/curve_intersect.h
index fb0b80b281f..2081eeb3eac 100644
--- a/intern/cycles/kernel/geom/curve_intersect.h
+++ b/intern/cycles/kernel/geom/curve_intersect.h
@@ -635,7 +635,7 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals kg,
float time,
int type)
{
- const bool is_motion = (type & PRIMITIVE_ALL_MOTION);
+ const bool is_motion = (type & PRIMITIVE_MOTION);
KernelCurve kcurve = kernel_tex_fetch(__curves, prim);
@@ -655,7 +655,7 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals kg,
motion_curve_keys(kg, object, prim, time, ka, k0, k1, kb, curve);
}
- if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
+ if (type & PRIMITIVE_CURVE_RIBBON) {
/* todo: adaptive number of subdivisions could help performance here. */
const int subdivisions = kernel_data.bvh.curve_subdivisions;
if (ribbon_intersect(P, dir, tmax, subdivisions, curve, isect)) {
@@ -704,7 +704,7 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg,
float4 P_curve[4];
- if (!(sd->type & PRIMITIVE_ALL_MOTION)) {
+ if (!(sd->type & PRIMITIVE_MOTION)) {
P_curve[0] = kernel_tex_fetch(__curve_keys, ka);
P_curve[1] = kernel_tex_fetch(__curve_keys, k0);
P_curve[2] = kernel_tex_fetch(__curve_keys, k1);
@@ -719,7 +719,7 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg,
const float4 dPdu4 = catmull_rom_basis_derivative(P_curve, sd->u);
const float3 dPdu = float4_to_float3(dPdu4);
- if (sd->type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) {
+ if (sd->type & PRIMITIVE_CURVE_RIBBON) {
/* Rounded smooth normals for ribbons, to approximate thick curve shape. */
const float3 tangent = normalize(dPdu);
const float3 bitangent = normalize(cross(tangent, -D));
@@ -727,8 +727,6 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg,
const float cosine = safe_sqrtf(1.0f - sine * sine);
sd->N = normalize(sine * bitangent - cosine * normalize(cross(tangent, bitangent)));
- sd->Ng = -D;
-
# if 0
/* This approximates the position and geometric normal of a thick curve too,
* but gives too many issues with wrong self intersections. */
@@ -744,25 +742,27 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg,
/* NOTE: It is possible that P will be the same as P_inside (precision issues, or very small
* radius). In this case use the view direction to approximate the normal. */
const float3 P_inside = float4_to_float3(catmull_rom_basis_eval(P_curve, sd->u));
- const float3 Ng = (!isequal_float3(P, P_inside)) ? normalize(P - P_inside) : -sd->I;
+ const float3 N = (!isequal_float3(P, P_inside)) ? normalize(P - P_inside) : -sd->I;
- sd->N = Ng;
- sd->Ng = Ng;
+ sd->N = N;
sd->v = 0.0f;
}
# ifdef __DPDU__
/* dPdu/dPdv */
sd->dPdu = dPdu;
- sd->dPdv = cross(dPdu, sd->Ng);
# endif
+ /* Convert to world space. */
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- const Transform tfm = object_get_transform(kg, sd);
- P = transform_point(&tfm, P);
+ object_position_transform_auto(kg, sd, &P);
+ object_normal_transform_auto(kg, sd, &sd->N);
+ object_dir_transform_auto(kg, sd, &sd->dPdu);
}
sd->P = P;
+ sd->Ng = (sd->type & PRIMITIVE_CURVE_RIBBON) ? sd->I : sd->N;
+ sd->dPdv = cross(sd->dPdu, sd->Ng);
sd->shader = kernel_tex_fetch(__curves, sd->prim).shader_id;
}
diff --git a/intern/cycles/kernel/geom/point.h b/intern/cycles/kernel/geom/point.h
index 021135b76fb..52a1e77d71a 100644
--- a/intern/cycles/kernel/geom/point.h
+++ b/intern/cycles/kernel/geom/point.h
@@ -46,8 +46,11 @@ ccl_device float point_attribute_float(KernelGlobals kg,
}
}
-ccl_device float2 point_attribute_float2(
- KernelGlobals kg, const ShaderData *sd, const AttributeDescriptor desc, float2 *dx, float2 *dy)
+ccl_device float2 point_attribute_float2(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float2 *dx,
+ ccl_private float2 *dy)
{
# ifdef __RAY_DIFFERENTIALS__
if (dx)
@@ -64,8 +67,11 @@ ccl_device float2 point_attribute_float2(
}
}
-ccl_device float3 point_attribute_float3(
- KernelGlobals kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy)
+ccl_device float3 point_attribute_float3(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float3 *dx,
+ ccl_private float3 *dy)
{
# ifdef __RAY_DIFFERENTIALS__
if (dx)
@@ -82,8 +88,11 @@ ccl_device float3 point_attribute_float3(
}
}
-ccl_device float4 point_attribute_float4(
- KernelGlobals kg, const ShaderData *sd, const AttributeDescriptor desc, float4 *dx, float4 *dy)
+ccl_device float4 point_attribute_float4(KernelGlobals kg,
+ ccl_private const ShaderData *sd,
+ const AttributeDescriptor desc,
+ ccl_private float4 *dx,
+ ccl_private float4 *dy)
{
# ifdef __RAY_DIFFERENTIALS__
if (dx)
@@ -104,7 +113,7 @@ ccl_device float4 point_attribute_float4(
ccl_device float point_radius(KernelGlobals kg, ccl_private const ShaderData *sd)
{
- if (sd->type & PRIMITIVE_ALL_POINT) {
+ if (sd->type & PRIMITIVE_POINT) {
return kernel_tex_fetch(__points, sd->prim).w;
}
diff --git a/intern/cycles/kernel/geom/point_intersect.h b/intern/cycles/kernel/geom/point_intersect.h
index da0b31f9a8c..757c8b81efa 100644
--- a/intern/cycles/kernel/geom/point_intersect.h
+++ b/intern/cycles/kernel/geom/point_intersect.h
@@ -23,7 +23,7 @@ CCL_NAMESPACE_BEGIN
#ifdef __POINTCLOUD__
ccl_device_forceinline bool point_intersect_test(
- const float4 point, const float3 P, const float3 dir, const float tmax, float *t)
+ const float4 point, const float3 P, const float3 dir, const float tmax, ccl_private float *t)
{
const float3 center = float4_to_float3(point);
const float radius = point.w;
@@ -43,7 +43,7 @@ ccl_device_forceinline bool point_intersect_test(
const float t_front = projC0 - td;
const bool valid_front = (0.0f <= t_front) & (t_front <= tmax);
- /* Always backface culling for now. */
+ /* Always back-face culling for now. */
# if 0
const float t_back = projC0 + td;
const bool valid_back = (0.0f <= t_back) & (t_back <= tmax);
@@ -75,8 +75,8 @@ ccl_device_forceinline bool point_intersect(KernelGlobals kg,
const float time,
const int type)
{
- const float4 point = (type & PRIMITIVE_ALL_MOTION) ? motion_point(kg, object, prim, time) :
- kernel_tex_fetch(__points, prim);
+ const float4 point = (type & PRIMITIVE_MOTION) ? motion_point(kg, object, prim, time) :
+ kernel_tex_fetch(__points, prim);
if (!point_intersect_test(point, P, dir, tmax, &isect->t)) {
return false;
@@ -93,7 +93,7 @@ ccl_device_forceinline bool point_intersect(KernelGlobals kg,
ccl_device_inline void point_shader_setup(KernelGlobals kg,
ccl_private ShaderData *sd,
ccl_private const Intersection *isect,
- const Ray *ray)
+ ccl_private const Ray *ray)
{
sd->shader = kernel_tex_fetch(__points_shader, isect->prim);
sd->P = ray->P + ray->D * isect->t;
@@ -104,17 +104,12 @@ ccl_device_inline void point_shader_setup(KernelGlobals kg,
sd->v = isect->v;
# endif
- /* Computer point center for normal. */
- float3 center = float4_to_float3((isect->type & PRIMITIVE_ALL_MOTION) ?
+ /* Compute point center for normal. */
+ float3 center = float4_to_float3((isect->type & PRIMITIVE_MOTION) ?
motion_point(kg, sd->object, sd->prim, sd->time) :
kernel_tex_fetch(__points, sd->prim));
-
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- const Transform tfm = object_get_transform(kg, sd);
-
-# ifndef __KERNEL_OPTIX__
- center = transform_point(&tfm, center);
-# endif
+ object_position_transform_auto(kg, sd, &center);
}
/* Normal */
diff --git a/intern/cycles/kernel/geom/primitive.h b/intern/cycles/kernel/geom/primitive.h
index 9416385638c..2e8e0cda6f1 100644
--- a/intern/cycles/kernel/geom/primitive.h
+++ b/intern/cycles/kernel/geom/primitive.h
@@ -37,19 +37,19 @@ ccl_device_inline float primitive_surface_attribute_float(KernelGlobals kg,
ccl_private float *dx,
ccl_private float *dy)
{
- if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ if (sd->type & PRIMITIVE_TRIANGLE) {
if (subd_triangle_patch(kg, sd) == ~0)
return triangle_attribute_float(kg, sd, desc, dx, dy);
else
return subd_triangle_attribute_float(kg, sd, desc, dx, dy);
}
#ifdef __HAIR__
- else if (sd->type & PRIMITIVE_ALL_CURVE) {
+ else if (sd->type & PRIMITIVE_CURVE) {
return curve_attribute_float(kg, sd, desc, dx, dy);
}
#endif
#ifdef __POINTCLOUD__
- else if (sd->type & PRIMITIVE_ALL_POINT) {
+ else if (sd->type & PRIMITIVE_POINT) {
return point_attribute_float(kg, sd, desc, dx, dy);
}
#endif
@@ -68,19 +68,19 @@ ccl_device_inline float2 primitive_surface_attribute_float2(KernelGlobals kg,
ccl_private float2 *dx,
ccl_private float2 *dy)
{
- if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ if (sd->type & PRIMITIVE_TRIANGLE) {
if (subd_triangle_patch(kg, sd) == ~0)
return triangle_attribute_float2(kg, sd, desc, dx, dy);
else
return subd_triangle_attribute_float2(kg, sd, desc, dx, dy);
}
#ifdef __HAIR__
- else if (sd->type & PRIMITIVE_ALL_CURVE) {
+ else if (sd->type & PRIMITIVE_CURVE) {
return curve_attribute_float2(kg, sd, desc, dx, dy);
}
#endif
#ifdef __POINTCLOUD__
- else if (sd->type & PRIMITIVE_ALL_POINT) {
+ else if (sd->type & PRIMITIVE_POINT) {
return point_attribute_float2(kg, sd, desc, dx, dy);
}
#endif
@@ -99,19 +99,19 @@ ccl_device_inline float3 primitive_surface_attribute_float3(KernelGlobals kg,
ccl_private float3 *dx,
ccl_private float3 *dy)
{
- if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ if (sd->type & PRIMITIVE_TRIANGLE) {
if (subd_triangle_patch(kg, sd) == ~0)
return triangle_attribute_float3(kg, sd, desc, dx, dy);
else
return subd_triangle_attribute_float3(kg, sd, desc, dx, dy);
}
#ifdef __HAIR__
- else if (sd->type & PRIMITIVE_ALL_CURVE) {
+ else if (sd->type & PRIMITIVE_CURVE) {
return curve_attribute_float3(kg, sd, desc, dx, dy);
}
#endif
#ifdef __POINTCLOUD__
- else if (sd->type & PRIMITIVE_ALL_POINT) {
+ else if (sd->type & PRIMITIVE_POINT) {
return point_attribute_float3(kg, sd, desc, dx, dy);
}
#endif
@@ -130,19 +130,19 @@ ccl_device_forceinline float4 primitive_surface_attribute_float4(KernelGlobals k
ccl_private float4 *dx,
ccl_private float4 *dy)
{
- if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ if (sd->type & PRIMITIVE_TRIANGLE) {
if (subd_triangle_patch(kg, sd) == ~0)
return triangle_attribute_float4(kg, sd, desc, dx, dy);
else
return subd_triangle_attribute_float4(kg, sd, desc, dx, dy);
}
#ifdef __HAIR__
- else if (sd->type & PRIMITIVE_ALL_CURVE) {
+ else if (sd->type & PRIMITIVE_CURVE) {
return curve_attribute_float4(kg, sd, desc, dx, dy);
}
#endif
#ifdef __POINTCLOUD__
- else if (sd->type & PRIMITIVE_ALL_POINT) {
+ else if (sd->type & PRIMITIVE_POINT) {
return point_attribute_float4(kg, sd, desc, dx, dy);
}
#endif
@@ -246,7 +246,7 @@ ccl_device bool primitive_ptex(KernelGlobals kg,
ccl_device float3 primitive_tangent(KernelGlobals kg, ccl_private ShaderData *sd)
{
#if defined(__HAIR__) || defined(__POINTCLOUD__)
- if (sd->type & (PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_POINT))
+ if (sd->type & (PRIMITIVE_CURVE | PRIMITIVE_POINT))
# ifdef __DPDU__
return normalize(sd->dPdu);
# else
@@ -282,16 +282,16 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg,
float3 center;
#if defined(__HAIR__) || defined(__POINTCLOUD__)
- bool is_curve_or_point = sd->type & (PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_POINT);
+ bool is_curve_or_point = sd->type & (PRIMITIVE_CURVE | PRIMITIVE_POINT);
if (is_curve_or_point) {
center = make_float3(0.0f, 0.0f, 0.0f);
- if (sd->type & PRIMITIVE_ALL_CURVE) {
+ if (sd->type & PRIMITIVE_CURVE) {
# if defined(__HAIR__)
center = curve_motion_center_location(kg, sd);
# endif
}
- else if (sd->type & PRIMITIVE_ALL_POINT) {
+ else if (sd->type & PRIMITIVE_POINT) {
# if defined(__POINTCLOUD__)
center = point_motion_center_location(kg, sd);
# endif
@@ -331,7 +331,7 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg,
}
else
#endif
- if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ if (sd->type & PRIMITIVE_TRIANGLE) {
/* Triangle */
if (subd_triangle_patch(kg, sd) == ~0) {
motion_pre = triangle_attribute_float3(kg, sd, desc, NULL, NULL);
diff --git a/intern/cycles/kernel/geom/shader_data.h b/intern/cycles/kernel/geom/shader_data.h
index d3932545ef6..f5055d8b285 100644
--- a/intern/cycles/kernel/geom/shader_data.h
+++ b/intern/cycles/kernel/geom/shader_data.h
@@ -69,56 +69,58 @@ ccl_device_inline void shader_setup_from_ray(KernelGlobals kg,
sd->I = -ray->D;
#ifdef __HAIR__
- if (sd->type & PRIMITIVE_ALL_CURVE) {
+ if (sd->type & PRIMITIVE_CURVE) {
/* curve */
curve_shader_setup(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim);
}
else
#endif
#ifdef __POINTCLOUD__
- if (sd->type & PRIMITIVE_ALL_POINT) {
+ if (sd->type & PRIMITIVE_POINT) {
/* point */
point_shader_setup(kg, sd, isect, ray);
}
else
#endif
- if (sd->type & PRIMITIVE_TRIANGLE) {
- /* static triangle */
- float3 Ng = triangle_normal(kg, sd);
- sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
+ {
+ if (sd->type == PRIMITIVE_TRIANGLE) {
+ /* static triangle */
+ float3 Ng = triangle_normal(kg, sd);
+ sd->shader = kernel_tex_fetch(__tri_shader, sd->prim);
- /* vectors */
- sd->P = triangle_refine(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim);
- sd->Ng = Ng;
- sd->N = Ng;
+ /* vectors */
+ sd->P = triangle_refine(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim);
+ sd->Ng = Ng;
+ sd->N = Ng;
- /* smooth normal */
- if (sd->shader & SHADER_SMOOTH_NORMAL)
- sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
+ /* smooth normal */
+ if (sd->shader & SHADER_SMOOTH_NORMAL)
+ sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
#ifdef __DPDU__
- /* dPdu/dPdv */
- triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
+ /* dPdu/dPdv */
+ triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv);
#endif
- }
- else {
- /* motion triangle */
- motion_triangle_shader_setup(
- kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim, false);
- }
-
- sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
+ }
+ else {
+ /* motion triangle */
+ motion_triangle_shader_setup(
+ kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim, false);
+ }
- if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
- /* instance transform */
- object_normal_transform_auto(kg, sd, &sd->N);
- object_normal_transform_auto(kg, sd, &sd->Ng);
+ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
+ /* instance transform */
+ object_normal_transform_auto(kg, sd, &sd->N);
+ object_normal_transform_auto(kg, sd, &sd->Ng);
#ifdef __DPDU__
- object_dir_transform_auto(kg, sd, &sd->dPdu);
- object_dir_transform_auto(kg, sd, &sd->dPdv);
+ object_dir_transform_auto(kg, sd, &sd->dPdu);
+ object_dir_transform_auto(kg, sd, &sd->dPdv);
#endif
+ }
}
+ sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags;
+
/* backfacing test */
bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
@@ -201,7 +203,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg,
object_dir_transform_auto(kg, sd, &sd->I);
}
- if (sd->type & PRIMITIVE_TRIANGLE) {
+ if (sd->type == PRIMITIVE_TRIANGLE) {
/* smooth normal */
if (sd->shader & SHADER_SMOOTH_NORMAL) {
sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v);
diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h
index c9c586f5ae4..3d5b65458c7 100644
--- a/intern/cycles/kernel/integrator/shade_surface.h
+++ b/intern/cycles/kernel/integrator/shade_surface.h
@@ -82,7 +82,7 @@ ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg,
# ifdef __HAIR__
if (!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS) &&
- (sd->type & PRIMITIVE_ALL_TRIANGLE))
+ (sd->type & PRIMITIVE_TRIANGLE))
# else
if (!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS))
# endif
diff --git a/intern/cycles/kernel/light/sample.h b/intern/cycles/kernel/light/sample.h
index 83f6d733d3a..b6662c7f6b3 100644
--- a/intern/cycles/kernel/light/sample.h
+++ b/intern/cycles/kernel/light/sample.h
@@ -191,7 +191,7 @@ ccl_device_inline float3 shadow_ray_offset(KernelGlobals kg,
float3 Ng = (transmit ? -sd->Ng : sd->Ng);
float3 P = ray_offset(sd->P, Ng);
- if ((sd->type & PRIMITIVE_ALL_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) {
+ if ((sd->type & PRIMITIVE_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) {
const float offset_cutoff =
kernel_tex_fetch(__objects, sd->object).shadow_terminator_geometry_offset;
/* Do ray offset (heavy stuff) only for close to be terminated triangles:
diff --git a/intern/cycles/kernel/osl/services.cpp b/intern/cycles/kernel/osl/services.cpp
index 4007005dee7..a79fc323a13 100644
--- a/intern/cycles/kernel/osl/services.cpp
+++ b/intern/cycles/kernel/osl/services.cpp
@@ -960,13 +960,15 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg
return set_attribute_int(3, type, derivatives, val);
}
else if ((name == u_geom_trianglevertices || name == u_geom_polyvertices) &&
- sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ sd->type & PRIMITIVE_TRIANGLE) {
float3 P[3];
- if (sd->type & PRIMITIVE_TRIANGLE)
- triangle_vertices(kg, sd->prim, P);
- else
+ if (sd->type & PRIMITIVE_MOTION) {
motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, P);
+ }
+ else {
+ triangle_vertices(kg, sd->prim, P);
+ }
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
object_position_transform(kg, sd, &P[0]);
@@ -986,7 +988,7 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg
}
/* Hair Attributes */
else if (name == u_is_curve) {
- float f = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
+ float f = (sd->type & PRIMITIVE_CURVE) != 0;
return set_attribute_float(f, type, derivatives, val);
}
else if (name == u_curve_thickness) {
@@ -999,7 +1001,7 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg
}
/* point attributes */
else if (name == u_is_point) {
- float f = (sd->type & PRIMITIVE_ALL_POINT) != 0;
+ float f = (sd->type & PRIMITIVE_POINT) != 0;
return set_attribute_float(f, type, derivatives, val);
}
else if (name == u_point_radius) {
@@ -1007,7 +1009,7 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg
return set_attribute_float(f, type, derivatives, val);
}
else if (name == u_normal_map_normal) {
- if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ if (sd->type & PRIMITIVE_TRIANGLE) {
float3 f = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v);
return set_attribute_float3(f, type, derivatives, val);
}
diff --git a/intern/cycles/kernel/svm/bevel.h b/intern/cycles/kernel/svm/bevel.h
index 6799489514f..46dfb6631da 100644
--- a/intern/cycles/kernel/svm/bevel.h
+++ b/intern/cycles/kernel/svm/bevel.h
@@ -206,12 +206,12 @@ ccl_device float3 svm_bevel(
for (int hit = 0; hit < num_eval_hits; hit++) {
/* Quickly retrieve P and Ng without setting up ShaderData. */
float3 hit_P;
- if (sd->type & PRIMITIVE_TRIANGLE) {
+ if (sd->type == PRIMITIVE_TRIANGLE) {
hit_P = triangle_refine_local(
kg, sd, ray.P, ray.D, ray.t, isect.hits[hit].object, isect.hits[hit].prim);
}
# ifdef __OBJECT_MOTION__
- else if (sd->type & PRIMITIVE_MOTION_TRIANGLE) {
+ else if (sd->type == PRIMITIVE_MOTION_TRIANGLE) {
float3 verts[3];
motion_triangle_vertices(kg, sd->object, isect.hits[hit].prim, sd->time, verts);
hit_P = motion_triangle_refine_local(
@@ -236,11 +236,11 @@ ccl_device float3 svm_bevel(
float u = isect.hits[hit].u;
float v = isect.hits[hit].v;
- if (sd->type & PRIMITIVE_TRIANGLE) {
+ if (sd->type == PRIMITIVE_TRIANGLE) {
N = triangle_smooth_normal(kg, N, prim, u, v);
}
# ifdef __OBJECT_MOTION__
- else if (sd->type & PRIMITIVE_MOTION_TRIANGLE) {
+ else if (sd->type == PRIMITIVE_MOTION_TRIANGLE) {
N = motion_triangle_smooth_normal(kg, N, sd->object, prim, u, v, sd->time);
}
# endif /* __OBJECT_MOTION__ */
diff --git a/intern/cycles/kernel/svm/closure.h b/intern/cycles/kernel/svm/closure.h
index 71952e9e0f8..2ca22d58191 100644
--- a/intern/cycles/kernel/svm/closure.h
+++ b/intern/cycles/kernel/svm/closure.h
@@ -107,7 +107,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
}
float3 N = stack_valid(data_node.x) ? stack_load_float3(stack, data_node.x) : sd->N;
- if (!(sd->type & PRIMITIVE_ALL_CURVE)) {
+ if (!(sd->type & PRIMITIVE_CURVE)) {
N = ensure_valid_reflection(sd->Ng, sd->I, N);
}
@@ -191,7 +191,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
float3 clearcoat_normal = stack_valid(data_cn_ssr.x) ?
stack_load_float3(stack, data_cn_ssr.x) :
sd->N;
- if (!(sd->type & PRIMITIVE_ALL_CURVE)) {
+ if (!(sd->type & PRIMITIVE_CURVE)) {
clearcoat_normal = ensure_valid_reflection(sd->Ng, sd->I, clearcoat_normal);
}
float3 subsurface_radius = stack_valid(data_cn_ssr.y) ?
@@ -902,7 +902,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg,
if (stack_valid(data_node.y)) {
bsdf->T = normalize(stack_load_float3(stack, data_node.y));
}
- else if (!(sd->type & PRIMITIVE_ALL_CURVE)) {
+ else if (!(sd->type & PRIMITIVE_CURVE)) {
bsdf->T = normalize(sd->dPdv);
bsdf->offset = 0.0f;
}
diff --git a/intern/cycles/kernel/svm/geometry.h b/intern/cycles/kernel/svm/geometry.h
index 772942e0c08..2bac58b0aa2 100644
--- a/intern/cycles/kernel/svm/geometry.h
+++ b/intern/cycles/kernel/svm/geometry.h
@@ -227,7 +227,7 @@ ccl_device_noinline void svm_node_hair_info(KernelGlobals kg,
switch (type) {
case NODE_INFO_CURVE_IS_STRAND: {
- data = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
+ data = (sd->type & PRIMITIVE_CURVE) != 0;
stack_store_float(stack, out_offset, data);
break;
}
diff --git a/intern/cycles/kernel/svm/tex_coord.h b/intern/cycles/kernel/svm/tex_coord.h
index 5e0debc968a..4b12a0065a6 100644
--- a/intern/cycles/kernel/svm/tex_coord.h
+++ b/intern/cycles/kernel/svm/tex_coord.h
@@ -291,7 +291,7 @@ ccl_device_noinline void svm_node_normal_map(KernelGlobals kg,
if (space == NODE_NORMAL_MAP_TANGENT) {
/* tangent space */
- if (sd->object == OBJECT_NONE || (sd->type & PRIMITIVE_ALL_TRIANGLE) == 0) {
+ if (sd->object == OBJECT_NONE || (sd->type & PRIMITIVE_TRIANGLE) == 0) {
/* Fallback to unperturbed normal. */
stack_store_float3(stack, normal_offset, sd->N);
return;
diff --git a/intern/cycles/kernel/svm/wireframe.h b/intern/cycles/kernel/svm/wireframe.h
index 645dc59f22e..2c91ab3dedf 100644
--- a/intern/cycles/kernel/svm/wireframe.h
+++ b/intern/cycles/kernel/svm/wireframe.h
@@ -43,7 +43,7 @@ ccl_device_inline float wireframe(KernelGlobals kg,
ccl_private float3 *P)
{
#if defined(__HAIR__) || defined(__POINTCLOUD__)
- if (sd->prim != PRIM_NONE && sd->type & PRIMITIVE_ALL_TRIANGLE)
+ if (sd->prim != PRIM_NONE && sd->type & PRIMITIVE_TRIANGLE)
#else
if (sd->prim != PRIM_NONE)
#endif
@@ -54,10 +54,12 @@ ccl_device_inline float wireframe(KernelGlobals kg,
/* Triangles */
int np = 3;
- if (sd->type & PRIMITIVE_TRIANGLE)
- triangle_vertices(kg, sd->prim, Co);
- else
+ if (sd->type & PRIMITIVE_MOTION) {
motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, Co);
+ }
+ else {
+ triangle_vertices(kg, sd->prim, Co);
+ }
if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
object_position_transform(kg, sd, &Co[0]);
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 855cc97edbf..5d41abb53c4 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -202,7 +202,7 @@ enum SamplingPattern {
/* These flags values correspond to `raytypes` in `osl.cpp`, so keep them in sync! */
-enum PathRayFlag {
+enum PathRayFlag : uint32_t {
/* --------------------------------------------------------------------
* Ray visibility.
*
@@ -388,6 +388,7 @@ typedef enum PassType {
PASS_DENOISING_NORMAL,
PASS_DENOISING_ALBEDO,
PASS_DENOISING_DEPTH,
+ PASS_DENOISING_PREVIOUS,
/* PASS_SHADOW_CATCHER accumulates contribution of shadow catcher object which is not affected by
* any other object. The pass accessor will divide the combined pass by the shadow catcher. The
@@ -537,31 +538,34 @@ typedef struct Intersection {
typedef enum PrimitiveType {
PRIMITIVE_NONE = 0,
PRIMITIVE_TRIANGLE = (1 << 0),
- PRIMITIVE_MOTION_TRIANGLE = (1 << 1),
- PRIMITIVE_CURVE_THICK = (1 << 2),
- PRIMITIVE_MOTION_CURVE_THICK = (1 << 3),
- PRIMITIVE_CURVE_RIBBON = (1 << 4),
- PRIMITIVE_MOTION_CURVE_RIBBON = (1 << 5),
- PRIMITIVE_POINT = (1 << 6),
- PRIMITIVE_MOTION_POINT = (1 << 7),
- PRIMITIVE_VOLUME = (1 << 8),
- PRIMITIVE_LAMP = (1 << 9),
-
- PRIMITIVE_ALL_TRIANGLE = (PRIMITIVE_TRIANGLE | PRIMITIVE_MOTION_TRIANGLE),
- PRIMITIVE_ALL_CURVE = (PRIMITIVE_CURVE_THICK | PRIMITIVE_MOTION_CURVE_THICK |
- PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON),
- PRIMITIVE_ALL_POINT = (PRIMITIVE_POINT | PRIMITIVE_MOTION_POINT),
- PRIMITIVE_ALL_VOLUME = (PRIMITIVE_VOLUME),
- PRIMITIVE_ALL_MOTION = (PRIMITIVE_MOTION_TRIANGLE | PRIMITIVE_MOTION_CURVE_THICK |
- PRIMITIVE_MOTION_CURVE_RIBBON | PRIMITIVE_MOTION_POINT),
- PRIMITIVE_ALL = (PRIMITIVE_ALL_TRIANGLE | PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_VOLUME |
- PRIMITIVE_LAMP | PRIMITIVE_ALL_POINT),
-
- PRIMITIVE_NUM = 10,
+ PRIMITIVE_CURVE_THICK = (1 << 1),
+ PRIMITIVE_CURVE_RIBBON = (1 << 2),
+ PRIMITIVE_POINT = (1 << 3),
+ PRIMITIVE_VOLUME = (1 << 4),
+ PRIMITIVE_LAMP = (1 << 5),
+
+ PRIMITIVE_MOTION = (1 << 6),
+ PRIMITIVE_MOTION_TRIANGLE = (PRIMITIVE_TRIANGLE | PRIMITIVE_MOTION),
+ PRIMITIVE_MOTION_CURVE_THICK = (PRIMITIVE_CURVE_THICK | PRIMITIVE_MOTION),
+ PRIMITIVE_MOTION_CURVE_RIBBON = (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION),
+ PRIMITIVE_MOTION_POINT = (PRIMITIVE_POINT | PRIMITIVE_MOTION),
+
+ PRIMITIVE_CURVE = (PRIMITIVE_CURVE_THICK | PRIMITIVE_CURVE_RIBBON),
+
+ PRIMITIVE_ALL = (PRIMITIVE_TRIANGLE | PRIMITIVE_CURVE | PRIMITIVE_POINT | PRIMITIVE_VOLUME |
+ PRIMITIVE_LAMP | PRIMITIVE_MOTION),
+
+ PRIMITIVE_NUM_SHAPES = 6,
+ PRIMITIVE_NUM_BITS = PRIMITIVE_NUM_SHAPES + 1, /* All shapes + motion bit. */
+ PRIMITIVE_NUM = PRIMITIVE_NUM_SHAPES * 2, /* With and without motion. */
} PrimitiveType;
-#define PRIMITIVE_PACK_SEGMENT(type, segment) ((segment << PRIMITIVE_NUM) | (type))
-#define PRIMITIVE_UNPACK_SEGMENT(type) (type >> PRIMITIVE_NUM)
+/* Convert type to index in range 0..PRIMITIVE_NUM-1. */
+#define PRIMITIVE_INDEX(type) (bitscan((uint32_t)(type)) * 2 + (((type)&PRIMITIVE_MOTION) ? 1 : 0))
+
+/* Pack segment into type value to save space. */
+#define PRIMITIVE_PACK_SEGMENT(type, segment) ((segment << PRIMITIVE_NUM_BITS) | (type))
+#define PRIMITIVE_UNPACK_SEGMENT(type) (type >> PRIMITIVE_NUM_BITS)
typedef enum CurveShapeType {
CURVE_RIBBON = 0,
@@ -1556,7 +1560,7 @@ enum {
/* Kernel Features */
-enum KernelFeatureFlag : unsigned int {
+enum KernelFeatureFlag : uint32_t {
/* Shader nodes. */
KERNEL_FEATURE_NODE_BSDF = (1U << 0U),
KERNEL_FEATURE_NODE_EMISSION = (1U << 1U),
diff --git a/intern/cycles/scene/geometry.cpp b/intern/cycles/scene/geometry.cpp
index 558b0e13b0f..49d18d00dd7 100644
--- a/intern/cycles/scene/geometry.cpp
+++ b/intern/cycles/scene/geometry.cpp
@@ -1002,10 +1002,10 @@ void GeometryManager::device_update_attributes(Device *device,
/* After mesh attributes and patch tables have been copied to device memory,
* we need to update offsets in the objects. */
- scene->object_manager->device_update_mesh_offsets(device, dscene, scene);
+ scene->object_manager->device_update_geom_offsets(device, dscene, scene);
}
-void GeometryManager::mesh_calc_offset(Scene *scene, BVHLayout bvh_layout)
+void GeometryManager::geom_calc_offset(Scene *scene, BVHLayout bvh_layout)
{
size_t vert_size = 0;
size_t tri_size = 0;
@@ -1370,22 +1370,22 @@ enum {
DEVICE_MESH_DATA_MODIFIED = (1 << 1),
DEVICE_POINT_DATA_MODIFIED = (1 << 2),
- ATTR_FLOAT_MODIFIED = (1 << 2),
- ATTR_FLOAT2_MODIFIED = (1 << 3),
- ATTR_FLOAT3_MODIFIED = (1 << 4),
- ATTR_FLOAT4_MODIFIED = (1 << 5),
- ATTR_UCHAR4_MODIFIED = (1 << 6),
+ ATTR_FLOAT_MODIFIED = (1 << 3),
+ ATTR_FLOAT2_MODIFIED = (1 << 4),
+ ATTR_FLOAT3_MODIFIED = (1 << 5),
+ ATTR_FLOAT4_MODIFIED = (1 << 6),
+ ATTR_UCHAR4_MODIFIED = (1 << 7),
- CURVE_DATA_NEED_REALLOC = (1 << 7),
- MESH_DATA_NEED_REALLOC = (1 << 8),
- POINT_DATA_NEED_REALLOC = (1 << 9),
+ CURVE_DATA_NEED_REALLOC = (1 << 8),
+ MESH_DATA_NEED_REALLOC = (1 << 9),
+ POINT_DATA_NEED_REALLOC = (1 << 10),
- ATTR_FLOAT_NEEDS_REALLOC = (1 << 10),
- ATTR_FLOAT2_NEEDS_REALLOC = (1 << 11),
- ATTR_FLOAT3_NEEDS_REALLOC = (1 << 12),
- ATTR_FLOAT4_NEEDS_REALLOC = (1 << 13),
+ ATTR_FLOAT_NEEDS_REALLOC = (1 << 11),
+ ATTR_FLOAT2_NEEDS_REALLOC = (1 << 12),
+ ATTR_FLOAT3_NEEDS_REALLOC = (1 << 13),
+ ATTR_FLOAT4_NEEDS_REALLOC = (1 << 14),
- ATTR_UCHAR4_NEEDS_REALLOC = (1 << 14),
+ ATTR_UCHAR4_NEEDS_REALLOC = (1 << 15),
ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC |
ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC |
@@ -1922,7 +1922,7 @@ void GeometryManager::device_update(Device *device,
const BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout,
device->get_bvh_layout_mask());
- mesh_calc_offset(scene, bvh_layout);
+ geom_calc_offset(scene, bvh_layout);
if (true_displacement_used || curve_shadow_transparency_used) {
scoped_callback_timer timer([scene](double time) {
if (scene->update_stats) {
diff --git a/intern/cycles/scene/geometry.h b/intern/cycles/scene/geometry.h
index b02387c3020..63ab2c2f4e0 100644
--- a/intern/cycles/scene/geometry.h
+++ b/intern/cycles/scene/geometry.h
@@ -242,7 +242,7 @@ class GeometryManager {
vector<AttributeRequestSet> &object_attributes);
/* Compute verts/triangles/curves offsets in global arrays. */
- void mesh_calc_offset(Scene *scene, BVHLayout bvh_layout);
+ void geom_calc_offset(Scene *scene, BVHLayout bvh_layout);
void device_update_object(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress);
diff --git a/intern/cycles/scene/image.cpp b/intern/cycles/scene/image.cpp
index 8bb2d87fd1e..3595ca55a46 100644
--- a/intern/cycles/scene/image.cpp
+++ b/intern/cycles/scene/image.cpp
@@ -381,8 +381,15 @@ ImageHandle ImageManager::add_image(const string &filename,
foreach (int tile, tiles) {
string tile_filename = filename;
+
+ /* Since we don't have information about the exact tile format used in this code location,
+ * just attempt all replacement patterns that Blender supports. */
if (tile != 0) {
string_replace(tile_filename, "<UDIM>", string_printf("%04d", tile));
+
+ int u = ((tile - 1001) % 10);
+ int v = ((tile - 1001) / 10);
+ string_replace(tile_filename, "<UVTILE>", string_printf("u%d_v%d", u + 1, v + 1));
}
const int slot = add_image_slot(new OIIOImageLoader(tile_filename), params, false);
handle.tile_slots.push_back(slot);
diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp
index f8110b20d6e..aa0a64f49ec 100644
--- a/intern/cycles/scene/object.cpp
+++ b/intern/cycles/scene/object.cpp
@@ -821,7 +821,7 @@ void ObjectManager::device_update_flags(
dscene->object_volume_step.clear_modified();
}
-void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Scene *scene)
+void ObjectManager::device_update_geom_offsets(Device *, DeviceScene *dscene, Scene *scene)
{
if (dscene->objects.size() == 0) {
return;
diff --git a/intern/cycles/scene/object.h b/intern/cycles/scene/object.h
index f983b58b59c..3a97fabbdaa 100644
--- a/intern/cycles/scene/object.h
+++ b/intern/cycles/scene/object.h
@@ -162,7 +162,7 @@ class ObjectManager {
Scene *scene,
Progress &progress,
bool bounds_valid = true);
- void device_update_mesh_offsets(Device *device, DeviceScene *dscene, Scene *scene);
+ void device_update_geom_offsets(Device *device, DeviceScene *dscene, Scene *scene);
void device_free(Device *device, DeviceScene *dscene, bool force_free);
diff --git a/intern/cycles/scene/pass.cpp b/intern/cycles/scene/pass.cpp
index a885ede50a4..ca5687e6b4d 100644
--- a/intern/cycles/scene/pass.cpp
+++ b/intern/cycles/scene/pass.cpp
@@ -101,6 +101,7 @@ const NodeEnum *Pass::get_type_enum()
pass_type_enum.insert("denoising_normal", PASS_DENOISING_NORMAL);
pass_type_enum.insert("denoising_albedo", PASS_DENOISING_ALBEDO);
pass_type_enum.insert("denoising_depth", PASS_DENOISING_DEPTH);
+ pass_type_enum.insert("denoising_previous", PASS_DENOISING_PREVIOUS);
pass_type_enum.insert("shadow_catcher", PASS_SHADOW_CATCHER);
pass_type_enum.insert("shadow_catcher_sample_count", PASS_SHADOW_CATCHER_SAMPLE_COUNT);
@@ -299,6 +300,10 @@ PassInfo Pass::get_info(const PassType type, const bool include_albedo)
case PASS_DENOISING_DEPTH:
pass_info.num_components = 1;
break;
+ case PASS_DENOISING_PREVIOUS:
+ pass_info.num_components = 3;
+ pass_info.use_exposure = true;
+ break;
case PASS_SHADOW_CATCHER:
pass_info.num_components = 3;
diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp
index c345d5bbc9a..e8316ad41b4 100644
--- a/intern/cycles/scene/shader_nodes.cpp
+++ b/intern/cycles/scene/shader_nodes.cpp
@@ -5901,7 +5901,7 @@ VectorMapRangeNode::VectorMapRangeNode() : ShaderNode(get_node_type())
{
}
-void VectorMapRangeNode::expand(ShaderGraph *graph)
+void VectorMapRangeNode::expand(ShaderGraph * /*graph*/)
{
}
diff --git a/intern/cycles/session/denoising.cpp b/intern/cycles/session/denoising.cpp
index 21df068092a..b9021b9cbe2 100644
--- a/intern/cycles/session/denoising.cpp
+++ b/intern/cycles/session/denoising.cpp
@@ -16,62 +16,17 @@
#include "session/denoising.h"
-#if 0
+#include "util/map.h"
+#include "util/system.h"
+#include "util/task.h"
+#include "util/time.h"
-# include "kernel/filter/filter_defines.h"
-
-# include "util/util_foreach.h"
-# include "util/util_map.h"
-# include "util/util_system.h"
-# include "util/util_task.h"
-# include "util/util_time.h"
-
-# include <OpenImageIO/filesystem.h>
+#include <OpenImageIO/filesystem.h>
CCL_NAMESPACE_BEGIN
/* Utility Functions */
-static void print_progress(int num, int total, int frame, int num_frames)
-{
- const char *label = "Denoise Frame ";
- int cols = system_console_width();
-
- cols -= strlen(label);
-
- int len = 1;
- for (int x = total; x > 9; x /= 10) {
- len++;
- }
-
- int bars = cols - 2 * len - 6;
-
- printf("\r%s", label);
-
- if (num_frames > 1) {
- int frame_len = 1;
- for (int x = num_frames - 1; x > 9; x /= 10) {
- frame_len++;
- }
- bars -= frame_len + 2;
- printf("%*d ", frame_len, frame);
- }
-
- int v = int(float(num) * bars / total);
- printf("[");
- for (int i = 0; i < v; i++) {
- printf("=");
- }
- if (v < bars) {
- printf(">");
- }
- for (int i = v + 1; i < bars; i++) {
- printf(" ");
- }
- printf(string_printf("] %%%dd / %d", len, total).c_str(), num);
- fflush(stdout);
-}
-
/* Splits in at its last dot, setting suffix to the part after the dot and in to the part before
* it. Returns whether a dot was found. */
static bool split_last_dot(string &in, string &suffix)
@@ -125,24 +80,18 @@ static void fill_mapping(vector<ChannelMapping> &map, int pos, string name, stri
}
}
-static const int INPUT_NUM_CHANNELS = 15;
-static const int INPUT_DENOISING_DEPTH = 0;
-static const int INPUT_DENOISING_NORMAL = 1;
-static const int INPUT_DENOISING_SHADOWING = 4;
-static const int INPUT_DENOISING_ALBEDO = 5;
-static const int INPUT_NOISY_IMAGE = 8;
-static const int INPUT_DENOISING_VARIANCE = 11;
-static const int INPUT_DENOISING_INTENSITY = 14;
+static const int INPUT_NUM_CHANNELS = 13;
+static const int INPUT_NOISY_IMAGE = 0;
+static const int INPUT_DENOISING_NORMAL = 3;
+static const int INPUT_DENOISING_ALBEDO = 6;
+static const int INPUT_MOTION = 9;
static vector<ChannelMapping> input_channels()
{
vector<ChannelMapping> map;
- fill_mapping(map, INPUT_DENOISING_DEPTH, "Denoising Depth", "Z");
+ fill_mapping(map, INPUT_NOISY_IMAGE, "Combined", "RGB");
fill_mapping(map, INPUT_DENOISING_NORMAL, "Denoising Normal", "XYZ");
- fill_mapping(map, INPUT_DENOISING_SHADOWING, "Denoising Shadowing", "X");
fill_mapping(map, INPUT_DENOISING_ALBEDO, "Denoising Albedo", "RGB");
- fill_mapping(map, INPUT_NOISY_IMAGE, "Noisy Image", "RGB");
- fill_mapping(map, INPUT_DENOISING_VARIANCE, "Denoising Variance", "RGB");
- fill_mapping(map, INPUT_DENOISING_INTENSITY, "Denoising Intensity", "X");
+ fill_mapping(map, INPUT_MOTION, "Vector", "XYZW");
return map;
}
@@ -162,7 +111,7 @@ bool DenoiseImageLayer::detect_denoising_channels()
input_to_image_channel.clear();
input_to_image_channel.resize(INPUT_NUM_CHANNELS, -1);
- foreach (const ChannelMapping &mapping, input_channels()) {
+ for (const ChannelMapping &mapping : input_channels()) {
vector<string>::iterator i = find(channels.begin(), channels.end(), mapping.name);
if (i == channels.end()) {
return false;
@@ -177,7 +126,7 @@ bool DenoiseImageLayer::detect_denoising_channels()
output_to_image_channel.clear();
output_to_image_channel.resize(OUTPUT_NUM_CHANNELS, -1);
- foreach (const ChannelMapping &mapping, output_channels()) {
+ for (const ChannelMapping &mapping : output_channels()) {
vector<string>::iterator i = find(channels.begin(), channels.end(), mapping.name);
if (i == channels.end()) {
return false;
@@ -199,18 +148,16 @@ bool DenoiseImageLayer::detect_denoising_channels()
return true;
}
-bool DenoiseImageLayer::match_channels(int neighbor,
- const std::vector<string> &channelnames,
+bool DenoiseImageLayer::match_channels(const std::vector<string> &channelnames,
const std::vector<string> &neighbor_channelnames)
{
- neighbor_input_to_image_channel.resize(neighbor + 1);
- vector<int> &mapping = neighbor_input_to_image_channel[neighbor];
+ vector<int> &mapping = previous_output_to_image_channel;
assert(mapping.size() == 0);
- mapping.resize(input_to_image_channel.size(), -1);
+ mapping.resize(output_to_image_channel.size(), -1);
- for (int i = 0; i < input_to_image_channel.size(); i++) {
- const string &channel = channelnames[input_to_image_channel[i]];
+ for (int i = 0; i < output_to_image_channel.size(); i++) {
+ const string &channel = channelnames[output_to_image_channel[i]];
std::vector<string>::const_iterator frame_channel = find(
neighbor_channelnames.begin(), neighbor_channelnames.end(), channel);
@@ -226,19 +173,9 @@ bool DenoiseImageLayer::match_channels(int neighbor,
/* Denoise Task */
-DenoiseTask::DenoiseTask(Device *device,
- DenoiserPipeline *denoiser,
- int frame,
- const vector<int> &neighbor_frames)
- : denoiser(denoiser),
- device(device),
- frame(frame),
- neighbor_frames(neighbor_frames),
- current_layer(0),
- input_pixels(device, "filter input buffer", MEM_READ_ONLY),
- num_tiles(0)
+DenoiseTask::DenoiseTask(Device *device, DenoiserPipeline *denoiser, int frame)
+ : denoiser(denoiser), device(device), frame(frame), current_layer(0), buffers(device)
{
- image.samples = denoiser->samples_override;
}
DenoiseTask::~DenoiseTask()
@@ -246,284 +183,39 @@ DenoiseTask::~DenoiseTask()
free();
}
-/* Device callbacks */
-
-bool DenoiseTask::acquire_tile(Device *device, Device *tile_device, RenderTile &tile)
-{
- thread_scoped_lock tile_lock(tiles_mutex);
-
- if (tiles.empty()) {
- return false;
- }
-
- tile = tiles.front();
- tiles.pop_front();
-
- device->map_tile(tile_device, tile);
-
- print_progress(num_tiles - tiles.size(), num_tiles, frame, denoiser->num_frames);
-
- return true;
-}
-
-/* Mapping tiles is required for regular rendering since each tile has its separate memory
- * which may be allocated on a different device.
- * For standalone denoising, there is a single memory that is present on all devices, so the only
- * thing that needs to be done here is to specify the surrounding tile geometry.
- *
- * However, since there is only one large memory, the denoised result has to be written to
- * a different buffer to avoid having to copy an entire horizontal slice of the image. */
-void DenoiseTask::map_neighboring_tiles(RenderTileNeighbors &neighbors, Device *tile_device)
-{
- RenderTile &center_tile = neighbors.tiles[RenderTileNeighbors::CENTER];
- RenderTile &target_tile = neighbors.target;
-
- /* Fill tile information. */
- for (int i = 0; i < RenderTileNeighbors::SIZE; i++) {
- if (i == RenderTileNeighbors::CENTER) {
- continue;
- }
-
- RenderTile &tile = neighbors.tiles[i];
- int dx = (i % 3) - 1;
- int dy = (i / 3) - 1;
- tile.x = clamp(center_tile.x + dx * denoiser->tile_size.x, 0, image.width);
- tile.w = clamp(center_tile.x + (dx + 1) * denoiser->tile_size.x, 0, image.width) - tile.x;
- tile.y = clamp(center_tile.y + dy * denoiser->tile_size.y, 0, image.height);
- tile.h = clamp(center_tile.y + (dy + 1) * denoiser->tile_size.y, 0, image.height) - tile.y;
-
- tile.buffer = center_tile.buffer;
- tile.offset = center_tile.offset;
- tile.stride = image.width;
- }
-
- /* Allocate output buffer. */
- device_vector<float> *output_mem = new device_vector<float>(
- tile_device, "denoising_output", MEM_READ_WRITE);
- output_mem->alloc(OUTPUT_NUM_CHANNELS * center_tile.w * center_tile.h);
-
- /* Fill output buffer with noisy image, assumed by kernel_filter_finalize
- * when skipping denoising of some pixels. */
- float *result = output_mem->data();
- float *in = &image.pixels[image.num_channels * (center_tile.y * image.width + center_tile.x)];
-
- const DenoiseImageLayer &layer = image.layers[current_layer];
- const int *input_to_image_channel = layer.input_to_image_channel.data();
-
- for (int y = 0; y < center_tile.h; y++) {
- for (int x = 0; x < center_tile.w; x++, result += OUTPUT_NUM_CHANNELS) {
- for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) {
- result[i] = in[image.num_channels * x + input_to_image_channel[INPUT_NOISY_IMAGE + i]];
- }
- }
- in += image.num_channels * image.width;
- }
-
- output_mem->copy_to_device();
-
- /* Fill output tile info. */
- target_tile = center_tile;
- target_tile.buffer = output_mem->device_pointer;
- target_tile.stride = target_tile.w;
- target_tile.offset -= target_tile.x + target_tile.y * target_tile.stride;
-
- thread_scoped_lock output_lock(output_mutex);
- assert(output_pixels.count(center_tile.tile_index) == 0);
- output_pixels[target_tile.tile_index] = output_mem;
-}
-
-void DenoiseTask::unmap_neighboring_tiles(RenderTileNeighbors &neighbors)
-{
- RenderTile &center_tile = neighbors.tiles[RenderTileNeighbors::CENTER];
- RenderTile &target_tile = neighbors.target;
-
- thread_scoped_lock output_lock(output_mutex);
- assert(output_pixels.count(center_tile.tile_index) == 1);
- device_vector<float> *output_mem = output_pixels[target_tile.tile_index];
- output_pixels.erase(center_tile.tile_index);
- output_lock.unlock();
-
- /* Copy denoised pixels from device. */
- output_mem->copy_from_device(0, OUTPUT_NUM_CHANNELS * target_tile.w, target_tile.h);
-
- float *result = output_mem->data();
- float *out = &image.pixels[image.num_channels * (target_tile.y * image.width + target_tile.x)];
-
- const DenoiseImageLayer &layer = image.layers[current_layer];
- const int *output_to_image_channel = layer.output_to_image_channel.data();
-
- for (int y = 0; y < target_tile.h; y++) {
- for (int x = 0; x < target_tile.w; x++, result += OUTPUT_NUM_CHANNELS) {
- for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) {
- out[image.num_channels * x + output_to_image_channel[i]] = result[i];
- }
- }
- out += image.num_channels * image.width;
- }
-
- /* Free device buffer. */
- output_mem->free();
- delete output_mem;
-}
-
-void DenoiseTask::release_tile()
-{
-}
-
-bool DenoiseTask::get_cancel()
-{
- return false;
-}
-
-void DenoiseTask::create_task(DeviceTask &task)
-{
- /* Callback functions. */
- task.acquire_tile = function_bind(&DenoiseTask::acquire_tile, this, device, _1, _2);
- task.map_neighbor_tiles = function_bind(&DenoiseTask::map_neighboring_tiles, this, _1, _2);
- task.unmap_neighbor_tiles = function_bind(&DenoiseTask::unmap_neighboring_tiles, this, _1);
- task.release_tile = function_bind(&DenoiseTask::release_tile, this);
- task.get_cancel = function_bind(&DenoiseTask::get_cancel, this);
-
- /* Denoising parameters. */
- task.denoising = denoiser->params;
- task.denoising.type = DENOISER_NLM;
- task.denoising.use = true;
- task.denoising_from_render = false;
-
- task.denoising_frames.resize(neighbor_frames.size());
- for (int i = 0; i < neighbor_frames.size(); i++) {
- task.denoising_frames[i] = neighbor_frames[i] - frame;
- }
-
- /* Buffer parameters. */
- task.pass_stride = INPUT_NUM_CHANNELS;
- task.target_pass_stride = OUTPUT_NUM_CHANNELS;
- task.pass_denoising_data = 0;
- task.pass_denoising_clean = -1;
- task.frame_stride = image.width * image.height * INPUT_NUM_CHANNELS;
-
- /* Create tiles. */
- thread_scoped_lock tile_lock(tiles_mutex);
- thread_scoped_lock output_lock(output_mutex);
-
- tiles.clear();
- assert(output_pixels.empty());
- output_pixels.clear();
-
- int tiles_x = divide_up(image.width, denoiser->tile_size.x);
- int tiles_y = divide_up(image.height, denoiser->tile_size.y);
-
- for (int ty = 0; ty < tiles_y; ty++) {
- for (int tx = 0; tx < tiles_x; tx++) {
- RenderTile tile;
- tile.x = tx * denoiser->tile_size.x;
- tile.y = ty * denoiser->tile_size.y;
- tile.w = min(image.width - tile.x, denoiser->tile_size.x);
- tile.h = min(image.height - tile.y, denoiser->tile_size.y);
- tile.start_sample = 0;
- tile.num_samples = image.layers[current_layer].samples;
- tile.sample = 0;
- tile.offset = 0;
- tile.stride = image.width;
- tile.tile_index = ty * tiles_x + tx;
- tile.task = RenderTile::DENOISE;
- tile.buffers = NULL;
- tile.buffer = input_pixels.device_pointer;
- tiles.push_back(tile);
- }
- }
-
- num_tiles = tiles.size();
-}
-
/* Denoiser Operations */
bool DenoiseTask::load_input_pixels(int layer)
{
- int w = image.width;
- int h = image.height;
- int num_pixels = image.width * image.height;
- int frame_stride = num_pixels * INPUT_NUM_CHANNELS;
-
/* Load center image */
DenoiseImageLayer &image_layer = image.layers[layer];
- float *buffer_data = input_pixels.data();
- image.read_pixels(image_layer, buffer_data);
- buffer_data += frame_stride;
-
- /* Load neighbor images */
- for (int i = 0; i < image.in_neighbors.size(); i++) {
- if (!image.read_neighbor_pixels(i, image_layer, buffer_data)) {
- error = "Failed to read neighbor frame pixels";
- return false;
- }
- buffer_data += frame_stride;
- }
-
- /* Preprocess */
- buffer_data = input_pixels.data();
- for (int neighbor = 0; neighbor < image.in_neighbors.size() + 1; neighbor++) {
- /* Clamp */
- if (denoiser->params.clamp_input) {
- for (int i = 0; i < num_pixels * INPUT_NUM_CHANNELS; i++) {
- buffer_data[i] = clamp(buffer_data[i], -1e8f, 1e8f);
- }
- }
-
- /* Box blur */
- int r = 5 * denoiser->params.radius;
- float *data = buffer_data + 14;
- array<float> temp(num_pixels);
-
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- int n = 0;
- float sum = 0.0f;
- for (int dx = max(x - r, 0); dx < min(x + r + 1, w); dx++, n++) {
- sum += data[INPUT_NUM_CHANNELS * (y * w + dx)];
- }
- temp[y * w + x] = sum / n;
- }
- }
-
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- int n = 0;
- float sum = 0.0f;
-
- for (int dy = max(y - r, 0); dy < min(y + r + 1, h); dy++, n++) {
- sum += temp[dy * w + x];
- }
+ float *buffer_data = buffers.buffer.data();
+ image.read_pixels(image_layer, buffers.params, buffer_data);
- data[INPUT_NUM_CHANNELS * (y * w + x)] = sum / n;
- }
- }
-
- /* Highlight compression */
- data = buffer_data + 8;
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- int idx = INPUT_NUM_CHANNELS * (y * w + x);
- float3 color = make_float3(data[idx], data[idx + 1], data[idx + 2]);
- color = color_highlight_compress(color, NULL);
- data[idx] = color.x;
- data[idx + 1] = color.y;
- data[idx + 2] = color.z;
- }
- }
-
- buffer_data += frame_stride;
+ /* Load previous image */
+ if (frame > 0 && !image.read_previous_pixels(image_layer, buffers.params, buffer_data)) {
+ error = "Failed to read neighbor frame pixels";
+ return false;
}
/* Copy to device */
- input_pixels.copy_to_device();
+ buffers.buffer.copy_to_device();
return true;
}
/* Task stages */
+static void add_pass(vector<Pass *> &passes, PassType type, PassMode mode = PassMode::NOISY)
+{
+ Pass *pass = new Pass();
+ pass->set_type(type);
+ pass->set_mode(mode);
+
+ passes.push_back(pass);
+}
+
bool DenoiseTask::load()
{
string center_filepath = denoiser->input[frame];
@@ -531,7 +223,8 @@ bool DenoiseTask::load()
return false;
}
- if (!image.load_neighbors(denoiser->input, neighbor_frames, error)) {
+ /* Use previous frame output as input for subsequent frames. */
+ if (frame > 0 && !image.load_previous(denoiser->output[frame - 1], error)) {
return false;
}
@@ -540,10 +233,35 @@ bool DenoiseTask::load()
return false;
}
+ /* Enable temporal denoising for frames after the first (which will use the output from the
+ * previous frames). */
+ DenoiseParams params = denoiser->denoiser->get_params();
+ params.temporally_stable = frame > 0;
+ denoiser->denoiser->set_params(params);
+
/* Allocate device buffer. */
- int num_frames = image.in_neighbors.size() + 1;
- input_pixels.alloc(image.width * INPUT_NUM_CHANNELS, image.height * num_frames);
- input_pixels.zero_to_device();
+ vector<Pass *> passes;
+ add_pass(passes, PassType::PASS_COMBINED);
+ add_pass(passes, PassType::PASS_DENOISING_ALBEDO);
+ add_pass(passes, PassType::PASS_DENOISING_NORMAL);
+ add_pass(passes, PassType::PASS_MOTION);
+ add_pass(passes, PassType::PASS_DENOISING_PREVIOUS);
+ add_pass(passes, PassType::PASS_COMBINED, PassMode::DENOISED);
+
+ BufferParams buffer_params;
+ buffer_params.width = image.width;
+ buffer_params.height = image.height;
+ buffer_params.full_x = 0;
+ buffer_params.full_y = 0;
+ buffer_params.full_width = image.width;
+ buffer_params.full_height = image.height;
+ buffer_params.update_passes(passes);
+
+ for (Pass *pass : passes) {
+ delete pass;
+ }
+
+ buffers.reset(buffer_params);
/* Read pixels for first layer. */
current_layer = 0;
@@ -565,10 +283,26 @@ bool DenoiseTask::exec()
}
/* Run task on device. */
- DeviceTask task(DeviceTask::RENDER);
- create_task(task);
- device->task_add(task);
- device->task_wait();
+ denoiser->denoiser->denoise_buffer(buffers.params, &buffers, 1, true);
+
+ /* Copy denoised pixels from device. */
+ buffers.buffer.copy_from_device();
+
+ float *result = buffers.buffer.data(), *out = image.pixels.data();
+
+ const DenoiseImageLayer &layer = image.layers[current_layer];
+ const int *output_to_image_channel = layer.output_to_image_channel.data();
+
+ for (int y = 0; y < image.height; y++) {
+ for (int x = 0; x < image.width; x++, result += buffers.params.pass_stride) {
+ for (int j = 0; j < OUTPUT_NUM_CHANNELS; j++) {
+ int offset = buffers.params.get_pass_offset(PASS_COMBINED, PassMode::DENOISED);
+ int image_channel = output_to_image_channel[j];
+ out[image.num_channels * x + image_channel] = result[offset + j];
+ }
+ }
+ out += image.num_channels * image.width;
+ }
printf("\n");
}
@@ -586,8 +320,7 @@ bool DenoiseTask::save()
void DenoiseTask::free()
{
image.free();
- input_pixels.free();
- assert(output_pixels.empty());
+ buffers.buffer.free();
}
/* Denoise Image Storage */
@@ -607,7 +340,7 @@ DenoiseImage::~DenoiseImage()
void DenoiseImage::close_input()
{
- in_neighbors.clear();
+ in_previous.reset();
}
void DenoiseImage::free()
@@ -677,39 +410,61 @@ bool DenoiseImage::parse_channels(const ImageSpec &in_spec, string &error)
return true;
}
-void DenoiseImage::read_pixels(const DenoiseImageLayer &layer, float *input_pixels)
+void DenoiseImage::read_pixels(const DenoiseImageLayer &layer,
+ const BufferParams &params,
+ float *input_pixels)
{
/* Pixels from center file have already been loaded into pixels.
* We copy a subset into the device input buffer with channels reshuffled. */
const int *input_to_image_channel = layer.input_to_image_channel.data();
for (int i = 0; i < width * height; i++) {
- for (int j = 0; j < INPUT_NUM_CHANNELS; j++) {
- int image_channel = input_to_image_channel[j];
- input_pixels[i * INPUT_NUM_CHANNELS + j] =
+ for (int j = 0; j < 3; ++j) {
+ int offset = params.get_pass_offset(PASS_COMBINED);
+ int image_channel = input_to_image_channel[INPUT_NOISY_IMAGE + j];
+ input_pixels[i * params.pass_stride + offset + j] =
+ pixels[((size_t)i) * num_channels + image_channel];
+ }
+ for (int j = 0; j < 3; ++j) {
+ int offset = params.get_pass_offset(PASS_DENOISING_NORMAL);
+ int image_channel = input_to_image_channel[INPUT_DENOISING_NORMAL + j];
+ input_pixels[i * params.pass_stride + offset + j] =
+ pixels[((size_t)i) * num_channels + image_channel];
+ }
+ for (int j = 0; j < 3; ++j) {
+ int offset = params.get_pass_offset(PASS_DENOISING_ALBEDO);
+ int image_channel = input_to_image_channel[INPUT_DENOISING_ALBEDO + j];
+ input_pixels[i * params.pass_stride + offset + j] =
+ pixels[((size_t)i) * num_channels + image_channel];
+ }
+ for (int j = 0; j < 4; ++j) {
+ int offset = params.get_pass_offset(PASS_MOTION);
+ int image_channel = input_to_image_channel[INPUT_MOTION + j];
+ input_pixels[i * params.pass_stride + offset + j] =
pixels[((size_t)i) * num_channels + image_channel];
}
}
}
-bool DenoiseImage::read_neighbor_pixels(int neighbor,
- const DenoiseImageLayer &layer,
+bool DenoiseImage::read_previous_pixels(const DenoiseImageLayer &layer,
+ const BufferParams &params,
float *input_pixels)
{
/* Load pixels from neighboring frames, and copy them into device buffer
* with channels reshuffled. */
size_t num_pixels = (size_t)width * (size_t)height;
array<float> neighbor_pixels(num_pixels * num_channels);
- if (!in_neighbors[neighbor]->read_image(TypeDesc::FLOAT, neighbor_pixels.data())) {
+ if (!in_previous->read_image(TypeDesc::FLOAT, neighbor_pixels.data())) {
return false;
}
- const int *input_to_image_channel = layer.neighbor_input_to_image_channel[neighbor].data();
+ const int *output_to_image_channel = layer.previous_output_to_image_channel.data();
for (int i = 0; i < width * height; i++) {
- for (int j = 0; j < INPUT_NUM_CHANNELS; j++) {
- int image_channel = input_to_image_channel[j];
- input_pixels[i * INPUT_NUM_CHANNELS + j] =
+ for (int j = 0; j < 3; ++j) {
+ int offset = params.get_pass_offset(PASS_DENOISING_PREVIOUS);
+ int image_channel = output_to_image_channel[j];
+ input_pixels[i * params.pass_stride + offset + j] =
neighbor_pixels[((size_t)i) * num_channels + image_channel];
}
}
@@ -739,8 +494,8 @@ bool DenoiseImage::load(const string &in_filepath, string &error)
return false;
}
- if (layers.size() == 0) {
- error = "Could not find a render layer containing denoising info";
+ if (layers.empty()) {
+ error = "Could not find a render layer containing denoising data and motion vector passes";
return false;
}
@@ -757,46 +512,34 @@ bool DenoiseImage::load(const string &in_filepath, string &error)
return true;
}
-bool DenoiseImage::load_neighbors(const vector<string> &filepaths,
- const vector<int> &frames,
- string &error)
+bool DenoiseImage::load_previous(const string &filepath, string &error)
{
- if (frames.size() > DENOISE_MAX_FRAMES - 1) {
- error = string_printf("Maximum number of neighbors (%d) exceeded\n", DENOISE_MAX_FRAMES - 1);
+ if (!Filesystem::is_regular(filepath)) {
+ error = "Couldn't find neighbor frame: " + filepath;
return false;
}
- for (int neighbor = 0; neighbor < frames.size(); neighbor++) {
- int frame = frames[neighbor];
- const string &filepath = filepaths[frame];
-
- if (!Filesystem::is_regular(filepath)) {
- error = "Couldn't find neighbor frame: " + filepath;
- return false;
- }
+ unique_ptr<ImageInput> in_neighbor(ImageInput::open(filepath));
+ if (!in_neighbor) {
+ error = "Couldn't open neighbor frame: " + filepath;
+ return false;
+ }
- unique_ptr<ImageInput> in_neighbor(ImageInput::open(filepath));
- if (!in_neighbor) {
- error = "Couldn't open neighbor frame: " + filepath;
- return false;
- }
+ const ImageSpec &neighbor_spec = in_neighbor->spec();
+ if (neighbor_spec.width != width || neighbor_spec.height != height) {
+ error = "Neighbor frame has different dimensions: " + filepath;
+ return false;
+ }
- const ImageSpec &neighbor_spec = in_neighbor->spec();
- if (neighbor_spec.width != width || neighbor_spec.height != height) {
- error = "Neighbor frame has different dimensions: " + filepath;
+ for (DenoiseImageLayer &layer : layers) {
+ if (!layer.match_channels(in_spec.channelnames, neighbor_spec.channelnames)) {
+ error = "Neighbor frame misses denoising data passes: " + filepath;
return false;
}
-
- foreach (DenoiseImageLayer &layer, layers) {
- if (!layer.match_channels(neighbor, in_spec.channelnames, neighbor_spec.channelnames)) {
- error = "Neighbor frame misses denoising data passes: " + filepath;
- return false;
- }
- }
-
- in_neighbors.push_back(std::move(in_neighbor));
}
+ in_previous = std::move(in_neighbor);
+
return true;
}
@@ -864,24 +607,22 @@ bool DenoiseImage::save_output(const string &out_filepath, string &error)
/* File pattern handling and outer loop over frames */
-DenoiserPipeline::DenoiserPipeline(DeviceInfo &device_info)
+DenoiserPipeline::DenoiserPipeline(DeviceInfo &device_info, const DenoiseParams &params)
{
- samples_override = 0;
- tile_size = make_int2(64, 64);
-
- num_frames = 0;
-
/* Initialize task scheduler. */
TaskScheduler::init();
/* Initialize device. */
- device = Device::create(device_info, stats, profiler, true);
-
+ device = Device::create(device_info, stats, profiler);
device->load_kernels(KERNEL_FEATURE_DENOISING);
+
+ denoiser = Denoiser::create(device, params);
+ denoiser->load_kernels(nullptr);
}
DenoiserPipeline::~DenoiserPipeline()
{
+ denoiser.reset();
delete device;
TaskScheduler::exit();
}
@@ -890,7 +631,7 @@ bool DenoiserPipeline::run()
{
assert(input.size() == output.size());
- num_frames = output.size();
+ int num_frames = output.size();
for (int frame = 0; frame < num_frames; frame++) {
/* Skip empty output paths. */
@@ -898,16 +639,8 @@ bool DenoiserPipeline::run()
continue;
}
- /* Determine neighbor frame numbers that should be used for filtering. */
- vector<int> neighbor_frames;
- for (int f = frame - params.neighbor_frames; f <= frame + params.neighbor_frames; f++) {
- if (f >= 0 && f < num_frames && f != frame) {
- neighbor_frames.push_back(f);
- }
- }
-
/* Execute task. */
- DenoiseTask task(device, this, frame, neighbor_frames);
+ DenoiseTask task(device, this, frame);
if (!task.load()) {
error = task.error;
return false;
@@ -930,5 +663,3 @@ bool DenoiserPipeline::run()
}
CCL_NAMESPACE_END
-
-#endif
diff --git a/intern/cycles/session/denoising.h b/intern/cycles/session/denoising.h
index 097cc570d06..15e691f73fd 100644
--- a/intern/cycles/session/denoising.h
+++ b/intern/cycles/session/denoising.h
@@ -17,20 +17,17 @@
#ifndef __DENOISING_H__
#define __DENOISING_H__
-#if 0
-
/* TODO(sergey): Make it explicit and clear when something is a denoiser, its pipeline or
* parameters. Currently it is an annoying mixture of terms used interchangeably. */
-# include "device/device.h"
-
-# include "render/buffers.h"
+#include "device/device.h"
+#include "integrator/denoiser.h"
-# include "util/util_string.h"
-# include "util/util_unique_ptr.h"
-# include "util/util_vector.h"
+#include "util/string.h"
+#include "util/unique_ptr.h"
+#include "util/vector.h"
-# include <OpenImageIO/imageio.h>
+#include <OpenImageIO/imageio.h>
OIIO_NAMESPACE_USING
@@ -40,7 +37,7 @@ CCL_NAMESPACE_BEGIN
class DenoiserPipeline {
public:
- DenoiserPipeline(DeviceInfo &device_info);
+ DenoiserPipeline(DeviceInfo &device_info, const DenoiseParams &params);
~DenoiserPipeline();
bool run();
@@ -55,22 +52,13 @@ class DenoiserPipeline {
* taking into account all input frames. */
vector<string> output;
- /* Sample number override, takes precedence over values from input frames. */
- int samples_override;
- /* Tile size for processing on device. */
- int2 tile_size;
-
- /* Equivalent to the settings in the regular denoiser. */
- DenoiseParams params;
-
protected:
friend class DenoiseTask;
Stats stats;
Profiler profiler;
Device *device;
-
- int num_frames;
+ std::unique_ptr<Denoiser> denoiser;
};
/* Denoise Image Layer */
@@ -88,13 +76,13 @@ struct DenoiseImageLayer {
/* Device input channel will be copied from image channel input_to_image_channel[i]. */
vector<int> input_to_image_channel;
- /* input_to_image_channel of the secondary frames, if any are used. */
- vector<vector<int>> neighbor_input_to_image_channel;
-
/* Write i-th channel of the processing output to output_to_image_channel[i]-th channel of the
* file. */
vector<int> output_to_image_channel;
+ /* output_to_image_channel of the previous frame, if used. */
+ vector<int> previous_output_to_image_channel;
+
/* Detect whether this layer contains a full set of channels and set up the offsets accordingly.
*/
bool detect_denoising_channels();
@@ -102,8 +90,7 @@ struct DenoiseImageLayer {
/* Map the channels of a secondary frame to the channels that are required for processing,
* fill neighbor_input_to_image_channel if all are present or return false if a channel are
* missing. */
- bool match_channels(int neighbor,
- const std::vector<string> &channelnames,
+ bool match_channels(const std::vector<string> &channelnames,
const std::vector<string> &neighbor_channelnames);
};
@@ -125,7 +112,7 @@ class DenoiseImage {
/* Image file handles */
ImageSpec in_spec;
- vector<unique_ptr<ImageInput>> in_neighbors;
+ unique_ptr<ImageInput> in_previous;
/* Render layers */
vector<DenoiseImageLayer> layers;
@@ -137,12 +124,16 @@ class DenoiseImage {
bool load(const string &in_filepath, string &error);
/* Load neighboring frames. */
- bool load_neighbors(const vector<string> &filepaths, const vector<int> &frames, string &error);
+ bool load_previous(const string &in_filepath, string &error);
/* Load subset of pixels from file buffer into input buffer, as needed for denoising
* on the device. Channels are reshuffled following the provided mapping. */
- void read_pixels(const DenoiseImageLayer &layer, float *input_pixels);
- bool read_neighbor_pixels(int neighbor, const DenoiseImageLayer &layer, float *input_pixels);
+ void read_pixels(const DenoiseImageLayer &layer,
+ const BufferParams &params,
+ float *input_pixels);
+ bool read_previous_pixels(const DenoiseImageLayer &layer,
+ const BufferParams &params,
+ float *input_pixels);
bool save_output(const string &out_filepath, string &error);
@@ -159,10 +150,7 @@ class DenoiseImage {
class DenoiseTask {
public:
- DenoiseTask(Device *device,
- DenoiserPipeline *denoiser,
- int frame,
- const vector<int> &neighbor_frames);
+ DenoiseTask(Device *device, DenoiserPipeline *denoiser, int frame);
~DenoiseTask();
/* Task stages */
@@ -180,37 +168,17 @@ class DenoiseTask {
/* Frame number to be denoised */
int frame;
- vector<int> neighbor_frames;
/* Image file data */
DenoiseImage image;
int current_layer;
- /* Device input buffer */
- device_vector<float> input_pixels;
-
- /* Tiles */
- thread_mutex tiles_mutex;
- list<RenderTile> tiles;
- int num_tiles;
-
- thread_mutex output_mutex;
- map<int, device_vector<float> *> output_pixels;
+ RenderBuffers buffers;
/* Task handling */
bool load_input_pixels(int layer);
- void create_task(DeviceTask &task);
-
- /* Device task callbacks */
- bool acquire_tile(Device *device, Device *tile_device, RenderTile &tile);
- void map_neighboring_tiles(RenderTileNeighbors &neighbors, Device *tile_device);
- void unmap_neighboring_tiles(RenderTileNeighbors &neighbors);
- void release_tile();
- bool get_cancel();
};
CCL_NAMESPACE_END
-#endif
-
#endif /* __DENOISING_H__ */
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index 69d0eea838c..a3eb116780f 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -41,8 +41,8 @@ class GHOST_Window : public GHOST_IWindow {
* Constructor.
* Creates a new window and opens it.
* To check if the window was created properly, use the getValid() method.
- * \param width: The width the window.
- * \param height: The height the window.
+ * \param width: The width of the window.
+ * \param height: The height of the window.
* \param state: The state the window is initially opened with.
* \param wantStereoVisual: Stereo visual for quad buffered stereo.
* \param exclusive: Use to show the window ontop and ignore others (used full-screen).
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index 3c006b9a70c..8a20323dcfc 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -259,6 +259,50 @@ void MEM_use_guarded_allocator(void);
#endif /* __cplusplus */
#ifdef __cplusplus
+
+# include <new>
+# include <type_traits>
+# include <utility>
+
+/**
+ * Allocate new memory for and constructs an object of type #T.
+ * #MEM_delete should be used to delete the object. Just calling #MEM_freeN is not enough when #T
+ * is not a trivial type.
+ */
+template<typename T, typename... Args>
+inline T *MEM_new(const char *allocation_name, Args &&...args)
+{
+ void *buffer = MEM_mallocN(sizeof(T), allocation_name);
+ return new (buffer) T(std::forward<Args>(args)...);
+}
+
+/**
+ * Allocates zero-initialized memory for an object of type #T. The constructor of #T is not called,
+ * therefor this should only used with trivial types (like all C types).
+ * It's valid to call #MEM_freeN on a pointer returned by this, because a destructor call is not
+ * necessary, because the type is trivial.
+ */
+template<typename T> inline T *MEM_cnew(const char *allocation_name)
+{
+ static_assert(std::is_trivial_v<T>, "For non-trivial types, MEM_new should be used.");
+ return static_cast<T *>(MEM_callocN(sizeof(T), allocation_name));
+}
+
+/**
+ * Destructs and deallocates an object previously allocated with any `MEM_*` function.
+ * Passing in null does nothing.
+ */
+template<typename T> inline void MEM_delete(const T *ptr)
+{
+ if (ptr == nullptr) {
+ /* Support #ptr being null, because C++ `delete` supports that as well. */
+ return;
+ }
+ /* C++ allows destruction of const objects, so the pointer is allowed to be const. */
+ ptr->~T();
+ MEM_freeN(const_cast<T *>(ptr));
+}
+
/* Allocation functions (for C++ only). */
# define MEM_CXX_CLASS_ALLOC_FUNCS(_id) \
public: \
@@ -292,36 +336,6 @@ void MEM_use_guarded_allocator(void);
{ \
}
-/* Needed when type includes a namespace, then the namespace should not be
- * specified after ~, so using a macro fails. */
-template<class T> inline void OBJECT_GUARDED_DESTRUCTOR(T *what)
-{
- what->~T();
-}
-
-# if defined __GNUC__
-# define OBJECT_GUARDED_NEW(type, args...) new (MEM_mallocN(sizeof(type), __func__)) type(args)
-# else
-# define OBJECT_GUARDED_NEW(type, ...) \
- new (MEM_mallocN(sizeof(type), __FUNCTION__)) type(__VA_ARGS__)
-# endif
-# define OBJECT_GUARDED_DELETE(what, type) \
- { \
- if (what) { \
- OBJECT_GUARDED_DESTRUCTOR((type *)what); \
- MEM_freeN(what); \
- } \
- } \
- (void)0
-# define OBJECT_GUARDED_SAFE_DELETE(what, type) \
- { \
- if (what) { \
- OBJECT_GUARDED_DESTRUCTOR((type *)what); \
- MEM_freeN(what); \
- what = NULL; \
- } \
- } \
- (void)0
#endif /* __cplusplus */
#endif /* __MEM_GUARDEDALLOC_H__ */
diff --git a/intern/iksolver/intern/IK_QJacobian.cpp b/intern/iksolver/intern/IK_QJacobian.cpp
index 19d711f3fe1..7e4d48e37c9 100644
--- a/intern/iksolver/intern/IK_QJacobian.cpp
+++ b/intern/iksolver/intern/IK_QJacobian.cpp
@@ -196,12 +196,12 @@ void IK_QJacobian::InvertSDLS()
// Compute the dampeds least squeares pseudo inverse of J.
//
// Since J is usually not invertible (most of the times it's not even
- // square), the psuedo inverse is used. This gives us a least squares
+ // square), the pseudo inverse is used. This gives us a least squares
// solution.
//
// This is fine when the J*Jt is of full rank. When J*Jt is near to
// singular the least squares inverse tries to minimize |J(dtheta) - dX)|
- // and doesn't try to minimize dTheta. This results in eratic changes in
+ // and doesn't try to minimize dTheta. This results in erratic changes in
// angle. The damped least squares minimizes |dtheta| to try and reduce this
// erratic behavior.
//
@@ -323,7 +323,7 @@ void IK_QJacobian::InvertDLS()
// least squares solution. This is fine when the m_jjt is
// of full rank. When m_jjt is near to singular the least squares
// inverse tries to minimize |J(dtheta) - dX)| and doesn't
- // try to minimize dTheta. This results in eratic changes in angle.
+ // try to minimize dTheta. This results in erratic changes in angle.
// Damped least squares minimizes |dtheta| to try and reduce this
// erratic behavior.
diff --git a/intern/libmv/intern/utildefines.h b/intern/libmv/intern/utildefines.h
index 052052a1d76..8b37253698d 100644
--- a/intern/libmv/intern/utildefines.h
+++ b/intern/libmv/intern/utildefines.h
@@ -27,9 +27,21 @@
#ifdef WITH_LIBMV_GUARDED_ALLOC
# include "MEM_guardedalloc.h"
-# define LIBMV_OBJECT_NEW OBJECT_GUARDED_NEW
-# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE
-# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE
+# if defined __GNUC__
+# define LIBMV_OBJECT_NEW(type, args...) \
+ new (MEM_mallocN(sizeof(type), __func__)) type(args)
+# else
+# define LIBMV_OBJECT_NEW(type, ...) \
+ new (MEM_mallocN(sizeof(type), __FUNCTION__)) type(__VA_ARGS__)
+# endif
+# define LIBMV_OBJECT_DELETE(what, type) \
+ { \
+ if (what) { \
+ ((type*)what)->~type(); \
+ MEM_freeN(what); \
+ } \
+ } \
+ (void)0
# define LIBMV_STRUCT_NEW(type, count) \
(type*)MEM_mallocN(sizeof(type) * count, __func__)
# define LIBMV_STRUCT_DELETE(what) MEM_freeN(what)
diff --git a/intern/libmv/libmv/autotrack/autotrack.cc b/intern/libmv/libmv/autotrack/autotrack.cc
index afdf48912e5..a407639ecfa 100644
--- a/intern/libmv/libmv/autotrack/autotrack.cc
+++ b/intern/libmv/libmv/autotrack/autotrack.cc
@@ -178,7 +178,7 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker,
return false;
}
- // Store original position befoer tracking, so we can claculate offset later.
+ // Store original position before tracking, so we can claculate offset later.
Vec2f original_center = tracked_marker->center;
// Do the tracking!
diff --git a/intern/libmv/libmv/build/build_config.h b/intern/libmv/libmv/build/build_config.h
index 7029a36a7dd..1d87660f87c 100644
--- a/intern/libmv/libmv/build/build_config.h
+++ b/intern/libmv/libmv/build/build_config.h
@@ -239,7 +239,7 @@
// Check what is the latest C++ specification the compiler supports.
//
// NOTE: Use explicit definition here to avoid expansion-to-defined warning from
-// being geenrated. While this will most likely a false-positive warning in this
+// being generated. While this will most likely a false-positive warning in this
// particular case, that warning might be helpful to catch errors elsewhere.
// C++11 check.
diff --git a/intern/libmv/libmv/image/tuple.h b/intern/libmv/libmv/image/tuple.h
index 447bf0cc81c..3f4b58886e4 100644
--- a/intern/libmv/libmv/image/tuple.h
+++ b/intern/libmv/libmv/image/tuple.h
@@ -25,7 +25,7 @@
namespace libmv {
-// A vector of elements with fixed lenght and deep copy semantics.
+// A vector of elements with fixed length and deep copy semantics.
template <typename T, int N>
class Tuple {
public:
diff --git a/intern/libmv/libmv/multiview/panography.h b/intern/libmv/libmv/multiview/panography.h
index 5860a34d1fd..6b87f25bdda 100644
--- a/intern/libmv/libmv/multiview/panography.h
+++ b/intern/libmv/libmv/multiview/panography.h
@@ -38,7 +38,7 @@ namespace libmv {
// The 2-point algorithm solves for the rotation of the camera with a single
// focal length (4 degrees of freedom).
//
-// Compute from 1 to 3 possible focal lenght for 2 point correspondences.
+// Compute from 1 to 3 possible focal length for 2 point correspondences.
// Suppose that the cameras share the same optical center and focal lengths:
//
// Image 1 => H*x = x' => Image 2
diff --git a/intern/libmv/libmv/numeric/numeric.h b/intern/libmv/libmv/numeric/numeric.h
index e3ebdb5a4bb..52f3b8d6a78 100644
--- a/intern/libmv/libmv/numeric/numeric.h
+++ b/intern/libmv/libmv/numeric/numeric.h
@@ -261,7 +261,7 @@ Mat3 RotationRodrigues(const Vec3& axis);
// positive z-axis, and y is oriented close to up.
Mat3 LookAt(Vec3 center);
-// Return a diagonal matrix from a vector containg the diagonal values.
+// Return a diagonal matrix from a vector containing the diagonal values.
template <typename TVec>
inline Mat Diag(const TVec& x) {
return x.asDiagonal();
diff --git a/intern/libmv/libmv/numeric/poly.h b/intern/libmv/libmv/numeric/poly.h
index a3d3801a399..c1deee42bf9 100644
--- a/intern/libmv/libmv/numeric/poly.h
+++ b/intern/libmv/libmv/numeric/poly.h
@@ -50,7 +50,7 @@ int SolveCubicPolynomial(Real a, Real b, Real c, Real* x0, Real* x1, Real* x2) {
Real CQ3 = 2916 * q * q * q;
if (R == 0 && Q == 0) {
- // Tripple root in one place.
+ // Triple root in one place.
*x0 = *x1 = *x2 = -a / 3;
return 3;
diff --git a/intern/memutil/MEM_RefCounted.h b/intern/memutil/MEM_RefCounted.h
index 319effdebaf..71be4b62f12 100644
--- a/intern/memutil/MEM_RefCounted.h
+++ b/intern/memutil/MEM_RefCounted.h
@@ -41,7 +41,7 @@
class MEM_RefCounted {
public:
/**
- * Constructs a a shared object.
+ * Constructs a shared object.
*/
MEM_RefCounted() : m_refCount(1)
{
diff --git a/intern/numaapi/source/build_config.h b/intern/numaapi/source/build_config.h
index e7c332483b5..58c07ac85ab 100644
--- a/intern/numaapi/source/build_config.h
+++ b/intern/numaapi/source/build_config.h
@@ -234,7 +234,7 @@
// Check what is the latest C++ specification the compiler supports.
//
// NOTE: Use explicit definition here to avoid expansion-to-defined warning from
-// being geenrated. While this will most likely a false-positive warning in this
+// being generated. While this will most likely a false-positive warning in this
// particular case, that warning might be helpful to catch errors elsewhere.
// C++11 check.
diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc
index 42a2b5bf3b6..9402a12a71a 100644
--- a/intern/opencolorio/fallback_impl.cc
+++ b/intern/opencolorio/fallback_impl.cc
@@ -485,8 +485,8 @@ OCIO_PackedImageDesc *FallbackImpl::createOCIO_PackedImageDesc(float *data,
long xStrideBytes,
long yStrideBytes)
{
- OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription *)MEM_callocN(
- sizeof(OCIO_PackedImageDescription), "OCIO_PackedImageDescription");
+ OCIO_PackedImageDescription *desc = MEM_cnew<OCIO_PackedImageDescription>(
+ "OCIO_PackedImageDescription");
desc->data = data;
desc->width = width;
desc->height = height;
diff --git a/intern/opencolorio/gpu_shader_display_transform.glsl b/intern/opencolorio/gpu_shader_display_transform.glsl
index d94ff9230e8..f5a7a7bf45d 100644
--- a/intern/opencolorio/gpu_shader_display_transform.glsl
+++ b/intern/opencolorio/gpu_shader_display_transform.glsl
@@ -119,7 +119,7 @@ vec4 curvemapping_evaluate_premulRGBF(vec4 col)
/* Using a triangle distribution which gives a more final uniform noise.
* See Banding in Games:A Noisy Rant(revision 5) Mikkel Gjøl, Playdead (slide 27) */
-/* GPUs are rounding before writting to framebuffer so we center the distribution around 0.0. */
+/* GPUs are rounding before writing to framebuffer so we center the distribution around 0.0. */
/* Return triangle noise in [-1..1[ range */
float dither_random_value(vec2 co)
{
diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc
index 058b8f51dd6..b4e48c013c0 100644
--- a/intern/opencolorio/ocio_impl.cc
+++ b/intern/opencolorio/ocio_impl.cc
@@ -67,7 +67,7 @@ static void OCIO_reportException(Exception &exception)
OCIO_ConstConfigRcPtr *OCIOImpl::getCurrentConfig(void)
{
- ConstConfigRcPtr *config = OBJECT_GUARDED_NEW(ConstConfigRcPtr);
+ ConstConfigRcPtr *config = MEM_new<ConstConfigRcPtr>(__func__);
try {
*config = GetCurrentConfig();
@@ -79,7 +79,7 @@ OCIO_ConstConfigRcPtr *OCIOImpl::getCurrentConfig(void)
OCIO_reportException(exception);
}
- OBJECT_GUARDED_DELETE(config, ConstConfigRcPtr);
+ MEM_delete(config);
return NULL;
}
@@ -96,7 +96,7 @@ void OCIOImpl::setCurrentConfig(const OCIO_ConstConfigRcPtr *config)
OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromEnv(void)
{
- ConstConfigRcPtr *config = OBJECT_GUARDED_NEW(ConstConfigRcPtr);
+ ConstConfigRcPtr *config = MEM_new<ConstConfigRcPtr>(__func__);
try {
*config = Config::CreateFromEnv();
@@ -108,14 +108,14 @@ OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromEnv(void)
OCIO_reportException(exception);
}
- OBJECT_GUARDED_DELETE(config, ConstConfigRcPtr);
+ MEM_delete(config);
return NULL;
}
OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromFile(const char *filename)
{
- ConstConfigRcPtr *config = OBJECT_GUARDED_NEW(ConstConfigRcPtr);
+ ConstConfigRcPtr *config = MEM_new<ConstConfigRcPtr>(__func__);
try {
*config = Config::CreateFromFile(filename);
@@ -127,14 +127,14 @@ OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromFile(const char *filename)
OCIO_reportException(exception);
}
- OBJECT_GUARDED_DELETE(config, ConstConfigRcPtr);
+ MEM_delete(config);
return NULL;
}
void OCIOImpl::configRelease(OCIO_ConstConfigRcPtr *config)
{
- OBJECT_GUARDED_DELETE((ConstConfigRcPtr *)config, ConstConfigRcPtr);
+ MEM_delete((ConstConfigRcPtr *)config);
}
int OCIOImpl::configGetNumColorSpaces(OCIO_ConstConfigRcPtr *config)
@@ -164,7 +164,7 @@ const char *OCIOImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *conf
OCIO_ConstColorSpaceRcPtr *OCIOImpl::configGetColorSpace(OCIO_ConstConfigRcPtr *config,
const char *name)
{
- ConstColorSpaceRcPtr *cs = OBJECT_GUARDED_NEW(ConstColorSpaceRcPtr);
+ ConstColorSpaceRcPtr *cs = MEM_new<ConstColorSpaceRcPtr>(__func__);
try {
*cs = (*(ConstConfigRcPtr *)config)->getColorSpace(name);
@@ -176,7 +176,7 @@ OCIO_ConstColorSpaceRcPtr *OCIOImpl::configGetColorSpace(OCIO_ConstConfigRcPtr *
OCIO_reportException(exception);
}
- OBJECT_GUARDED_DELETE(cs, ConstColorSpaceRcPtr);
+ MEM_delete(cs);
return NULL;
}
@@ -380,7 +380,7 @@ const char *OCIOImpl::configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, in
OCIO_ConstLookRcPtr *OCIOImpl::configGetLook(OCIO_ConstConfigRcPtr *config, const char *name)
{
- ConstLookRcPtr *look = OBJECT_GUARDED_NEW(ConstLookRcPtr);
+ ConstLookRcPtr *look = MEM_new<ConstLookRcPtr>(__func__);
try {
*look = (*(ConstConfigRcPtr *)config)->getLook(name);
@@ -392,7 +392,7 @@ OCIO_ConstLookRcPtr *OCIOImpl::configGetLook(OCIO_ConstConfigRcPtr *config, cons
OCIO_reportException(exception);
}
- OBJECT_GUARDED_DELETE(look, ConstLookRcPtr);
+ MEM_delete(look);
return NULL;
}
@@ -404,7 +404,7 @@ const char *OCIOImpl::lookGetProcessSpace(OCIO_ConstLookRcPtr *look)
void OCIOImpl::lookRelease(OCIO_ConstLookRcPtr *look)
{
- OBJECT_GUARDED_DELETE((ConstLookRcPtr *)look, ConstLookRcPtr);
+ MEM_delete((ConstLookRcPtr *)look);
}
int OCIOImpl::colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs_)
@@ -521,14 +521,14 @@ void OCIOImpl::colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config_,
void OCIOImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs)
{
- OBJECT_GUARDED_DELETE((ConstColorSpaceRcPtr *)cs, ConstColorSpaceRcPtr);
+ MEM_delete((ConstColorSpaceRcPtr *)cs);
}
OCIO_ConstProcessorRcPtr *OCIOImpl::configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config,
const char *srcName,
const char *dstName)
{
- ConstProcessorRcPtr *processor = OBJECT_GUARDED_NEW(ConstProcessorRcPtr);
+ ConstProcessorRcPtr *processor = MEM_new<ConstProcessorRcPtr>(__func__);
try {
*processor = (*(ConstConfigRcPtr *)config)->getProcessor(srcName, dstName);
@@ -540,20 +540,20 @@ OCIO_ConstProcessorRcPtr *OCIOImpl::configGetProcessorWithNames(OCIO_ConstConfig
OCIO_reportException(exception);
}
- OBJECT_GUARDED_DELETE(processor, ConstProcessorRcPtr);
+ MEM_delete(processor);
return 0;
}
void OCIOImpl::processorRelease(OCIO_ConstProcessorRcPtr *processor)
{
- OBJECT_GUARDED_DELETE(processor, ConstProcessorRcPtr);
+ MEM_delete(processor);
}
OCIO_ConstCPUProcessorRcPtr *OCIOImpl::processorGetCPUProcessor(
OCIO_ConstProcessorRcPtr *processor)
{
- ConstCPUProcessorRcPtr *cpu_processor = OBJECT_GUARDED_NEW(ConstCPUProcessorRcPtr);
+ ConstCPUProcessorRcPtr *cpu_processor = MEM_new<ConstCPUProcessorRcPtr>(__func__);
*cpu_processor = (*(ConstProcessorRcPtr *)processor)->getDefaultCPUProcessor();
return (OCIO_ConstCPUProcessorRcPtr *)cpu_processor;
}
@@ -636,7 +636,7 @@ void OCIOImpl::cpuProcessorApplyRGBA_predivide(OCIO_ConstCPUProcessorRcPtr *cpu_
void OCIOImpl::cpuProcessorRelease(OCIO_ConstCPUProcessorRcPtr *cpu_processor)
{
- OBJECT_GUARDED_DELETE(cpu_processor, ConstCPUProcessorRcPtr);
+ MEM_delete(cpu_processor);
}
const char *OCIOImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs)
@@ -725,7 +725,7 @@ OCIO_ConstProcessorRcPtr *OCIOImpl::createDisplayProcessor(OCIO_ConstConfigRcPtr
/* Create processor from transform. This is the moment were OCIO validates
* the entire transform, no need to check for the validity of inputs above. */
- ConstProcessorRcPtr *p = OBJECT_GUARDED_NEW(ConstProcessorRcPtr);
+ ConstProcessorRcPtr *p = MEM_new<ConstProcessorRcPtr>(__func__);
try {
*p = config->getProcessor(group);
@@ -737,7 +737,7 @@ OCIO_ConstProcessorRcPtr *OCIOImpl::createDisplayProcessor(OCIO_ConstConfigRcPtr
OCIO_reportException(exception);
}
- OBJECT_GUARDED_DELETE(p, ConstProcessorRcPtr);
+ MEM_delete(p);
return NULL;
}
@@ -771,7 +771,7 @@ OCIO_PackedImageDesc *OCIOImpl::createOCIO_PackedImageDesc(float *data,
void OCIOImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id)
{
- OBJECT_GUARDED_DELETE((PackedImageDesc *)id, PackedImageDesc);
+ MEM_delete((PackedImageDesc *)id);
}
const char *OCIOImpl::getVersionString(void)
diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt
index bce8a8baa84..f141689791f 100644
--- a/intern/opensubdiv/CMakeLists.txt
+++ b/intern/opensubdiv/CMakeLists.txt
@@ -72,9 +72,20 @@ if(WITH_OPENSUBDIV)
internal/device/device_context_openmp.h
# Evaluator.
+ internal/evaluator/eval_output.cc
+ internal/evaluator/eval_output.h
+ internal/evaluator/eval_output_cpu.cc
+ internal/evaluator/eval_output_cpu.h
+ internal/evaluator/eval_output_gpu.cc
+ internal/evaluator/eval_output_gpu.h
+ internal/evaluator/evaluator_cache_impl.cc
+ internal/evaluator/evaluator_cache_impl.h
internal/evaluator/evaluator_capi.cc
internal/evaluator/evaluator_impl.cc
internal/evaluator/evaluator_impl.h
+ internal/evaluator/patch_map.cc
+ internal/evaluator/patch_map.h
+
# Topology.
internal/topology/mesh_topology.cc
diff --git a/intern/opensubdiv/internal/evaluator/eval_output.cc b/intern/opensubdiv/internal/evaluator/eval_output.cc
new file mode 100644
index 00000000000..58f835ab2e0
--- /dev/null
+++ b/intern/opensubdiv/internal/evaluator/eval_output.cc
@@ -0,0 +1,35 @@
+// Copyright 2021 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#include "internal/evaluator/eval_output.h"
+
+namespace blender {
+namespace opensubdiv {
+
+bool is_adaptive(CpuPatchTable *patch_table)
+{
+ return patch_table->GetPatchArrayBuffer()[0].GetDescriptor().IsAdaptive();
+}
+
+bool is_adaptive(GLPatchTable *patch_table)
+{
+ return patch_table->GetPatchArrays()[0].GetDescriptor().IsAdaptive();
+}
+
+} // namespace opensubdiv
+} // namespace blender
diff --git a/intern/opensubdiv/internal/evaluator/eval_output.h b/intern/opensubdiv/internal/evaluator/eval_output.h
new file mode 100644
index 00000000000..a55b89001a4
--- /dev/null
+++ b/intern/opensubdiv/internal/evaluator/eval_output.h
@@ -0,0 +1,582 @@
+// Copyright 2021 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_EVAL_OUTPUT_H_
+#define OPENSUBDIV_EVAL_OUTPUT_H_
+
+#include <opensubdiv/osd/cpuPatchTable.h>
+#include <opensubdiv/osd/glPatchTable.h>
+#include <opensubdiv/osd/mesh.h>
+#include <opensubdiv/osd/types.h>
+
+#include "internal/base/type.h"
+#include "internal/evaluator/evaluator_impl.h"
+
+using OpenSubdiv::Far::PatchTable;
+using OpenSubdiv::Far::StencilTable;
+using OpenSubdiv::Osd::BufferDescriptor;
+using OpenSubdiv::Osd::CpuPatchTable;
+using OpenSubdiv::Osd::GLPatchTable;
+using OpenSubdiv::Osd::PatchCoord;
+
+namespace blender {
+namespace opensubdiv {
+
+// Base class for the implementation of the evaluators.
+class EvalOutputAPI::EvalOutput {
+ public:
+ virtual ~EvalOutput() = default;
+
+ virtual void updateData(const float *src, int start_vertex, int num_vertices) = 0;
+
+ virtual void updateVaryingData(const float *src, int start_vertex, int num_vertices) = 0;
+
+ virtual void updateFaceVaryingData(const int face_varying_channel,
+ const float *src,
+ int start_vertex,
+ int num_vertices) = 0;
+
+ virtual void refine() = 0;
+
+ // NOTE: P must point to a memory of at least float[3]*num_patch_coords.
+ virtual void evalPatches(const PatchCoord *patch_coord,
+ const int num_patch_coords,
+ float *P) = 0;
+
+ // NOTE: P, dPdu, dPdv must point to a memory of at least float[3]*num_patch_coords.
+ virtual void evalPatchesWithDerivatives(const PatchCoord *patch_coord,
+ const int num_patch_coords,
+ float *P,
+ float *dPdu,
+ float *dPdv) = 0;
+
+ // NOTE: varying must point to a memory of at least float[3]*num_patch_coords.
+ virtual void evalPatchesVarying(const PatchCoord *patch_coord,
+ const int num_patch_coords,
+ float *varying) = 0;
+
+ virtual void evalPatchesFaceVarying(const int face_varying_channel,
+ const PatchCoord *patch_coord,
+ const int num_patch_coords,
+ float face_varying[2]) = 0;
+
+ // The following interfaces are dependant on the actual evaluator type (CPU, OpenGL, etc.) which
+ // have slightly different APIs to access patch arrays, as well as different types for their
+ // data structure. They need to be overridden in the specific instances of the EvalOutput derived
+ // classes if needed, while the interfaces above are overriden through VolatileEvalOutput.
+
+ virtual void fillPatchArraysBuffer(OpenSubdiv_Buffer * /*patch_arrays_buffer*/)
+ {
+ }
+
+ virtual void wrapPatchIndexBuffer(OpenSubdiv_Buffer * /*patch_index_buffer*/)
+ {
+ }
+
+ virtual void wrapPatchParamBuffer(OpenSubdiv_Buffer * /*patch_param_buffer*/)
+ {
+ }
+
+ virtual void wrapSrcBuffer(OpenSubdiv_Buffer * /*src_buffer*/)
+ {
+ }
+
+ virtual void fillFVarPatchArraysBuffer(const int /*face_varying_channel*/,
+ OpenSubdiv_Buffer * /*patch_arrays_buffer*/)
+ {
+ }
+
+ virtual void wrapFVarPatchIndexBuffer(const int /*face_varying_channel*/,
+ OpenSubdiv_Buffer * /*patch_index_buffer*/)
+ {
+ }
+
+ virtual void wrapFVarPatchParamBuffer(const int /*face_varying_channel*/,
+ OpenSubdiv_Buffer * /*patch_param_buffer*/)
+ {
+ }
+
+ virtual void wrapFVarSrcBuffer(const int /*face_varying_channel*/,
+ OpenSubdiv_Buffer * /*src_buffer*/)
+ {
+ }
+};
+
+namespace {
+
+// Buffer which implements API required by OpenSubdiv and uses an existing memory as an underlying
+// storage.
+template<typename T> class RawDataWrapperBuffer {
+ public:
+ RawDataWrapperBuffer(T *data) : data_(data)
+ {
+ }
+
+ T *BindCpuBuffer()
+ {
+ return data_;
+ }
+
+ int BindVBO()
+ {
+ return 0;
+ }
+
+ // TODO(sergey): Support UpdateData().
+
+ protected:
+ T *data_;
+};
+
+template<typename T> class RawDataWrapperVertexBuffer : public RawDataWrapperBuffer<T> {
+ public:
+ RawDataWrapperVertexBuffer(T *data, int num_vertices)
+ : RawDataWrapperBuffer<T>(data), num_vertices_(num_vertices)
+ {
+ }
+
+ int GetNumVertices()
+ {
+ return num_vertices_;
+ }
+
+ protected:
+ int num_vertices_;
+};
+
+class ConstPatchCoordWrapperBuffer : public RawDataWrapperVertexBuffer<const PatchCoord> {
+ public:
+ ConstPatchCoordWrapperBuffer(const PatchCoord *data, int num_vertices)
+ : RawDataWrapperVertexBuffer(data, num_vertices)
+ {
+ }
+};
+} // namespace
+
+// Discriminators used in FaceVaryingVolatileEval in order to detect whether we are using adaptive
+// patches as the CPU and OpenGL PatchTable have different APIs.
+bool is_adaptive(CpuPatchTable *patch_table);
+bool is_adaptive(GLPatchTable *patch_table);
+
+template<typename EVAL_VERTEX_BUFFER,
+ typename STENCIL_TABLE,
+ typename PATCH_TABLE,
+ typename EVALUATOR,
+ typename DEVICE_CONTEXT = void>
+class FaceVaryingVolatileEval {
+ public:
+ typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache;
+
+ FaceVaryingVolatileEval(int face_varying_channel,
+ const StencilTable *face_varying_stencils,
+ int face_varying_width,
+ PATCH_TABLE *patch_table,
+ EvaluatorCache *evaluator_cache = NULL,
+ DEVICE_CONTEXT *device_context = NULL)
+ : face_varying_channel_(face_varying_channel),
+ src_face_varying_desc_(0, face_varying_width, face_varying_width),
+ patch_table_(patch_table),
+ evaluator_cache_(evaluator_cache),
+ device_context_(device_context)
+ {
+ using OpenSubdiv::Osd::convertToCompatibleStencilTable;
+ num_coarse_face_varying_vertices_ = face_varying_stencils->GetNumControlVertices();
+ const int num_total_face_varying_vertices = face_varying_stencils->GetNumControlVertices() +
+ face_varying_stencils->GetNumStencils();
+ src_face_varying_data_ = EVAL_VERTEX_BUFFER::Create(
+ 2, num_total_face_varying_vertices, device_context);
+ face_varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(face_varying_stencils,
+ device_context_);
+ }
+
+ ~FaceVaryingVolatileEval()
+ {
+ delete src_face_varying_data_;
+ delete face_varying_stencils_;
+ }
+
+ void updateData(const float *src, int start_vertex, int num_vertices)
+ {
+ src_face_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_);
+ }
+
+ void refine()
+ {
+ BufferDescriptor dst_face_varying_desc = src_face_varying_desc_;
+ dst_face_varying_desc.offset += num_coarse_face_varying_vertices_ *
+ src_face_varying_desc_.stride;
+ const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
+ evaluator_cache_, src_face_varying_desc_, dst_face_varying_desc, device_context_);
+ // in and out points to same buffer so output is put directly after coarse vertices, needed in
+ // adaptive mode
+ EVALUATOR::EvalStencils(src_face_varying_data_,
+ src_face_varying_desc_,
+ src_face_varying_data_,
+ dst_face_varying_desc,
+ face_varying_stencils_,
+ eval_instance,
+ device_context_);
+ }
+
+ // NOTE: face_varying must point to a memory of at least float[2]*num_patch_coords.
+ void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *face_varying)
+ {
+ RawDataWrapperBuffer<float> face_varying_data(face_varying);
+ BufferDescriptor face_varying_desc(0, 2, 2);
+ ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
+ const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
+ evaluator_cache_, src_face_varying_desc_, face_varying_desc, device_context_);
+
+ BufferDescriptor src_desc = get_src_varying_desc();
+
+ EVALUATOR::EvalPatchesFaceVarying(src_face_varying_data_,
+ src_desc,
+ &face_varying_data,
+ face_varying_desc,
+ patch_coord_buffer.GetNumVertices(),
+ &patch_coord_buffer,
+ patch_table_,
+ face_varying_channel_,
+ eval_instance,
+ device_context_);
+ }
+
+ EVAL_VERTEX_BUFFER *getSrcBuffer() const
+ {
+ return src_face_varying_data_;
+ }
+
+ int getFVarSrcBufferOffset() const
+ {
+ BufferDescriptor src_desc = get_src_varying_desc();
+ return src_desc.offset;
+ }
+
+ PATCH_TABLE *getPatchTable() const
+ {
+ return patch_table_;
+ }
+
+ private:
+ BufferDescriptor get_src_varying_desc() const
+ {
+ // src_face_varying_data_ always contains coarse vertices at the beginning.
+ // In adaptive mode they are followed by number of blocks for intermediate
+ // subdivision levels, and this is what OSD expects in this mode.
+ // In non-adaptive mode (generateIntermediateLevels == false),
+ // they are followed by max subdivision level, but they break interpolation as OSD
+ // expects only one subd level in this buffer.
+ // So in non-adaptive mode we put offset into buffer descriptor to skip over coarse vertices.
+ BufferDescriptor src_desc = src_face_varying_desc_;
+ if (!is_adaptive(patch_table_)) {
+ src_desc.offset += num_coarse_face_varying_vertices_ * src_face_varying_desc_.stride;
+ }
+ return src_desc;
+ }
+
+ protected:
+ int face_varying_channel_;
+
+ BufferDescriptor src_face_varying_desc_;
+
+ int num_coarse_face_varying_vertices_;
+ EVAL_VERTEX_BUFFER *src_face_varying_data_;
+ const STENCIL_TABLE *face_varying_stencils_;
+
+ // NOTE: We reference this, do not own it.
+ PATCH_TABLE *patch_table_;
+
+ EvaluatorCache *evaluator_cache_;
+ DEVICE_CONTEXT *device_context_;
+};
+
+// Volatile evaluator which can be used from threads.
+//
+// TODO(sergey): Make it possible to evaluate coordinates in chunks.
+// TODO(sergey): Make it possible to evaluate multiple face varying layers.
+// (or maybe, it's cheap to create new evaluator for existing
+// topology to evaluate all needed face varying layers?)
+template<typename SRC_VERTEX_BUFFER,
+ typename EVAL_VERTEX_BUFFER,
+ typename STENCIL_TABLE,
+ typename PATCH_TABLE,
+ typename EVALUATOR,
+ typename DEVICE_CONTEXT = void>
+class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
+ public:
+ typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache;
+ typedef FaceVaryingVolatileEval<EVAL_VERTEX_BUFFER,
+ STENCIL_TABLE,
+ PATCH_TABLE,
+ EVALUATOR,
+ DEVICE_CONTEXT>
+ FaceVaryingEval;
+
+ VolatileEvalOutput(const StencilTable *vertex_stencils,
+ const StencilTable *varying_stencils,
+ const vector<const StencilTable *> &all_face_varying_stencils,
+ const int face_varying_width,
+ const PatchTable *patch_table,
+ EvaluatorCache *evaluator_cache = NULL,
+ DEVICE_CONTEXT *device_context = NULL)
+ : src_desc_(0, 3, 3),
+ src_varying_desc_(0, 3, 3),
+ face_varying_width_(face_varying_width),
+ evaluator_cache_(evaluator_cache),
+ device_context_(device_context)
+ {
+ // Total number of vertices = coarse points + refined points + local points.
+ int num_total_vertices = vertex_stencils->GetNumControlVertices() +
+ vertex_stencils->GetNumStencils();
+ num_coarse_vertices_ = vertex_stencils->GetNumControlVertices();
+ using OpenSubdiv::Osd::convertToCompatibleStencilTable;
+ src_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_);
+ src_varying_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_);
+ patch_table_ = PATCH_TABLE::Create(patch_table, device_context_);
+ vertex_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(vertex_stencils,
+ device_context_);
+ varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(varying_stencils,
+ device_context_);
+ // Create evaluators for every face varying channel.
+ face_varying_evaluators.reserve(all_face_varying_stencils.size());
+ int face_varying_channel = 0;
+ for (const StencilTable *face_varying_stencils : all_face_varying_stencils) {
+ face_varying_evaluators.push_back(new FaceVaryingEval(face_varying_channel,
+ face_varying_stencils,
+ face_varying_width,
+ patch_table_,
+ evaluator_cache_,
+ device_context_));
+ ++face_varying_channel;
+ }
+ }
+
+ ~VolatileEvalOutput() override
+ {
+ delete src_data_;
+ delete src_varying_data_;
+ delete patch_table_;
+ delete vertex_stencils_;
+ delete varying_stencils_;
+ for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators) {
+ delete face_varying_evaluator;
+ }
+ }
+
+ // TODO(sergey): Implement binding API.
+
+ void updateData(const float *src, int start_vertex, int num_vertices) override
+ {
+ src_data_->UpdateData(src, start_vertex, num_vertices, device_context_);
+ }
+
+ void updateVaryingData(const float *src, int start_vertex, int num_vertices) override
+ {
+ src_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_);
+ }
+
+ void updateFaceVaryingData(const int face_varying_channel,
+ const float *src,
+ int start_vertex,
+ int num_vertices) override
+ {
+ assert(face_varying_channel >= 0);
+ assert(face_varying_channel < face_varying_evaluators.size());
+ face_varying_evaluators[face_varying_channel]->updateData(src, start_vertex, num_vertices);
+ }
+
+ bool hasVaryingData() const
+ {
+ // return varying_stencils_ != NULL;
+ // TODO(sergey): Check this based on actual topology.
+ return false;
+ }
+
+ bool hasFaceVaryingData() const
+ {
+ return face_varying_evaluators.size() != 0;
+ }
+
+ void refine() override
+ {
+ // Evaluate vertex positions.
+ BufferDescriptor dst_desc = src_desc_;
+ dst_desc.offset += num_coarse_vertices_ * src_desc_.stride;
+ const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
+ evaluator_cache_, src_desc_, dst_desc, device_context_);
+ EVALUATOR::EvalStencils(src_data_,
+ src_desc_,
+ src_data_,
+ dst_desc,
+ vertex_stencils_,
+ eval_instance,
+ device_context_);
+ // Evaluate varying data.
+ if (hasVaryingData()) {
+ BufferDescriptor dst_varying_desc = src_varying_desc_;
+ dst_varying_desc.offset += num_coarse_vertices_ * src_varying_desc_.stride;
+ eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
+ evaluator_cache_, src_varying_desc_, dst_varying_desc, device_context_);
+ EVALUATOR::EvalStencils(src_varying_data_,
+ src_varying_desc_,
+ src_varying_data_,
+ dst_varying_desc,
+ varying_stencils_,
+ eval_instance,
+ device_context_);
+ }
+ // Evaluate face-varying data.
+ if (hasFaceVaryingData()) {
+ for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators) {
+ face_varying_evaluator->refine();
+ }
+ }
+ }
+
+ // NOTE: P must point to a memory of at least float[3]*num_patch_coords.
+ void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *P) override
+ {
+ RawDataWrapperBuffer<float> P_data(P);
+ // TODO(sergey): Support interleaved vertex-varying data.
+ BufferDescriptor P_desc(0, 3, 3);
+ ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
+ const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
+ evaluator_cache_, src_desc_, P_desc, device_context_);
+ EVALUATOR::EvalPatches(src_data_,
+ src_desc_,
+ &P_data,
+ P_desc,
+ patch_coord_buffer.GetNumVertices(),
+ &patch_coord_buffer,
+ patch_table_,
+ eval_instance,
+ device_context_);
+ }
+
+ // NOTE: P, dPdu, dPdv must point to a memory of at least float[3]*num_patch_coords.
+ void evalPatchesWithDerivatives(const PatchCoord *patch_coord,
+ const int num_patch_coords,
+ float *P,
+ float *dPdu,
+ float *dPdv) override
+ {
+ assert(dPdu);
+ assert(dPdv);
+ RawDataWrapperBuffer<float> P_data(P);
+ RawDataWrapperBuffer<float> dPdu_data(dPdu), dPdv_data(dPdv);
+ // TODO(sergey): Support interleaved vertex-varying data.
+ BufferDescriptor P_desc(0, 3, 3);
+ BufferDescriptor dpDu_desc(0, 3, 3), pPdv_desc(0, 3, 3);
+ ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
+ const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
+ evaluator_cache_, src_desc_, P_desc, dpDu_desc, pPdv_desc, device_context_);
+ EVALUATOR::EvalPatches(src_data_,
+ src_desc_,
+ &P_data,
+ P_desc,
+ &dPdu_data,
+ dpDu_desc,
+ &dPdv_data,
+ pPdv_desc,
+ patch_coord_buffer.GetNumVertices(),
+ &patch_coord_buffer,
+ patch_table_,
+ eval_instance,
+ device_context_);
+ }
+
+ // NOTE: varying must point to a memory of at least float[3]*num_patch_coords.
+ void evalPatchesVarying(const PatchCoord *patch_coord,
+ const int num_patch_coords,
+ float *varying) override
+ {
+ RawDataWrapperBuffer<float> varying_data(varying);
+ BufferDescriptor varying_desc(3, 3, 6);
+ ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
+ const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
+ evaluator_cache_, src_varying_desc_, varying_desc, device_context_);
+ EVALUATOR::EvalPatchesVarying(src_varying_data_,
+ src_varying_desc_,
+ &varying_data,
+ varying_desc,
+ patch_coord_buffer.GetNumVertices(),
+ &patch_coord_buffer,
+ patch_table_,
+ eval_instance,
+ device_context_);
+ }
+
+ void evalPatchesFaceVarying(const int face_varying_channel,
+ const PatchCoord *patch_coord,
+ const int num_patch_coords,
+ float face_varying[2]) override
+ {
+ assert(face_varying_channel >= 0);
+ assert(face_varying_channel < face_varying_evaluators.size());
+ face_varying_evaluators[face_varying_channel]->evalPatches(
+ patch_coord, num_patch_coords, face_varying);
+ }
+
+ SRC_VERTEX_BUFFER *getSrcBuffer() const
+ {
+ return src_data_;
+ }
+
+ PATCH_TABLE *getPatchTable() const
+ {
+ return patch_table_;
+ }
+
+ SRC_VERTEX_BUFFER *getFVarSrcBuffer(const int face_varying_channel) const
+ {
+ return face_varying_evaluators[face_varying_channel]->getSrcBuffer();
+ }
+
+ int getFVarSrcBufferOffset(const int face_varying_channel) const
+ {
+ return face_varying_evaluators[face_varying_channel]->getFVarSrcBufferOffset();
+ }
+
+ PATCH_TABLE *getFVarPatchTable(const int face_varying_channel) const
+ {
+ return face_varying_evaluators[face_varying_channel]->getPatchTable();
+ }
+
+ private:
+ SRC_VERTEX_BUFFER *src_data_;
+ SRC_VERTEX_BUFFER *src_varying_data_;
+ PATCH_TABLE *patch_table_;
+ BufferDescriptor src_desc_;
+ BufferDescriptor src_varying_desc_;
+
+ int num_coarse_vertices_;
+
+ const STENCIL_TABLE *vertex_stencils_;
+ const STENCIL_TABLE *varying_stencils_;
+
+ int face_varying_width_;
+ vector<FaceVaryingEval *> face_varying_evaluators;
+
+ EvaluatorCache *evaluator_cache_;
+ DEVICE_CONTEXT *device_context_;
+};
+
+} // namespace opensubdiv
+} // namespace blender
+
+#endif // OPENSUBDIV_EVAL_OUTPUT_H_
diff --git a/intern/opensubdiv/internal/evaluator/eval_output_cpu.cc b/intern/opensubdiv/internal/evaluator/eval_output_cpu.cc
new file mode 100644
index 00000000000..02a41cb1580
--- /dev/null
+++ b/intern/opensubdiv/internal/evaluator/eval_output_cpu.cc
@@ -0,0 +1,23 @@
+// Copyright 2021 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+namespace blender {
+namespace opensubdiv {
+
+}
+} // namespace blender
diff --git a/intern/opensubdiv/internal/evaluator/eval_output_cpu.h b/intern/opensubdiv/internal/evaluator/eval_output_cpu.h
new file mode 100644
index 00000000000..58bae7a322e
--- /dev/null
+++ b/intern/opensubdiv/internal/evaluator/eval_output_cpu.h
@@ -0,0 +1,66 @@
+// Copyright 2021 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_EVAL_OUTPUT_CPU_H_
+#define OPENSUBDIV_EVAL_OUTPUT_CPU_H_
+
+#include "internal/evaluator/eval_output.h"
+
+#include <opensubdiv/osd/cpuEvaluator.h>
+#include <opensubdiv/osd/cpuPatchTable.h>
+#include <opensubdiv/osd/cpuVertexBuffer.h>
+
+using OpenSubdiv::Far::StencilTable;
+using OpenSubdiv::Osd::CpuEvaluator;
+using OpenSubdiv::Osd::CpuVertexBuffer;
+
+namespace blender {
+namespace opensubdiv {
+
+// Note: Define as a class instead of typedef to make it possible
+// to have anonymous class in opensubdiv_evaluator_internal.h
+class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer,
+ CpuVertexBuffer,
+ StencilTable,
+ CpuPatchTable,
+ CpuEvaluator> {
+ public:
+ CpuEvalOutput(const StencilTable *vertex_stencils,
+ const StencilTable *varying_stencils,
+ const vector<const StencilTable *> &all_face_varying_stencils,
+ const int face_varying_width,
+ const PatchTable *patch_table,
+ EvaluatorCache *evaluator_cache = NULL)
+ : VolatileEvalOutput<CpuVertexBuffer,
+ CpuVertexBuffer,
+ StencilTable,
+ CpuPatchTable,
+ CpuEvaluator>(vertex_stencils,
+ varying_stencils,
+ all_face_varying_stencils,
+ face_varying_width,
+ patch_table,
+ evaluator_cache)
+ {
+ }
+};
+
+} // namespace opensubdiv
+} // namespace blender
+
+#endif // OPENSUBDIV_EVAL_OUTPUT_CPU_H_
diff --git a/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc b/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc
new file mode 100644
index 00000000000..b352ed2c014
--- /dev/null
+++ b/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc
@@ -0,0 +1,120 @@
+// Copyright 2021 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#include "internal/evaluator/eval_output_gpu.h"
+
+#include "opensubdiv_evaluator_capi.h"
+
+using OpenSubdiv::Osd::PatchArray;
+using OpenSubdiv::Osd::PatchArrayVector;
+
+namespace blender {
+namespace opensubdiv {
+
+namespace {
+
+static void buildPatchArraysBufferFromVector(const PatchArrayVector &patch_arrays,
+ OpenSubdiv_Buffer *patch_arrays_buffer)
+{
+ const size_t patch_array_size = sizeof(PatchArray);
+ const size_t patch_array_byte_site = patch_array_size * patch_arrays.size();
+ patch_arrays_buffer->device_alloc(patch_arrays_buffer, patch_arrays.size());
+ patch_arrays_buffer->bind_gpu(patch_arrays_buffer);
+ patch_arrays_buffer->device_update(
+ patch_arrays_buffer, 0, patch_array_byte_site, &patch_arrays[0]);
+}
+
+} // namespace
+
+GpuEvalOutput::GpuEvalOutput(const StencilTable *vertex_stencils,
+ const StencilTable *varying_stencils,
+ const vector<const StencilTable *> &all_face_varying_stencils,
+ const int face_varying_width,
+ const PatchTable *patch_table,
+ VolatileEvalOutput::EvaluatorCache *evaluator_cache)
+ : VolatileEvalOutput<GLVertexBuffer,
+ GLVertexBuffer,
+ GLStencilTableSSBO,
+ GLPatchTable,
+ GLComputeEvaluator>(vertex_stencils,
+ varying_stencils,
+ all_face_varying_stencils,
+ face_varying_width,
+ patch_table,
+ evaluator_cache)
+{
+}
+
+void GpuEvalOutput::fillPatchArraysBuffer(OpenSubdiv_Buffer *patch_arrays_buffer)
+{
+ GLPatchTable *patch_table = getPatchTable();
+ buildPatchArraysBufferFromVector(patch_table->GetPatchArrays(), patch_arrays_buffer);
+}
+
+void GpuEvalOutput::wrapPatchIndexBuffer(OpenSubdiv_Buffer *patch_index_buffer)
+{
+ GLPatchTable *patch_table = getPatchTable();
+ patch_index_buffer->wrap_device_handle(patch_index_buffer, patch_table->GetPatchIndexBuffer());
+}
+
+void GpuEvalOutput::wrapPatchParamBuffer(OpenSubdiv_Buffer *patch_param_buffer)
+{
+ GLPatchTable *patch_table = getPatchTable();
+ patch_param_buffer->wrap_device_handle(patch_param_buffer, patch_table->GetPatchParamBuffer());
+}
+
+void GpuEvalOutput::wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer)
+{
+ GLVertexBuffer *vertex_buffer = getSrcBuffer();
+ src_buffer->wrap_device_handle(src_buffer, vertex_buffer->BindVBO());
+}
+
+void GpuEvalOutput::fillFVarPatchArraysBuffer(const int face_varying_channel,
+ OpenSubdiv_Buffer *patch_arrays_buffer)
+{
+ GLPatchTable *patch_table = getFVarPatchTable(face_varying_channel);
+ buildPatchArraysBufferFromVector(patch_table->GetFVarPatchArrays(face_varying_channel),
+ patch_arrays_buffer);
+}
+
+void GpuEvalOutput::wrapFVarPatchIndexBuffer(const int face_varying_channel,
+ OpenSubdiv_Buffer *patch_index_buffer)
+{
+ GLPatchTable *patch_table = getFVarPatchTable(face_varying_channel);
+ patch_index_buffer->wrap_device_handle(
+ patch_index_buffer, patch_table->GetFVarPatchIndexBuffer(face_varying_channel));
+}
+
+void GpuEvalOutput::wrapFVarPatchParamBuffer(const int face_varying_channel,
+ OpenSubdiv_Buffer *patch_param_buffer)
+{
+ GLPatchTable *patch_table = getFVarPatchTable(face_varying_channel);
+ patch_param_buffer->wrap_device_handle(
+ patch_param_buffer, patch_table->GetFVarPatchParamBuffer(face_varying_channel));
+}
+
+void GpuEvalOutput::wrapFVarSrcBuffer(const int face_varying_channel,
+ OpenSubdiv_Buffer *src_buffer)
+{
+ GLVertexBuffer *vertex_buffer = getFVarSrcBuffer(face_varying_channel);
+ src_buffer->buffer_offset = getFVarSrcBufferOffset(face_varying_channel);
+ src_buffer->wrap_device_handle(src_buffer, vertex_buffer->BindVBO());
+}
+
+} // namespace opensubdiv
+} // namespace blender
diff --git a/intern/opensubdiv/internal/evaluator/eval_output_gpu.h b/intern/opensubdiv/internal/evaluator/eval_output_gpu.h
new file mode 100644
index 00000000000..783efd484aa
--- /dev/null
+++ b/intern/opensubdiv/internal/evaluator/eval_output_gpu.h
@@ -0,0 +1,71 @@
+// Copyright 2021 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// Author: Sergey Sharybin
+
+#ifndef OPENSUBDIV_EVAL_OUTPUT_GPU_H_
+#define OPENSUBDIV_EVAL_OUTPUT_GPU_H_
+
+#include "internal/evaluator/eval_output.h"
+
+#include <opensubdiv/osd/glComputeEvaluator.h>
+#include <opensubdiv/osd/glPatchTable.h>
+#include <opensubdiv/osd/glVertexBuffer.h>
+
+using OpenSubdiv::Osd::GLComputeEvaluator;
+using OpenSubdiv::Osd::GLStencilTableSSBO;
+using OpenSubdiv::Osd::GLVertexBuffer;
+
+namespace blender {
+namespace opensubdiv {
+
+class GpuEvalOutput : public VolatileEvalOutput<GLVertexBuffer,
+ GLVertexBuffer,
+ GLStencilTableSSBO,
+ GLPatchTable,
+ GLComputeEvaluator> {
+ public:
+ GpuEvalOutput(const StencilTable *vertex_stencils,
+ const StencilTable *varying_stencils,
+ const vector<const StencilTable *> &all_face_varying_stencils,
+ const int face_varying_width,
+ const PatchTable *patch_table,
+ EvaluatorCache *evaluator_cache = NULL);
+
+ void fillPatchArraysBuffer(OpenSubdiv_Buffer *patch_arrays_buffer) override;
+
+ void wrapPatchIndexBuffer(OpenSubdiv_Buffer *patch_index_buffer) override;
+
+ void wrapPatchParamBuffer(OpenSubdiv_Buffer *patch_param_buffer) override;
+
+ void wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer) override;
+
+ void fillFVarPatchArraysBuffer(const int face_varying_channel,
+ OpenSubdiv_Buffer *patch_arrays_buffer) override;
+
+ void wrapFVarPatchIndexBuffer(const int face_varying_channel,
+ OpenSubdiv_Buffer *patch_index_buffer) override;
+
+ void wrapFVarPatchParamBuffer(const int face_varying_channel,
+ OpenSubdiv_Buffer *patch_param_buffer) override;
+
+ void wrapFVarSrcBuffer(const int face_varying_channel, OpenSubdiv_Buffer *src_buffer) override;
+};
+
+} // namespace opensubdiv
+} // namespace blender
+
+#endif // OPENSUBDIV_EVAL_OUTPUT_GPU_H_
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.cc b/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.cc
new file mode 100644
index 00000000000..2fffcefa460
--- /dev/null
+++ b/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.cc
@@ -0,0 +1,47 @@
+// Copyright 2021 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#include "internal/evaluator/evaluator_cache_impl.h"
+
+#include "internal/evaluator/eval_output_gpu.h"
+
+OpenSubdiv_EvaluatorCacheImpl::OpenSubdiv_EvaluatorCacheImpl()
+{
+}
+
+OpenSubdiv_EvaluatorCacheImpl::~OpenSubdiv_EvaluatorCacheImpl()
+{
+ delete static_cast<blender::opensubdiv::GpuEvalOutput::EvaluatorCache *>(eval_cache);
+}
+
+OpenSubdiv_EvaluatorCacheImpl *openSubdiv_createEvaluatorCacheInternal(
+ eOpenSubdivEvaluator evaluator_type)
+{
+ if (evaluator_type != eOpenSubdivEvaluator::OPENSUBDIV_EVALUATOR_GLSL_COMPUTE) {
+ return nullptr;
+ }
+ OpenSubdiv_EvaluatorCacheImpl *evaluator_cache;
+ evaluator_cache = new OpenSubdiv_EvaluatorCacheImpl;
+ blender::opensubdiv::GpuEvalOutput::EvaluatorCache *eval_cache;
+ eval_cache = new blender::opensubdiv::GpuEvalOutput::EvaluatorCache();
+ evaluator_cache->eval_cache = eval_cache;
+ return evaluator_cache;
+}
+
+void openSubdiv_deleteEvaluatorCacheInternal(OpenSubdiv_EvaluatorCacheImpl *evaluator_cache)
+{
+ delete evaluator_cache;
+}
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.h b/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.h
new file mode 100644
index 00000000000..060a78e5cbd
--- /dev/null
+++ b/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.h
@@ -0,0 +1,38 @@
+// Copyright 2021 Blender Foundation. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef OPENSUBDIV_EVALUATOR_CACHE_IMPL_H_
+#define OPENSUBDIV_EVALUATOR_CACHE_IMPL_H_
+
+#include "internal/base/memory.h"
+
+#include "opensubdiv_capi_type.h"
+
+struct OpenSubdiv_EvaluatorCacheImpl {
+ public:
+ OpenSubdiv_EvaluatorCacheImpl();
+ ~OpenSubdiv_EvaluatorCacheImpl();
+
+ void *eval_cache;
+ MEM_CXX_CLASS_ALLOC_FUNCS("OpenSubdiv_EvaluatorCacheImpl");
+};
+
+OpenSubdiv_EvaluatorCacheImpl *openSubdiv_createEvaluatorCacheInternal(
+ eOpenSubdivEvaluator evaluator_type);
+
+void openSubdiv_deleteEvaluatorCacheInternal(OpenSubdiv_EvaluatorCacheImpl *evaluator_cache);
+
+#endif // OPENSUBDIV_EVALUATOR_CACHE_IMPL_H_
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_capi.cc b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc
index 4b12206e103..567afd3a763 100644
--- a/intern/opensubdiv/internal/evaluator/evaluator_capi.cc
+++ b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc
@@ -18,9 +18,12 @@
#include "opensubdiv_evaluator_capi.h"
+#include <opensubdiv/osd/glslPatchShaderSource.h>
+
#include "MEM_guardedalloc.h"
#include <new>
+#include "internal/evaluator/evaluator_cache_impl.h"
#include "internal/evaluator/evaluator_impl.h"
namespace {
@@ -132,6 +135,74 @@ void evaluateFaceVarying(OpenSubdiv_Evaluator *evaluator,
face_varying_channel, ptex_face_index, face_u, face_v, face_varying);
}
+void getPatchMap(struct OpenSubdiv_Evaluator *evaluator,
+ struct OpenSubdiv_Buffer *patch_map_handles,
+ struct OpenSubdiv_Buffer *patch_map_quadtree,
+ int *min_patch_face,
+ int *max_patch_face,
+ int *max_depth,
+ int *patches_are_triangular)
+{
+ evaluator->impl->eval_output->getPatchMap(patch_map_handles,
+ patch_map_quadtree,
+ min_patch_face,
+ max_patch_face,
+ max_depth,
+ patches_are_triangular);
+}
+
+void fillPatchArraysBuffer(struct OpenSubdiv_Evaluator *evaluator,
+ struct OpenSubdiv_Buffer *patch_array_buffer)
+{
+ evaluator->impl->eval_output->fillPatchArraysBuffer(patch_array_buffer);
+}
+
+void wrapPatchIndexBuffer(struct OpenSubdiv_Evaluator *evaluator,
+ struct OpenSubdiv_Buffer *patch_index_buffer)
+{
+ evaluator->impl->eval_output->wrapPatchIndexBuffer(patch_index_buffer);
+}
+
+void wrapPatchParamBuffer(struct OpenSubdiv_Evaluator *evaluator,
+ struct OpenSubdiv_Buffer *patch_param_buffer)
+{
+ evaluator->impl->eval_output->wrapPatchParamBuffer(patch_param_buffer);
+}
+
+void wrapSrcBuffer(struct OpenSubdiv_Evaluator *evaluator, struct OpenSubdiv_Buffer *src_buffer)
+{
+ evaluator->impl->eval_output->wrapSrcBuffer(src_buffer);
+}
+
+void fillFVarPatchArraysBuffer(struct OpenSubdiv_Evaluator *evaluator,
+ const int face_varying_channel,
+ struct OpenSubdiv_Buffer *patch_array_buffer)
+{
+ evaluator->impl->eval_output->fillFVarPatchArraysBuffer(face_varying_channel,
+ patch_array_buffer);
+}
+
+void wrapFVarPatchIndexBuffer(struct OpenSubdiv_Evaluator *evaluator,
+ const int face_varying_channel,
+ struct OpenSubdiv_Buffer *patch_index_buffer)
+{
+ evaluator->impl->eval_output->wrapFVarPatchIndexBuffer(face_varying_channel, patch_index_buffer);
+}
+
+void wrapFVarPatchParamBuffer(struct OpenSubdiv_Evaluator *evaluator,
+ const int face_varying_channel,
+ struct OpenSubdiv_Buffer *patch_param_buffer)
+{
+ evaluator->impl->eval_output->wrapFVarPatchParamBuffer(face_varying_channel, patch_param_buffer);
+}
+
+void wrapFVarSrcBuffer(struct OpenSubdiv_Evaluator *evaluator,
+ const int face_varying_channel,
+ struct OpenSubdiv_Buffer *src_buffer)
+{
+ evaluator->impl->eval_output->wrapFVarSrcBuffer(face_varying_channel, src_buffer);
+}
+
void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator)
{
evaluator->setCoarsePositions = setCoarsePositions;
@@ -149,21 +220,64 @@ void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator)
evaluator->evaluateFaceVarying = evaluateFaceVarying;
evaluator->evaluatePatchesLimit = evaluatePatchesLimit;
+
+ evaluator->getPatchMap = getPatchMap;
+
+ evaluator->fillPatchArraysBuffer = fillPatchArraysBuffer;
+ evaluator->wrapPatchIndexBuffer = wrapPatchIndexBuffer;
+ evaluator->wrapPatchParamBuffer = wrapPatchParamBuffer;
+ evaluator->wrapSrcBuffer = wrapSrcBuffer;
+
+ evaluator->fillFVarPatchArraysBuffer = fillFVarPatchArraysBuffer;
+ evaluator->wrapFVarPatchIndexBuffer = wrapFVarPatchIndexBuffer;
+ evaluator->wrapFVarPatchParamBuffer = wrapFVarPatchParamBuffer;
+ evaluator->wrapFVarSrcBuffer = wrapFVarSrcBuffer;
}
} // namespace
OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
- OpenSubdiv_TopologyRefiner *topology_refiner)
+ OpenSubdiv_TopologyRefiner *topology_refiner,
+ eOpenSubdivEvaluator evaluator_type,
+ OpenSubdiv_EvaluatorCache *evaluator_cache)
{
- OpenSubdiv_Evaluator *evaluator = OBJECT_GUARDED_NEW(OpenSubdiv_Evaluator);
+ OpenSubdiv_Evaluator *evaluator = MEM_new<OpenSubdiv_Evaluator>(__func__);
assignFunctionPointers(evaluator);
- evaluator->impl = openSubdiv_createEvaluatorInternal(topology_refiner);
+ evaluator->impl = openSubdiv_createEvaluatorInternal(
+ topology_refiner, evaluator_type, evaluator_cache ? evaluator_cache->impl : nullptr);
+ evaluator->type = evaluator->impl ? evaluator_type : static_cast<eOpenSubdivEvaluator>(0);
return evaluator;
}
void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator *evaluator)
{
openSubdiv_deleteEvaluatorInternal(evaluator->impl);
- OBJECT_GUARDED_DELETE(evaluator, OpenSubdiv_Evaluator);
+ MEM_delete(evaluator);
+}
+
+OpenSubdiv_EvaluatorCache *openSubdiv_createEvaluatorCache(eOpenSubdivEvaluator evaluator_type)
+{
+ OpenSubdiv_EvaluatorCache *evaluator_cache = MEM_new<OpenSubdiv_EvaluatorCache>(__func__);
+ evaluator_cache->impl = openSubdiv_createEvaluatorCacheInternal(evaluator_type);
+ return evaluator_cache;
+}
+
+void openSubdiv_deleteEvaluatorCache(OpenSubdiv_EvaluatorCache *evaluator_cache)
+{
+ if (!evaluator_cache) {
+ return;
+ }
+
+ openSubdiv_deleteEvaluatorCacheInternal(evaluator_cache->impl);
+ MEM_delete(evaluator_cache);
+}
+
+const char *openSubdiv_getGLSLPatchBasisSource(void)
+{
+ /* Using a global string to avoid dealing with memory allocation/ownership. */
+ static std::string patch_basis_source;
+ if (patch_basis_source.empty()) {
+ patch_basis_source = OpenSubdiv::Osd::GLSLPatchShaderSource::GetPatchBasisShaderSource();
+ }
+ return patch_basis_source.c_str();
}
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.cc b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc
index 4f4f332ff15..755b8bfbc81 100644
--- a/intern/opensubdiv/internal/evaluator/evaluator_impl.cc
+++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc
@@ -28,9 +28,6 @@
#include <opensubdiv/far/patchMap.h>
#include <opensubdiv/far/patchTable.h>
#include <opensubdiv/far/patchTableFactory.h>
-#include <opensubdiv/osd/cpuEvaluator.h>
-#include <opensubdiv/osd/cpuPatchTable.h>
-#include <opensubdiv/osd/cpuVertexBuffer.h>
#include <opensubdiv/osd/mesh.h>
#include <opensubdiv/osd/types.h>
#include <opensubdiv/version.h>
@@ -38,19 +35,20 @@
#include "MEM_guardedalloc.h"
#include "internal/base/type.h"
+#include "internal/evaluator/eval_output_cpu.h"
+#include "internal/evaluator/eval_output_gpu.h"
+#include "internal/evaluator/evaluator_cache_impl.h"
+#include "internal/evaluator/patch_map.h"
#include "internal/topology/topology_refiner_impl.h"
+#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_topology_refiner_capi.h"
-using OpenSubdiv::Far::PatchMap;
using OpenSubdiv::Far::PatchTable;
using OpenSubdiv::Far::PatchTableFactory;
using OpenSubdiv::Far::StencilTable;
using OpenSubdiv::Far::StencilTableFactory;
using OpenSubdiv::Far::TopologyRefiner;
-using OpenSubdiv::Osd::BufferDescriptor;
-using OpenSubdiv::Osd::CpuEvaluator;
-using OpenSubdiv::Osd::CpuPatchTable;
-using OpenSubdiv::Osd::CpuVertexBuffer;
+using OpenSubdiv::Osd::PatchArray;
using OpenSubdiv::Osd::PatchCoord;
namespace blender {
@@ -140,407 +138,9 @@ template<typename T, int kNumMaxElementsOnStack> class StackOrHeapArray {
// 32 is a number of inner vertices along the patch size at subdivision level 6.
typedef StackOrHeapArray<PatchCoord, 32 * 32> StackOrHeapPatchCoordArray;
-// Buffer which implements API required by OpenSubdiv and uses an existing memory as an underlying
-// storage.
-template<typename T> class RawDataWrapperBuffer {
- public:
- RawDataWrapperBuffer(T *data) : data_(data)
- {
- }
-
- T *BindCpuBuffer()
- {
- return data_;
- }
-
- // TODO(sergey): Support UpdateData().
-
- protected:
- T *data_;
-};
-
-template<typename T> class RawDataWrapperVertexBuffer : public RawDataWrapperBuffer<T> {
- public:
- RawDataWrapperVertexBuffer(T *data, int num_vertices)
- : RawDataWrapperBuffer<T>(data), num_vertices_(num_vertices)
- {
- }
-
- int GetNumVertices()
- {
- return num_vertices_;
- }
-
- protected:
- int num_vertices_;
-};
-
-class ConstPatchCoordWrapperBuffer : public RawDataWrapperVertexBuffer<const PatchCoord> {
- public:
- ConstPatchCoordWrapperBuffer(const PatchCoord *data, int num_vertices)
- : RawDataWrapperVertexBuffer(data, num_vertices)
- {
- }
-};
-
-template<typename EVAL_VERTEX_BUFFER,
- typename STENCIL_TABLE,
- typename PATCH_TABLE,
- typename EVALUATOR,
- typename DEVICE_CONTEXT = void>
-class FaceVaryingVolatileEval {
- public:
- typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache;
-
- FaceVaryingVolatileEval(int face_varying_channel,
- const StencilTable *face_varying_stencils,
- int face_varying_width,
- PATCH_TABLE *patch_table,
- EvaluatorCache *evaluator_cache = NULL,
- DEVICE_CONTEXT *device_context = NULL)
- : face_varying_channel_(face_varying_channel),
- src_face_varying_desc_(0, face_varying_width, face_varying_width),
- patch_table_(patch_table),
- evaluator_cache_(evaluator_cache),
- device_context_(device_context)
- {
- using OpenSubdiv::Osd::convertToCompatibleStencilTable;
- num_coarse_face_varying_vertices_ = face_varying_stencils->GetNumControlVertices();
- const int num_total_face_varying_vertices = face_varying_stencils->GetNumControlVertices() +
- face_varying_stencils->GetNumStencils();
- src_face_varying_data_ = EVAL_VERTEX_BUFFER::Create(
- 2, num_total_face_varying_vertices, device_context);
- face_varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(face_varying_stencils,
- device_context_);
- }
-
- ~FaceVaryingVolatileEval()
- {
- delete src_face_varying_data_;
- delete face_varying_stencils_;
- }
-
- void updateData(const float *src, int start_vertex, int num_vertices)
- {
- src_face_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_);
- }
-
- void refine()
- {
- BufferDescriptor dst_face_varying_desc = src_face_varying_desc_;
- dst_face_varying_desc.offset += num_coarse_face_varying_vertices_ *
- src_face_varying_desc_.stride;
- const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
- evaluator_cache_, src_face_varying_desc_, dst_face_varying_desc, device_context_);
- // in and out points to same buffer so output is put directly after coarse vertices, needed in
- // adaptive mode
- EVALUATOR::EvalStencils(src_face_varying_data_,
- src_face_varying_desc_,
- src_face_varying_data_,
- dst_face_varying_desc,
- face_varying_stencils_,
- eval_instance,
- device_context_);
- }
-
- // NOTE: face_varying must point to a memory of at least float[2]*num_patch_coords.
- void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *face_varying)
- {
- RawDataWrapperBuffer<float> face_varying_data(face_varying);
- BufferDescriptor face_varying_desc(0, 2, 2);
- ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
- const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
- evaluator_cache_, src_face_varying_desc_, face_varying_desc, device_context_);
-
- // src_face_varying_data_ always contains coarse vertices at the beginning.
- // In adaptive mode they are followed by number of blocks for intermediate
- // subdivision levels, and this is what OSD expects in this mode.
- // In non-adaptive mode (generateIntermediateLevels == false),
- // they are followed by max subdivision level, but they break interpolation as OSD
- // expects only one subd level in this buffer.
- // So in non-adaptive mode we put offset into buffer descriptor to skip over coarse vertices.
- BufferDescriptor src_desc = src_face_varying_desc_;
- if (!patch_table_->GetPatchArrayBuffer()[0].GetDescriptor().IsAdaptive()) {
- src_desc.offset += num_coarse_face_varying_vertices_ * src_face_varying_desc_.stride;
- }
-
- EVALUATOR::EvalPatchesFaceVarying(src_face_varying_data_,
- src_desc,
- &face_varying_data,
- face_varying_desc,
- patch_coord_buffer.GetNumVertices(),
- &patch_coord_buffer,
- patch_table_,
- face_varying_channel_,
- eval_instance,
- device_context_);
- }
-
- protected:
- int face_varying_channel_;
-
- BufferDescriptor src_face_varying_desc_;
-
- int num_coarse_face_varying_vertices_;
- EVAL_VERTEX_BUFFER *src_face_varying_data_;
- const STENCIL_TABLE *face_varying_stencils_;
-
- // NOTE: We reference this, do not own it.
- PATCH_TABLE *patch_table_;
-
- EvaluatorCache *evaluator_cache_;
- DEVICE_CONTEXT *device_context_;
-};
-
-// Volatile evaluator which can be used from threads.
-//
-// TODO(sergey): Make it possible to evaluate coordinates in chunks.
-// TODO(sergey): Make it possible to evaluate multiple face varying layers.
-// (or maybe, it's cheap to create new evaluator for existing
-// topology to evaluate all needed face varying layers?)
-template<typename SRC_VERTEX_BUFFER,
- typename EVAL_VERTEX_BUFFER,
- typename STENCIL_TABLE,
- typename PATCH_TABLE,
- typename EVALUATOR,
- typename DEVICE_CONTEXT = void>
-class VolatileEvalOutput {
- public:
- typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache;
- typedef FaceVaryingVolatileEval<EVAL_VERTEX_BUFFER,
- STENCIL_TABLE,
- PATCH_TABLE,
- EVALUATOR,
- DEVICE_CONTEXT>
- FaceVaryingEval;
-
- VolatileEvalOutput(const StencilTable *vertex_stencils,
- const StencilTable *varying_stencils,
- const vector<const StencilTable *> &all_face_varying_stencils,
- const int face_varying_width,
- const PatchTable *patch_table,
- EvaluatorCache *evaluator_cache = NULL,
- DEVICE_CONTEXT *device_context = NULL)
- : src_desc_(0, 3, 3),
- src_varying_desc_(0, 3, 3),
- face_varying_width_(face_varying_width),
- evaluator_cache_(evaluator_cache),
- device_context_(device_context)
- {
- // Total number of vertices = coarse points + refined points + local points.
- int num_total_vertices = vertex_stencils->GetNumControlVertices() +
- vertex_stencils->GetNumStencils();
- num_coarse_vertices_ = vertex_stencils->GetNumControlVertices();
- using OpenSubdiv::Osd::convertToCompatibleStencilTable;
- src_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_);
- src_varying_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_);
- patch_table_ = PATCH_TABLE::Create(patch_table, device_context_);
- vertex_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(vertex_stencils,
- device_context_);
- varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(varying_stencils,
- device_context_);
- // Create evaluators for every face varying channel.
- face_varying_evaluators.reserve(all_face_varying_stencils.size());
- int face_varying_channel = 0;
- for (const StencilTable *face_varying_stencils : all_face_varying_stencils) {
- face_varying_evaluators.push_back(new FaceVaryingEval(face_varying_channel,
- face_varying_stencils,
- face_varying_width,
- patch_table_,
- evaluator_cache_,
- device_context_));
- ++face_varying_channel;
- }
- }
-
- ~VolatileEvalOutput()
- {
- delete src_data_;
- delete src_varying_data_;
- delete patch_table_;
- delete vertex_stencils_;
- delete varying_stencils_;
- for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators) {
- delete face_varying_evaluator;
- }
- }
-
- // TODO(sergey): Implement binding API.
-
- void updateData(const float *src, int start_vertex, int num_vertices)
- {
- src_data_->UpdateData(src, start_vertex, num_vertices, device_context_);
- }
-
- void updateVaryingData(const float *src, int start_vertex, int num_vertices)
- {
- src_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_);
- }
-
- void updateFaceVaryingData(const int face_varying_channel,
- const float *src,
- int start_vertex,
- int num_vertices)
- {
- assert(face_varying_channel >= 0);
- assert(face_varying_channel < face_varying_evaluators.size());
- face_varying_evaluators[face_varying_channel]->updateData(src, start_vertex, num_vertices);
- }
-
- bool hasVaryingData() const
- {
- // return varying_stencils_ != NULL;
- // TODO(sergey): Check this based on actual topology.
- return false;
- }
-
- bool hasFaceVaryingData() const
- {
- return face_varying_evaluators.size() != 0;
- }
-
- void refine()
- {
- // Evaluate vertex positions.
- BufferDescriptor dst_desc = src_desc_;
- dst_desc.offset += num_coarse_vertices_ * src_desc_.stride;
- const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
- evaluator_cache_, src_desc_, dst_desc, device_context_);
- EVALUATOR::EvalStencils(src_data_,
- src_desc_,
- src_data_,
- dst_desc,
- vertex_stencils_,
- eval_instance,
- device_context_);
- // Evaluate varying data.
- if (hasVaryingData()) {
- BufferDescriptor dst_varying_desc = src_varying_desc_;
- dst_varying_desc.offset += num_coarse_vertices_ * src_varying_desc_.stride;
- eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
- evaluator_cache_, src_varying_desc_, dst_varying_desc, device_context_);
- EVALUATOR::EvalStencils(src_varying_data_,
- src_varying_desc_,
- src_varying_data_,
- dst_varying_desc,
- varying_stencils_,
- eval_instance,
- device_context_);
- }
- // Evaluate face-varying data.
- if (hasFaceVaryingData()) {
- for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators) {
- face_varying_evaluator->refine();
- }
- }
- }
-
- // NOTE: P must point to a memory of at least float[3]*num_patch_coords.
- void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *P)
- {
- RawDataWrapperBuffer<float> P_data(P);
- // TODO(sergey): Support interleaved vertex-varying data.
- BufferDescriptor P_desc(0, 3, 3);
- ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
- const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
- evaluator_cache_, src_desc_, P_desc, device_context_);
- EVALUATOR::EvalPatches(src_data_,
- src_desc_,
- &P_data,
- P_desc,
- patch_coord_buffer.GetNumVertices(),
- &patch_coord_buffer,
- patch_table_,
- eval_instance,
- device_context_);
- }
-
- // NOTE: P, dPdu, dPdv must point to a memory of at least float[3]*num_patch_coords.
- void evalPatchesWithDerivatives(const PatchCoord *patch_coord,
- const int num_patch_coords,
- float *P,
- float *dPdu,
- float *dPdv)
- {
- assert(dPdu);
- assert(dPdv);
- RawDataWrapperBuffer<float> P_data(P);
- RawDataWrapperBuffer<float> dPdu_data(dPdu), dPdv_data(dPdv);
- // TODO(sergey): Support interleaved vertex-varying data.
- BufferDescriptor P_desc(0, 3, 3);
- BufferDescriptor dpDu_desc(0, 3, 3), pPdv_desc(0, 3, 3);
- ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
- const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
- evaluator_cache_, src_desc_, P_desc, dpDu_desc, pPdv_desc, device_context_);
- EVALUATOR::EvalPatches(src_data_,
- src_desc_,
- &P_data,
- P_desc,
- &dPdu_data,
- dpDu_desc,
- &dPdv_data,
- pPdv_desc,
- patch_coord_buffer.GetNumVertices(),
- &patch_coord_buffer,
- patch_table_,
- eval_instance,
- device_context_);
- }
-
- // NOTE: varying must point to a memory of at least float[3]*num_patch_coords.
- void evalPatchesVarying(const PatchCoord *patch_coord,
- const int num_patch_coords,
- float *varying)
- {
- RawDataWrapperBuffer<float> varying_data(varying);
- BufferDescriptor varying_desc(3, 3, 6);
- ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
- const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
- evaluator_cache_, src_varying_desc_, varying_desc, device_context_);
- EVALUATOR::EvalPatchesVarying(src_varying_data_,
- src_varying_desc_,
- &varying_data,
- varying_desc,
- patch_coord_buffer.GetNumVertices(),
- &patch_coord_buffer,
- patch_table_,
- eval_instance,
- device_context_);
- }
-
- void evalPatchesFaceVarying(const int face_varying_channel,
- const PatchCoord *patch_coord,
- const int num_patch_coords,
- float face_varying[2])
- {
- assert(face_varying_channel >= 0);
- assert(face_varying_channel < face_varying_evaluators.size());
- face_varying_evaluators[face_varying_channel]->evalPatches(
- patch_coord, num_patch_coords, face_varying);
- }
-
- private:
- SRC_VERTEX_BUFFER *src_data_;
- SRC_VERTEX_BUFFER *src_varying_data_;
- PATCH_TABLE *patch_table_;
- BufferDescriptor src_desc_;
- BufferDescriptor src_varying_desc_;
-
- int num_coarse_vertices_;
-
- const STENCIL_TABLE *vertex_stencils_;
- const STENCIL_TABLE *varying_stencils_;
-
- int face_varying_width_;
- vector<FaceVaryingEval *> face_varying_evaluators;
-
- EvaluatorCache *evaluator_cache_;
- DEVICE_CONTEXT *device_context_;
-};
-
void convertPatchCoordsToArray(const OpenSubdiv_PatchCoord *patch_coords,
const int num_patch_coords,
- const OpenSubdiv::Far::PatchMap *patch_map,
+ const PatchMap *patch_map,
StackOrHeapPatchCoordArray *array)
{
array->resize(num_patch_coords);
@@ -553,79 +153,50 @@ void convertPatchCoordsToArray(const OpenSubdiv_PatchCoord *patch_coords,
} // namespace
-// Note: Define as a class instead of typedef to make it possible
-// to have anonymous class in opensubdiv_evaluator_internal.h
-class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer,
- CpuVertexBuffer,
- StencilTable,
- CpuPatchTable,
- CpuEvaluator> {
- public:
- CpuEvalOutput(const StencilTable *vertex_stencils,
- const StencilTable *varying_stencils,
- const vector<const StencilTable *> &all_face_varying_stencils,
- const int face_varying_width,
- const PatchTable *patch_table,
- EvaluatorCache *evaluator_cache = NULL)
- : VolatileEvalOutput<CpuVertexBuffer,
- CpuVertexBuffer,
- StencilTable,
- CpuPatchTable,
- CpuEvaluator>(vertex_stencils,
- varying_stencils,
- all_face_varying_stencils,
- face_varying_width,
- patch_table,
- evaluator_cache)
- {
- }
-};
-
////////////////////////////////////////////////////////////////////////////////
// Evaluator wrapper for anonymous API.
-CpuEvalOutputAPI::CpuEvalOutputAPI(CpuEvalOutput *implementation,
- OpenSubdiv::Far::PatchMap *patch_map)
- : implementation_(implementation), patch_map_(patch_map)
+EvalOutputAPI::EvalOutputAPI(EvalOutput *implementation, PatchMap *patch_map)
+ : patch_map_(patch_map), implementation_(implementation)
{
}
-CpuEvalOutputAPI::~CpuEvalOutputAPI()
+EvalOutputAPI::~EvalOutputAPI()
{
delete implementation_;
}
-void CpuEvalOutputAPI::setCoarsePositions(const float *positions,
- const int start_vertex_index,
- const int num_vertices)
+void EvalOutputAPI::setCoarsePositions(const float *positions,
+ const int start_vertex_index,
+ const int num_vertices)
{
// TODO(sergey): Add sanity check on indices.
implementation_->updateData(positions, start_vertex_index, num_vertices);
}
-void CpuEvalOutputAPI::setVaryingData(const float *varying_data,
- const int start_vertex_index,
- const int num_vertices)
+void EvalOutputAPI::setVaryingData(const float *varying_data,
+ const int start_vertex_index,
+ const int num_vertices)
{
// TODO(sergey): Add sanity check on indices.
implementation_->updateVaryingData(varying_data, start_vertex_index, num_vertices);
}
-void CpuEvalOutputAPI::setFaceVaryingData(const int face_varying_channel,
- const float *face_varying_data,
- const int start_vertex_index,
- const int num_vertices)
+void EvalOutputAPI::setFaceVaryingData(const int face_varying_channel,
+ const float *face_varying_data,
+ const int start_vertex_index,
+ const int num_vertices)
{
// TODO(sergey): Add sanity check on indices.
implementation_->updateFaceVaryingData(
face_varying_channel, face_varying_data, start_vertex_index, num_vertices);
}
-void CpuEvalOutputAPI::setCoarsePositionsFromBuffer(const void *buffer,
- const int start_offset,
- const int stride,
- const int start_vertex_index,
- const int num_vertices)
+void EvalOutputAPI::setCoarsePositionsFromBuffer(const void *buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices)
{
// TODO(sergey): Add sanity check on indices.
const unsigned char *current_buffer = (unsigned char *)buffer;
@@ -638,11 +209,11 @@ void CpuEvalOutputAPI::setCoarsePositionsFromBuffer(const void *buffer,
}
}
-void CpuEvalOutputAPI::setVaryingDataFromBuffer(const void *buffer,
- const int start_offset,
- const int stride,
- const int start_vertex_index,
- const int num_vertices)
+void EvalOutputAPI::setVaryingDataFromBuffer(const void *buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices)
{
// TODO(sergey): Add sanity check on indices.
const unsigned char *current_buffer = (unsigned char *)buffer;
@@ -655,12 +226,12 @@ void CpuEvalOutputAPI::setVaryingDataFromBuffer(const void *buffer,
}
}
-void CpuEvalOutputAPI::setFaceVaryingDataFromBuffer(const int face_varying_channel,
- const void *buffer,
- const int start_offset,
- const int stride,
- const int start_vertex_index,
- const int num_vertices)
+void EvalOutputAPI::setFaceVaryingDataFromBuffer(const int face_varying_channel,
+ const void *buffer,
+ const int start_offset,
+ const int stride,
+ const int start_vertex_index,
+ const int num_vertices)
{
// TODO(sergey): Add sanity check on indices.
const unsigned char *current_buffer = (unsigned char *)buffer;
@@ -675,17 +246,17 @@ void CpuEvalOutputAPI::setFaceVaryingDataFromBuffer(const int face_varying_chann
}
}
-void CpuEvalOutputAPI::refine()
+void EvalOutputAPI::refine()
{
implementation_->refine();
}
-void CpuEvalOutputAPI::evaluateLimit(const int ptex_face_index,
- float face_u,
- float face_v,
- float P[3],
- float dPdu[3],
- float dPdv[3])
+void EvalOutputAPI::evaluateLimit(const int ptex_face_index,
+ float face_u,
+ float face_v,
+ float P[3],
+ float dPdu[3],
+ float dPdv[3])
{
assert(face_u >= 0.0f);
assert(face_u <= 1.0f);
@@ -701,10 +272,10 @@ void CpuEvalOutputAPI::evaluateLimit(const int ptex_face_index,
}
}
-void CpuEvalOutputAPI::evaluateVarying(const int ptex_face_index,
- float face_u,
- float face_v,
- float varying[3])
+void EvalOutputAPI::evaluateVarying(const int ptex_face_index,
+ float face_u,
+ float face_v,
+ float varying[3])
{
assert(face_u >= 0.0f);
assert(face_u <= 1.0f);
@@ -715,11 +286,11 @@ void CpuEvalOutputAPI::evaluateVarying(const int ptex_face_index,
implementation_->evalPatchesVarying(&patch_coord, 1, varying);
}
-void CpuEvalOutputAPI::evaluateFaceVarying(const int face_varying_channel,
- const int ptex_face_index,
- float face_u,
- float face_v,
- float face_varying[2])
+void EvalOutputAPI::evaluateFaceVarying(const int face_varying_channel,
+ const int ptex_face_index,
+ float face_u,
+ float face_v,
+ float face_varying[2])
{
assert(face_u >= 0.0f);
assert(face_u <= 1.0f);
@@ -730,11 +301,11 @@ void CpuEvalOutputAPI::evaluateFaceVarying(const int face_varying_channel,
implementation_->evalPatchesFaceVarying(face_varying_channel, &patch_coord, 1, face_varying);
}
-void CpuEvalOutputAPI::evaluatePatchesLimit(const OpenSubdiv_PatchCoord *patch_coords,
- const int num_patch_coords,
- float *P,
- float *dPdu,
- float *dPdv)
+void EvalOutputAPI::evaluatePatchesLimit(const OpenSubdiv_PatchCoord *patch_coords,
+ const int num_patch_coords,
+ float *P,
+ float *dPdu,
+ float *dPdv)
{
StackOrHeapPatchCoordArray patch_coords_array;
convertPatchCoordsToArray(patch_coords, num_patch_coords, patch_map_, &patch_coords_array);
@@ -747,6 +318,73 @@ void CpuEvalOutputAPI::evaluatePatchesLimit(const OpenSubdiv_PatchCoord *patch_c
}
}
+void EvalOutputAPI::getPatchMap(OpenSubdiv_Buffer *patch_map_handles,
+ OpenSubdiv_Buffer *patch_map_quadtree,
+ int *min_patch_face,
+ int *max_patch_face,
+ int *max_depth,
+ int *patches_are_triangular)
+{
+ *min_patch_face = patch_map_->getMinPatchFace();
+ *max_patch_face = patch_map_->getMaxPatchFace();
+ *max_depth = patch_map_->getMaxDepth();
+ *patches_are_triangular = patch_map_->getPatchesAreTriangular();
+
+ const std::vector<PatchTable::PatchHandle> &handles = patch_map_->getHandles();
+ PatchTable::PatchHandle *buffer_handles = static_cast<PatchTable::PatchHandle *>(
+ patch_map_handles->alloc(patch_map_handles, handles.size()));
+ memcpy(buffer_handles, &handles[0], sizeof(PatchTable::PatchHandle) * handles.size());
+
+ const std::vector<PatchMap::QuadNode> &quadtree = patch_map_->nodes();
+ PatchMap::QuadNode *buffer_nodes = static_cast<PatchMap::QuadNode *>(
+ patch_map_quadtree->alloc(patch_map_quadtree, quadtree.size()));
+ memcpy(buffer_nodes, &quadtree[0], sizeof(PatchMap::QuadNode) * quadtree.size());
+}
+
+void EvalOutputAPI::fillPatchArraysBuffer(OpenSubdiv_Buffer *patch_arrays_buffer)
+{
+ implementation_->fillPatchArraysBuffer(patch_arrays_buffer);
+}
+
+void EvalOutputAPI::wrapPatchIndexBuffer(OpenSubdiv_Buffer *patch_index_buffer)
+{
+ implementation_->wrapPatchIndexBuffer(patch_index_buffer);
+}
+
+void EvalOutputAPI::wrapPatchParamBuffer(OpenSubdiv_Buffer *patch_param_buffer)
+{
+ implementation_->wrapPatchParamBuffer(patch_param_buffer);
+}
+
+void EvalOutputAPI::wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer)
+{
+ implementation_->wrapSrcBuffer(src_buffer);
+}
+
+void EvalOutputAPI::fillFVarPatchArraysBuffer(const int face_varying_channel,
+ OpenSubdiv_Buffer *patch_arrays_buffer)
+{
+ implementation_->fillFVarPatchArraysBuffer(face_varying_channel, patch_arrays_buffer);
+}
+
+void EvalOutputAPI::wrapFVarPatchIndexBuffer(const int face_varying_channel,
+ OpenSubdiv_Buffer *patch_index_buffer)
+{
+ implementation_->wrapFVarPatchIndexBuffer(face_varying_channel, patch_index_buffer);
+}
+
+void EvalOutputAPI::wrapFVarPatchParamBuffer(const int face_varying_channel,
+ OpenSubdiv_Buffer *patch_param_buffer)
+{
+ implementation_->wrapFVarPatchParamBuffer(face_varying_channel, patch_param_buffer);
+}
+
+void EvalOutputAPI::wrapFVarSrcBuffer(const int face_varying_channel,
+ OpenSubdiv_Buffer *src_buffer)
+{
+ implementation_->wrapFVarSrcBuffer(face_varying_channel, src_buffer);
+}
+
} // namespace opensubdiv
} // namespace blender
@@ -763,8 +401,15 @@ OpenSubdiv_EvaluatorImpl::~OpenSubdiv_EvaluatorImpl()
}
OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
- OpenSubdiv_TopologyRefiner *topology_refiner)
+ OpenSubdiv_TopologyRefiner *topology_refiner,
+ eOpenSubdivEvaluator evaluator_type,
+ OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr)
{
+ // Only CPU and GLCompute are implemented at the moment.
+ if (evaluator_type != OPENSUBDIV_EVALUATOR_CPU &&
+ evaluator_type != OPENSUBDIV_EVALUATOR_GLSL_COMPUTE) {
+ return NULL;
+ }
using blender::opensubdiv::vector;
TopologyRefiner *refiner = topology_refiner->impl->topology_refiner;
if (refiner == NULL) {
@@ -867,14 +512,34 @@ OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
}
}
// Create OpenSubdiv's CPU side evaluator.
- // TODO(sergey): Make it possible to use different evaluators.
- blender::opensubdiv::CpuEvalOutput *eval_output = new blender::opensubdiv::CpuEvalOutput(
- vertex_stencils, varying_stencils, all_face_varying_stencils, 2, patch_table);
- OpenSubdiv::Far::PatchMap *patch_map = new PatchMap(*patch_table);
+ blender::opensubdiv::EvalOutputAPI::EvalOutput *eval_output = nullptr;
+
+ const bool use_gl_evaluator = evaluator_type == OPENSUBDIV_EVALUATOR_GLSL_COMPUTE;
+ if (use_gl_evaluator) {
+ blender::opensubdiv::GpuEvalOutput::EvaluatorCache *evaluator_cache = nullptr;
+ if (evaluator_cache_descr) {
+ evaluator_cache = static_cast<blender::opensubdiv::GpuEvalOutput::EvaluatorCache *>(
+ evaluator_cache_descr->eval_cache);
+ }
+
+ eval_output = new blender::opensubdiv::GpuEvalOutput(vertex_stencils,
+ varying_stencils,
+ all_face_varying_stencils,
+ 2,
+ patch_table,
+ evaluator_cache);
+ }
+ else {
+ eval_output = new blender::opensubdiv::CpuEvalOutput(
+ vertex_stencils, varying_stencils, all_face_varying_stencils, 2, patch_table);
+ }
+
+ blender::opensubdiv::PatchMap *patch_map = new blender::opensubdiv::PatchMap(*patch_table);
// Wrap everything we need into an object which we control from our side.
OpenSubdiv_EvaluatorImpl *evaluator_descr;
evaluator_descr = new OpenSubdiv_EvaluatorImpl();
- evaluator_descr->eval_output = new blender::opensubdiv::CpuEvalOutputAPI(eval_output, patch_map);
+
+ evaluator_descr->eval_output = new blender::opensubdiv::EvalOutputAPI(eval_output, patch_map);
evaluator_descr->patch_map = patch_map;
evaluator_descr->patch_table = patch_table;
// TOOD(sergey): Look into whether we've got duplicated stencils arrays.
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.h b/intern/opensubdiv/internal/evaluator/evaluator_impl.h
index e7ccc9b376a..e24d47cba79 100644
--- a/intern/opensubdiv/internal/evaluator/evaluator_impl.h
+++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.h
@@ -28,14 +28,17 @@
#include "internal/base/memory.h"
+#include "opensubdiv_capi_type.h"
+
+struct OpenSubdiv_Buffer;
+struct OpenSubdiv_EvaluatorCacheImpl;
struct OpenSubdiv_PatchCoord;
struct OpenSubdiv_TopologyRefiner;
namespace blender {
namespace opensubdiv {
-// Anonymous forward declaration of actual evaluator implementation.
-class CpuEvalOutput;
+class PatchMap;
// Wrapper around implementation, which defines API which we are capable to
// provide over the implementation.
@@ -43,11 +46,15 @@ class CpuEvalOutput;
// TODO(sergey): It is almost the same as C-API object, so ideally need to
// merge them somehow, but how to do this and keep files with all the templates
// and such separate?
-class CpuEvalOutputAPI {
+class EvalOutputAPI {
public:
- // NOTE: API object becomes an owner of evaluator. Patch we are referencing.
- CpuEvalOutputAPI(CpuEvalOutput *implementation, OpenSubdiv::Far::PatchMap *patch_map);
- ~CpuEvalOutputAPI();
+ // Anonymous forward declaration of actual evaluator implementation.
+ class EvalOutput;
+
+ // NOTE: PatchMap is not owned, only referenced.
+ EvalOutputAPI(EvalOutput *implementation, PatchMap *patch_map);
+
+ ~EvalOutputAPI();
// Set coarse positions from a continuous array of coordinates.
void setCoarsePositions(const float *positions,
@@ -130,9 +137,47 @@ class CpuEvalOutputAPI {
float *dPdu,
float *dPdv);
+ // Fill the output buffers and variables with data from the PatchMap.
+ void getPatchMap(OpenSubdiv_Buffer *patch_map_handles,
+ OpenSubdiv_Buffer *patch_map_quadtree,
+ int *min_patch_face,
+ int *max_patch_face,
+ int *max_depth,
+ int *patches_are_triangular);
+
+ // Copy the patch arrays buffer used by OpenSubDiv for the source data to the given buffer.
+ void fillPatchArraysBuffer(OpenSubdiv_Buffer *patch_arrays_buffer);
+
+ // Wrap the patch index buffer used by OpenSubDiv for the source data with the given buffer.
+ void wrapPatchIndexBuffer(OpenSubdiv_Buffer *patch_index_buffer);
+
+ // Wrap the patch param buffer used by OpenSubDiv for the source data with the given buffer.
+ void wrapPatchParamBuffer(OpenSubdiv_Buffer *patch_param_buffer);
+
+ // Wrap the buffer used by OpenSubDiv for the source data with the given buffer.
+ void wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer);
+
+ // Copy the patch arrays buffer used by OpenSubDiv for the face varying channel with the given
+ // buffer.
+ void fillFVarPatchArraysBuffer(const int face_varying_channel,
+ OpenSubdiv_Buffer *patch_arrays_buffer);
+
+ // Wrap the patch index buffer used by OpenSubDiv for the face varying channel with the given
+ // buffer.
+ void wrapFVarPatchIndexBuffer(const int face_varying_channel,
+ OpenSubdiv_Buffer *patch_index_buffer);
+
+ // Wrap the patch param buffer used by OpenSubDiv for the face varying channel with the given
+ // buffer.
+ void wrapFVarPatchParamBuffer(const int face_varying_channel,
+ OpenSubdiv_Buffer *patch_param_buffer);
+
+ // Wrap thebuffer used by OpenSubDiv for the face varying channel with the given buffer.
+ void wrapFVarSrcBuffer(const int face_varying_channel, OpenSubdiv_Buffer *src_buffer);
+
protected:
- CpuEvalOutput *implementation_;
- OpenSubdiv::Far::PatchMap *patch_map_;
+ PatchMap *patch_map_;
+ EvalOutput *implementation_;
};
} // namespace opensubdiv
@@ -143,15 +188,17 @@ struct OpenSubdiv_EvaluatorImpl {
OpenSubdiv_EvaluatorImpl();
~OpenSubdiv_EvaluatorImpl();
- blender::opensubdiv::CpuEvalOutputAPI *eval_output;
- const OpenSubdiv::Far::PatchMap *patch_map;
+ blender::opensubdiv::EvalOutputAPI *eval_output;
+ const blender::opensubdiv::PatchMap *patch_map;
const OpenSubdiv::Far::PatchTable *patch_table;
MEM_CXX_CLASS_ALLOC_FUNCS("OpenSubdiv_EvaluatorImpl");
};
OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
- struct OpenSubdiv_TopologyRefiner *topology_refiner);
+ struct OpenSubdiv_TopologyRefiner *topology_refiner,
+ eOpenSubdivEvaluator evaluator_type,
+ OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr);
void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorImpl *evaluator);
diff --git a/intern/opensubdiv/internal/evaluator/patch_map.cc b/intern/opensubdiv/internal/evaluator/patch_map.cc
new file mode 100644
index 00000000000..1b10c1118b9
--- /dev/null
+++ b/intern/opensubdiv/internal/evaluator/patch_map.cc
@@ -0,0 +1,213 @@
+// Original code copyright 2013 Pixar.
+//
+// Licensed under the Apache License, Version 2.0 (the "Apache License")
+// with the following modification; you may not use this file except in
+// compliance with the Apache License and the following modification to it:
+// Section 6. Trademarks. is deleted and replaced with:
+//
+// 6. Trademarks. This License does not grant permission to use the trade
+// names, trademarks, service marks, or product names of the Licensor
+// and its affiliates, except as required to comply with Section 4(c) of
+// the License and to reproduce the content of the NOTICE file.
+//
+// You may obtain a copy of the Apache License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the Apache License with the above modification is
+// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the Apache License for the specific
+// language governing permissions and limitations under the Apache License.
+//
+// Modifications copyright 2021 Blender Foundation. All rights reserved.
+
+#include "internal/evaluator/patch_map.h"
+#include <algorithm>
+
+using OpenSubdiv::Far::ConstPatchParamArray;
+using OpenSubdiv::Far::Index;
+using OpenSubdiv::Far::PatchParam;
+using OpenSubdiv::Far::PatchParamTable;
+using OpenSubdiv::Far::PatchTable;
+
+namespace blender {
+namespace opensubdiv {
+
+//
+// Inline quadtree assembly methods used by the constructor:
+//
+
+// sets all the children to point to the patch of given index
+inline void PatchMap::QuadNode::SetChildren(int index)
+{
+
+ for (int i = 0; i < 4; ++i) {
+ children[i].isSet = true;
+ children[i].isLeaf = true;
+ children[i].index = index;
+ }
+}
+
+// sets the child in "quadrant" to point to the node or patch of the given index
+inline void PatchMap::QuadNode::SetChild(int quadrant, int index, bool isLeaf)
+{
+
+ assert(!children[quadrant].isSet);
+ children[quadrant].isSet = true;
+ children[quadrant].isLeaf = isLeaf;
+ children[quadrant].index = index;
+}
+
+inline void PatchMap::assignRootNode(QuadNode *node, int index)
+{
+
+ // Assign the given index to all children of the node (all leaves)
+ node->SetChildren(index);
+}
+
+inline PatchMap::QuadNode *PatchMap::assignLeafOrChildNode(QuadNode *node,
+ bool isLeaf,
+ int quadrant,
+ int index)
+{
+
+ // Assign the node given if it is a leaf node, otherwise traverse
+ // the node -- creating/assigning a new child node if needed
+
+ if (isLeaf) {
+ node->SetChild(quadrant, index, true);
+ return node;
+ }
+ if (node->children[quadrant].isSet) {
+ return &_quadtree[node->children[quadrant].index];
+ }
+ else {
+ int newChildNodeIndex = (int)_quadtree.size();
+ _quadtree.push_back(QuadNode());
+ node->SetChild(quadrant, newChildNodeIndex, false);
+ return &_quadtree[newChildNodeIndex];
+ }
+}
+
+//
+// Constructor and initialization methods for the handles and quadtree:
+//
+PatchMap::PatchMap(PatchTable const &patchTable)
+ : _minPatchFace(-1), _maxPatchFace(-1), _maxDepth(0)
+{
+
+ _patchesAreTriangular = patchTable.GetVaryingPatchDescriptor().GetNumControlVertices() == 3;
+
+ if (patchTable.GetNumPatchesTotal() > 0) {
+ initializeHandles(patchTable);
+ initializeQuadtree(patchTable);
+ }
+}
+
+void PatchMap::initializeHandles(PatchTable const &patchTable)
+{
+
+ //
+ // Populate the vector of patch Handles. Keep track of the min and max
+ // face indices to allocate resources accordingly and limit queries:
+ //
+ _minPatchFace = (int)patchTable.GetPatchParamTable()[0].GetFaceId();
+ _maxPatchFace = _minPatchFace;
+
+ int numArrays = (int)patchTable.GetNumPatchArrays();
+ int numPatches = (int)patchTable.GetNumPatchesTotal();
+
+ _handles.resize(numPatches);
+
+ for (int pArray = 0, handleIndex = 0; pArray < numArrays; ++pArray) {
+
+ ConstPatchParamArray params = patchTable.GetPatchParams(pArray);
+
+ int patchSize = patchTable.GetPatchArrayDescriptor(pArray).GetNumControlVertices();
+
+ for (Index j = 0; j < patchTable.GetNumPatches(pArray); ++j, ++handleIndex) {
+
+ Handle &h = _handles[handleIndex];
+
+ h.arrayIndex = pArray;
+ h.patchIndex = handleIndex;
+ h.vertIndex = j * patchSize;
+
+ int patchFaceId = params[j].GetFaceId();
+ _minPatchFace = std::min(_minPatchFace, patchFaceId);
+ _maxPatchFace = std::max(_maxPatchFace, patchFaceId);
+ }
+ }
+}
+
+void PatchMap::initializeQuadtree(PatchTable const &patchTable)
+{
+
+ //
+ // Reserve quadtree nodes for the worst case and prune later. Set the
+ // initial size to accomodate the root node of each patch face:
+ //
+ int nPatchFaces = (_maxPatchFace - _minPatchFace) + 1;
+
+ int nHandles = (int)_handles.size();
+
+ _quadtree.reserve(nPatchFaces + nHandles);
+ _quadtree.resize(nPatchFaces);
+
+ PatchParamTable const &params = patchTable.GetPatchParamTable();
+
+ for (int handle = 0; handle < nHandles; ++handle) {
+
+ PatchParam const &param = params[handle];
+
+ int depth = param.GetDepth();
+ int rootDepth = param.NonQuadRoot();
+
+ _maxDepth = std::max(_maxDepth, depth);
+
+ QuadNode *node = &_quadtree[param.GetFaceId() - _minPatchFace];
+
+ if (depth == rootDepth) {
+ assignRootNode(node, handle);
+ continue;
+ }
+
+ if (!_patchesAreTriangular) {
+ // Use the UV bits of the PatchParam directly for quad patches:
+ int u = param.GetU();
+ int v = param.GetV();
+
+ for (int j = rootDepth + 1; j <= depth; ++j) {
+ int uBit = (u >> (depth - j)) & 1;
+ int vBit = (v >> (depth - j)) & 1;
+
+ int quadrant = (vBit << 1) | uBit;
+
+ node = assignLeafOrChildNode(node, (j == depth), quadrant, handle);
+ }
+ }
+ else {
+ // Use an interior UV point of triangles to identify quadrants:
+ double u = 0.25;
+ double v = 0.25;
+ param.UnnormalizeTriangle(u, v);
+
+ double median = 0.5;
+ bool triRotated = false;
+
+ for (int j = rootDepth + 1; j <= depth; ++j, median *= 0.5) {
+ int quadrant = transformUVToTriQuadrant(median, u, v, triRotated);
+
+ node = assignLeafOrChildNode(node, (j == depth), quadrant, handle);
+ }
+ }
+ }
+
+ // Swap the Node vector with a copy to reduce worst case memory allocation:
+ QuadTree tmpTree = _quadtree;
+ _quadtree.swap(tmpTree);
+}
+
+} // namespace opensubdiv
+} // namespace blender
diff --git a/intern/opensubdiv/internal/evaluator/patch_map.h b/intern/opensubdiv/internal/evaluator/patch_map.h
new file mode 100644
index 00000000000..af804d6ca71
--- /dev/null
+++ b/intern/opensubdiv/internal/evaluator/patch_map.h
@@ -0,0 +1,264 @@
+// Original code copyright 2013 Pixar.
+//
+// Licensed under the Apache License, Version 2.0 (the "Apache License")
+// with the following modification; you may not use this file except in
+// compliance with the Apache License and the following modification to it:
+// Section 6. Trademarks. is deleted and replaced with:
+//
+// 6. Trademarks. This License does not grant permission to use the trade
+// names, trademarks, service marks, or product names of the Licensor
+// and its affiliates, except as required to comply with Section 4(c) of
+// the License and to reproduce the content of the NOTICE file.
+//
+// You may obtain a copy of the Apache License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the Apache License with the above modification is
+// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the Apache License for the specific
+// language governing permissions and limitations under the Apache License.
+//
+// Modifications copyright 2021 Blender Foundation. All rights reserved.
+
+#ifndef OPENSUBDIV_PATCH_MAP_H_
+#define OPENSUBDIV_PATCH_MAP_H_
+
+#include <opensubdiv/far/patchTable.h>
+
+namespace blender {
+namespace opensubdiv {
+
+/// \brief An quadtree-based map connecting coarse faces to their sub-patches
+///
+/// PatchTable::PatchArrays contain lists of patches that represent the limit
+/// surface of a mesh, sorted by their topological type. These arrays break the
+/// connection between coarse faces and their sub-patches.
+///
+/// The PatchMap provides a quad-tree based lookup structure that, given a singular
+/// parametric location, can efficiently return a handle to the sub-patch that
+/// contains this location.
+///
+class PatchMap {
+ public:
+ // Quadtree node with 4 children, tree is just a vector of nodes
+ struct QuadNode {
+ QuadNode()
+ {
+ std::memset(this, 0, sizeof(QuadNode));
+ }
+
+ struct Child {
+ unsigned int isSet : 1; // true if the child has been set
+ unsigned int isLeaf : 1; // true if the child is a QuadNode
+ unsigned int index : 30; // child index (either QuadNode or Handle)
+ };
+
+ // sets all the children to point to the patch of given index
+ void SetChildren(int index);
+
+ // sets the child in "quadrant" to point to the node or patch of the given index
+ void SetChild(int quadrant, int index, bool isLeaf);
+
+ Child children[4];
+ };
+
+ typedef OpenSubdiv::Far::PatchTable::PatchHandle Handle;
+
+ /// \brief Constructor
+ ///
+ /// @param patchTable A valid PatchTable
+ ///
+ PatchMap(OpenSubdiv::Far::PatchTable const &patchTable);
+
+ /// \brief Returns a handle to the sub-patch of the face at the given (u,v).
+ /// Note that the patch face ID corresponds to potentially quadrangulated
+ /// face indices and not the base face indices (see Far::PtexIndices for more
+ /// details).
+ ///
+ /// @param patchFaceId The index of the patch (Ptex) face
+ ///
+ /// @param u Local u parameter
+ ///
+ /// @param v Local v parameter
+ ///
+ /// @return A patch handle or 0 if the face is not supported (index
+ /// out of bounds) or is tagged as a hole
+ ///
+ Handle const *FindPatch(int patchFaceId, double u, double v) const;
+
+ int getMinPatchFace() const
+ {
+ return _minPatchFace;
+ }
+
+ int getMaxPatchFace() const
+ {
+ return _maxPatchFace;
+ }
+
+ int getMaxDepth() const
+ {
+ return _maxDepth;
+ }
+
+ bool getPatchesAreTriangular() const
+ {
+ return _patchesAreTriangular;
+ }
+
+ const std::vector<Handle> &getHandles()
+ {
+ return _handles;
+ }
+
+ const std::vector<QuadNode> &nodes()
+ {
+ return _quadtree;
+ }
+
+ private:
+ void initializeHandles(OpenSubdiv::Far::PatchTable const &patchTable);
+ void initializeQuadtree(OpenSubdiv::Far::PatchTable const &patchTable);
+
+ typedef std::vector<QuadNode> QuadTree;
+
+ // Internal methods supporting quadtree construction and queries
+ void assignRootNode(QuadNode *node, int index);
+ QuadNode *assignLeafOrChildNode(QuadNode *node, bool isLeaf, int quad, int index);
+
+ template<class T> static int transformUVToQuadQuadrant(T const &median, T &u, T &v);
+ template<class T>
+ static int transformUVToTriQuadrant(T const &median, T &u, T &v, bool &rotated);
+
+ private:
+ bool _patchesAreTriangular; // tri and quad assembly and search requirements differ
+
+ int _minPatchFace; // minimum patch face index supported by the map
+ int _maxPatchFace; // maximum patch face index supported by the map
+ int _maxDepth; // maximum depth of a patch in the tree
+
+ std::vector<Handle> _handles; // all the patches in the PatchTable
+ std::vector<QuadNode> _quadtree; // quadtree nodes
+};
+
+//
+// Given a median value for both U and V, these methods transform a (u,v) pair
+// into the quadrant that contains them and returns the quadrant index.
+//
+// Quadrant indexing for tri and quad patches -- consistent with PatchParam's
+// usage of UV bits:
+//
+// (0,1) o-----o-----o (1,1) (0,1) o (1,0) o-----o-----o (0,0)
+// | | | |\ \ 1 |\ 0 |
+// | 2 | 3 | | \ \ | \ |
+// | | | | 2 \ \| 3 \|
+// o-----o-----o o-----o o-----o
+// | | | |\ 3 |\ \ 2 |
+// | 0 | 1 | | \ | \ \ |
+// | | | | 0 \| 1 \ \|
+// (0,0) o-----o-----o (1,0) (0,0) o-----o-----o (1,0) o (0,1)
+//
+// The triangular case also takes and returns/affects the rotation of the
+// quadrant being searched and identified (quadrant 3 imparts a rotation).
+//
+template<class T> inline int PatchMap::transformUVToQuadQuadrant(T const &median, T &u, T &v)
+{
+
+ int uHalf = (u >= median);
+ if (uHalf)
+ u -= median;
+
+ int vHalf = (v >= median);
+ if (vHalf)
+ v -= median;
+
+ return (vHalf << 1) | uHalf;
+}
+
+template<class T>
+int inline PatchMap::transformUVToTriQuadrant(T const &median, T &u, T &v, bool &rotated)
+{
+
+ if (!rotated) {
+ if (u >= median) {
+ u -= median;
+ return 1;
+ }
+ if (v >= median) {
+ v -= median;
+ return 2;
+ }
+ if ((u + v) >= median) {
+ rotated = true;
+ return 3;
+ }
+ return 0;
+ }
+ else {
+ if (u < median) {
+ v -= median;
+ return 1;
+ }
+ if (v < median) {
+ u -= median;
+ return 2;
+ }
+ u -= median;
+ v -= median;
+ if ((u + v) < median) {
+ rotated = false;
+ return 3;
+ }
+ return 0;
+ }
+}
+
+/// Returns a handle to the sub-patch of the face at the given (u,v).
+inline PatchMap::Handle const *PatchMap::FindPatch(int faceid, double u, double v) const
+{
+
+ //
+ // Reject patch faces not supported by this map, or those corresponding
+ // to holes or otherwise unassigned (the root node for a patch will
+ // have all or no quadrants set):
+ //
+ if ((faceid < _minPatchFace) || (faceid > _maxPatchFace))
+ return 0;
+
+ QuadNode const *node = &_quadtree[faceid - _minPatchFace];
+
+ if (!node->children[0].isSet)
+ return 0;
+
+ //
+ // Search the tree for the sub-patch containing the given (u,v)
+ //
+ assert((u >= 0.0) && (u <= 1.0) && (v >= 0.0) && (v <= 1.0));
+
+ double median = 0.5;
+ bool triRotated = false;
+
+ for (int depth = 0; depth <= _maxDepth; ++depth, median *= 0.5) {
+
+ int quadrant = _patchesAreTriangular ? transformUVToTriQuadrant(median, u, v, triRotated) :
+ transformUVToQuadQuadrant(median, u, v);
+
+ // holes should have been rejected at the root node of the face
+ assert(node->children[quadrant].isSet);
+
+ if (node->children[quadrant].isLeaf) {
+ return &_handles[node->children[quadrant].index];
+ }
+ else {
+ node = &_quadtree[node->children[quadrant].index];
+ }
+ }
+ assert(0);
+ return 0;
+}
+} // namespace opensubdiv
+} // namespace blender
+
+#endif // OPENSUBDIV_PATCH_MAP_H_
diff --git a/intern/opensubdiv/internal/topology/mesh_topology.cc b/intern/opensubdiv/internal/topology/mesh_topology.cc
index 29c387876ef..461a85fbdfb 100644
--- a/intern/opensubdiv/internal/topology/mesh_topology.cc
+++ b/intern/opensubdiv/internal/topology/mesh_topology.cc
@@ -183,7 +183,7 @@ void MeshTopology::setNumFaces(int num_faces)
num_faces_ = num_faces;
// NOTE: Extra element to store fake face past the last real one to make it
- // possible to calculate number of verticies in the last face.
+ // possible to calculate number of vertices in the last face.
faces_first_vertex_index_.resize(num_faces + 1, 0);
}
diff --git a/intern/opensubdiv/internal/topology/mesh_topology.h b/intern/opensubdiv/internal/topology/mesh_topology.h
index 861614482ef..a2fad890d9d 100644
--- a/intern/opensubdiv/internal/topology/mesh_topology.h
+++ b/intern/opensubdiv/internal/topology/mesh_topology.h
@@ -111,7 +111,7 @@ class MeshTopology {
// Pipeline related.
// This function is to be called when number of vertices, edges, faces, and
- // face-verticies are known.
+ // face-vertices are known.
//
// Usually is called from the end of topology refiner factory's
// resizeComponentTopology().
@@ -162,7 +162,7 @@ class MeshTopology {
int num_faces_;
- // Continuous array of all verticies of all faces:
+ // Continuous array of all vertices of all faces:
// [vertex indices of face 0][vertex indices of face 1] .. [vertex indices of face n].
vector<int> face_vertex_indices_;
diff --git a/intern/opensubdiv/internal/topology/topology_refiner_capi.cc b/intern/opensubdiv/internal/topology/topology_refiner_capi.cc
index b30d509be20..547ea190837 100644
--- a/intern/opensubdiv/internal/topology/topology_refiner_capi.cc
+++ b/intern/opensubdiv/internal/topology/topology_refiner_capi.cc
@@ -225,7 +225,7 @@ void assignFunctionPointers(OpenSubdiv_TopologyRefiner *topology_refiner)
OpenSubdiv_TopologyRefiner *allocateTopologyRefiner()
{
- OpenSubdiv_TopologyRefiner *topology_refiner = OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefiner);
+ OpenSubdiv_TopologyRefiner *topology_refiner = MEM_new<OpenSubdiv_TopologyRefiner>(__func__);
assignFunctionPointers(topology_refiner);
return topology_refiner;
}
@@ -252,7 +252,7 @@ OpenSubdiv_TopologyRefiner *openSubdiv_createTopologyRefinerFromConverter(
void openSubdiv_deleteTopologyRefiner(OpenSubdiv_TopologyRefiner *topology_refiner)
{
delete topology_refiner->impl;
- OBJECT_GUARDED_DELETE(topology_refiner, OpenSubdiv_TopologyRefiner);
+ MEM_delete(topology_refiner);
}
bool openSubdiv_topologyRefinerCompareWithConverter(
diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h
index 6f914a20bf5..164a6dfeb03 100644
--- a/intern/opensubdiv/opensubdiv_converter_capi.h
+++ b/intern/opensubdiv/opensubdiv_converter_capi.h
@@ -135,7 +135,7 @@ typedef struct OpenSubdiv_Converter {
// specified in precalcUVLayer().
int (*getNumUVCoordinates)(const struct OpenSubdiv_Converter *converter);
// For the given face index and its corner (known as loop in Blender)
- // get corrsponding UV coordinate index.
+ // get corresponding UV coordinate index.
int (*getFaceCornerUVIndex)(const struct OpenSubdiv_Converter *converter,
const int face_index,
const int corner_index);
diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.h b/intern/opensubdiv/opensubdiv_evaluator_capi.h
index b860ae8db2e..1afd3e966f6 100644
--- a/intern/opensubdiv/opensubdiv_evaluator_capi.h
+++ b/intern/opensubdiv/opensubdiv_evaluator_capi.h
@@ -19,6 +19,10 @@
#ifndef OPENSUBDIV_EVALUATOR_CAPI_H_
#define OPENSUBDIV_EVALUATOR_CAPI_H_
+#include <stdint.h> // for uint64_t
+
+#include "opensubdiv_capi_type.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -27,6 +31,38 @@ struct OpenSubdiv_EvaluatorInternal;
struct OpenSubdiv_PatchCoord;
struct OpenSubdiv_TopologyRefiner;
+// Callback type for doing input/output operations on buffers.
+// Useful to abstract GPU buffers.
+typedef struct OpenSubdiv_Buffer {
+ // Bind the buffer to the GPU.
+ void (*bind_gpu)(const struct OpenSubdiv_Buffer *buffer);
+
+ // Allocate the buffer directly on the host for the given size in bytes. This has to return
+ // a pointer to the newly allocated memory.
+ void *(*alloc)(const struct OpenSubdiv_Buffer *buffer, const unsigned int size);
+
+ // Allocate the buffer directly on the device for the given size in bytes.
+ void (*device_alloc)(const struct OpenSubdiv_Buffer *buffer, const unsigned int size);
+
+ // Update the given range of the buffer with new data.
+ void (*device_update)(const struct OpenSubdiv_Buffer *buffer,
+ unsigned int start,
+ unsigned int len,
+ const void *data);
+
+ // Wrap an existing GPU buffer, given its device handle, into the client's buffer type for
+ // read-only use.
+ void (*wrap_device_handle)(const struct OpenSubdiv_Buffer *buffer, uint64_t device_ptr);
+
+ // Offset in the buffer where the data starts, if a single buffer is used for multiple data
+ // channels.
+ int buffer_offset;
+
+ // Pointer to the client buffer data, which is modified or initialized through the various
+ // callbacks.
+ void *data;
+} OpenSubdiv_Buffer;
+
typedef struct OpenSubdiv_Evaluator {
// Set coarse positions from a continuous array of coordinates.
void (*setCoarsePositions)(struct OpenSubdiv_Evaluator *evaluator,
@@ -122,15 +158,78 @@ typedef struct OpenSubdiv_Evaluator {
float *dPdu,
float *dPdv);
+ // Copy the patch map to the given buffers, and output some topology information.
+ void (*getPatchMap)(struct OpenSubdiv_Evaluator *evaluator,
+ struct OpenSubdiv_Buffer *patch_map_handles,
+ struct OpenSubdiv_Buffer *patch_map_quadtree,
+ int *min_patch_face,
+ int *max_patch_face,
+ int *max_depth,
+ int *patches_are_triangular);
+
+ // Fill the given buffer with data from the evaluator's patch array buffer.
+ void (*fillPatchArraysBuffer)(struct OpenSubdiv_Evaluator *evaluator,
+ struct OpenSubdiv_Buffer *patch_array_buffer);
+
+ // Fill the given buffer with data from the evaluator's patch index buffer.
+ void (*wrapPatchIndexBuffer)(struct OpenSubdiv_Evaluator *evaluator,
+ struct OpenSubdiv_Buffer *patch_index_buffer);
+
+ // Fill the given buffer with data from the evaluator's patch parameter buffer.
+ void (*wrapPatchParamBuffer)(struct OpenSubdiv_Evaluator *evaluator,
+ struct OpenSubdiv_Buffer *patch_param_buffer);
+
+ // Fill the given buffer with data from the evaluator's source buffer.
+ void (*wrapSrcBuffer)(struct OpenSubdiv_Evaluator *evaluator,
+ struct OpenSubdiv_Buffer *src_buffer);
+
+ // Fill the given buffer with data from the evaluator's face varying patch array buffer.
+ void (*fillFVarPatchArraysBuffer)(struct OpenSubdiv_Evaluator *evaluator,
+ const int face_varying_channel,
+ struct OpenSubdiv_Buffer *patch_array_buffer);
+
+ // Fill the given buffer with data from the evaluator's face varying patch index buffer.
+ void (*wrapFVarPatchIndexBuffer)(struct OpenSubdiv_Evaluator *evaluator,
+ const int face_varying_channel,
+ struct OpenSubdiv_Buffer *patch_index_buffer);
+
+ // Fill the given buffer with data from the evaluator's face varying patch parameter buffer.
+ void (*wrapFVarPatchParamBuffer)(struct OpenSubdiv_Evaluator *evaluator,
+ const int face_varying_channel,
+ struct OpenSubdiv_Buffer *patch_param_buffer);
+
+ // Fill the given buffer with data from the evaluator's face varying source buffer.
+ void (*wrapFVarSrcBuffer)(struct OpenSubdiv_Evaluator *evaluator,
+ const int face_varying_channel,
+ struct OpenSubdiv_Buffer *src_buffer);
+
// Implementation of the evaluator.
struct OpenSubdiv_EvaluatorImpl *impl;
+
+ // Type of the evaluator.
+ eOpenSubdivEvaluator type;
} OpenSubdiv_Evaluator;
+typedef struct OpenSubdiv_EvaluatorCache {
+ // Implementation of the evaluator cache.
+ struct OpenSubdiv_EvaluatorCacheImpl *impl;
+} OpenSubdiv_EvaluatorCache;
+
OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
- struct OpenSubdiv_TopologyRefiner *topology_refiner);
+ struct OpenSubdiv_TopologyRefiner *topology_refiner,
+ eOpenSubdivEvaluator evaluator_type,
+ OpenSubdiv_EvaluatorCache *evaluator_cache);
void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator *evaluator);
+OpenSubdiv_EvaluatorCache *openSubdiv_createEvaluatorCache(eOpenSubdivEvaluator evaluator_type);
+
+void openSubdiv_deleteEvaluatorCache(OpenSubdiv_EvaluatorCache *evaluator_cache);
+
+// Return the GLSL source code from the OpenSubDiv library used for patch evaluation.
+// This function is not thread-safe.
+const char *openSubdiv_getGLSLPatchBasisSource(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc b/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc
index b7c19bf4f9b..bc39326b57d 100644
--- a/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc
+++ b/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc
@@ -21,7 +21,9 @@
#include <cstddef>
OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
- struct OpenSubdiv_TopologyRefiner * /*topology_refiner*/)
+ struct OpenSubdiv_TopologyRefiner * /*topology_refiner*/,
+ eOpenSubdivEvaluator /*evaluator_type*/,
+ OpenSubdiv_EvaluatorCache * /*evaluator_cache*/)
{
return NULL;
}
@@ -29,3 +31,17 @@ OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator * /*evaluator*/)
{
}
+
+OpenSubdiv_EvaluatorCache *openSubdiv_createEvaluatorCache(eOpenSubdivEvaluator /*evaluator_type*/)
+{
+ return NULL;
+}
+
+void openSubdiv_deleteEvaluatorCache(OpenSubdiv_EvaluatorCache * /*evaluator_cache*/)
+{
+}
+
+const char *openSubdiv_getGLSLPatchBasisSource()
+{
+ return NULL;
+}
diff --git a/intern/utfconv/utfconv.c b/intern/utfconv/utfconv.c
index 00094b84042..673c567070c 100644
--- a/intern/utfconv/utfconv.c
+++ b/intern/utfconv/utfconv.c
@@ -56,7 +56,7 @@ size_t count_utf_8_from_16(const wchar_t *string16)
}
else {
if (u < 0xE000) {
- /*illigal*/;
+ /*illegal*/;
}
else {
count += 3;
diff --git a/release/datafiles/fonts/droidsans.ttf b/release/datafiles/fonts/droidsans.ttf
index eea72f53ccd..b03e47f087e 100644
--- a/release/datafiles/fonts/droidsans.ttf
+++ b/release/datafiles/fonts/droidsans.ttf
Binary files differ
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 9d270fd007f628b23ccbcbd87caa2dc35286b26
+Subproject 620b85f16d03a6aadd7cae56969c9c29b06b992
diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c
index 3cbc6b26b4a..94d8c13aa06 100644
--- a/release/datafiles/userdef/userdef_default.c
+++ b/release/datafiles/userdef/userdef_default.c
@@ -61,7 +61,7 @@ const UserDef U_default = {
USER_HIDE_DOT | USER_SHOW_GIZMO_NAVIGATE | USER_SHOW_VIEWPORTNAME | USER_SHOW_FPS |
USER_CONTINUOUS_MOUSE | USER_SAVE_PROMPT),
.uiflag2 = USER_REGION_OVERLAP,
- .gpu_flag = USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE,
+ .gpu_flag = USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE | USER_GPU_FLAG_SUBDIVISION_EVALUATION,
.app_flag = 0,
/** Default language of English (1), not Automatic (0). */
.language = 1,
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject b3c179b2869d86c44a4b29e2c638ce2a596a820
+Subproject c08568cc376d2e4298710c4172fb0c74f0611de
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject 16467648282500cc229c271f62201ef897f2c2c
+Subproject 7936dde9ece881d531b1a2ee6c45ddb56d30038
diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py
index ac932fe38dc..bdc345ee50a 100644
--- a/release/scripts/modules/bl_i18n_utils/settings.py
+++ b/release/scripts/modules/bl_i18n_utils/settings.py
@@ -100,6 +100,7 @@ LANGUAGES = (
(45, "Abkhaz (Аԥсуа бызшәа)", "ab"),
(46, "Thai (ภาษาไทย)", "th_TH"),
(47, "Slovak (Slovenčina)", "sk_SK"),
+ (48, "Georgian (ქართული)", "ka"),
)
# Default context, in py (keep in sync with `BLT_translation.h`)!
diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py
index e13eb15dfd2..2e0113051a5 100644
--- a/release/scripts/modules/bl_i18n_utils/utils.py
+++ b/release/scripts/modules/bl_i18n_utils/utils.py
@@ -1135,6 +1135,7 @@ class I18nMessages:
# XXX Temp solution, until I can make own mo generator working...
import subprocess
with tempfile.NamedTemporaryFile(mode='w+', encoding="utf-8") as tmp_po_f:
+ os.makedirs(os.path.dirname(fname), exist_ok=True)
self.write_messages_to_po(tmp_po_f)
cmd = (
self.settings.GETTEXT_MSGFMT_EXECUTABLE,
diff --git a/release/scripts/modules/rna_manual_reference.py b/release/scripts/modules/rna_manual_reference.py
index 33ce674c672..2983a326358 100644
--- a/release/scripts/modules/rna_manual_reference.py
+++ b/release/scripts/modules/rna_manual_reference.py
@@ -46,18 +46,21 @@ url_manual_mapping = (
("bpy.types.fluiddomainsettings.sndparticle_potential_min_trappedair*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-min-trappedair"),
("bpy.types.fluiddomainsettings.sndparticle_potential_max_wavecrest*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-max-wavecrest"),
("bpy.types.fluiddomainsettings.sndparticle_potential_min_wavecrest*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-min-wavecrest"),
+ ("bpy.types.lineartgpencilmodifier.use_offset_towards_custom_camera*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-offset-towards-custom-camera"),
("bpy.types.movietrackingsettings.refine_intrinsics_principal_point*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-refine-intrinsics-principal-point"),
("bpy.types.cyclesobjectsettings.shadow_terminator_geometry_offset*", "render/cycles/object_settings/object_data.html#bpy-types-cyclesobjectsettings-shadow-terminator-geometry-offset"),
("bpy.types.cyclesrenderlayersettings.denoising_optix_input_passes*", "render/layers/denoising.html#bpy-types-cyclesrenderlayersettings-denoising-optix-input-passes"),
("bpy.types.sequencertoolsettings.use_snap_current_frame_to_strips*", "video_editing/sequencer/editing.html#bpy-types-sequencertoolsettings-use-snap-current-frame-to-strips"),
("bpy.types.fluiddomainsettings.sndparticle_potential_max_energy*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-max-energy"),
("bpy.types.fluiddomainsettings.sndparticle_potential_min_energy*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-min-energy"),
+ ("bpy.types.lineartgpencilmodifier.use_overlap_edge_type_support*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-overlap-edge-type-support"),
("bpy.types.movietrackingsettings.refine_intrinsics_focal_length*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-refine-intrinsics-focal-length"),
("bpy.types.rigidbodyconstraint.rigidbodyconstraint.use_breaking*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-rigidbodyconstraint-use-breaking"),
("bpy.types.cyclesrendersettings.preview_denoising_input_passes*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-preview-denoising-input-passes"),
("bpy.types.cyclesrendersettings.preview_denoising_start_sample*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-preview-denoising-start-sample"),
("bpy.types.fluiddomainsettings.sndparticle_sampling_trappedair*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-sampling-trappedair"),
("bpy.types.fluiddomainsettings.sndparticle_sampling_wavecrest*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-sampling-wavecrest"),
+ ("bpy.types.lineartgpencilmodifier.use_image_boundary_trimming*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-image-boundary-trimming"),
("bpy.types.rigidbodyconstraint.use_override_solver_iterations*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-use-override-solver-iterations"),
("bpy.types.toolsettings.use_transform_correct_face_attributes*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-transform-correct-face-attributes"),
("bpy.types.cyclesrendersettings.adaptive_scrambling_distance*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-adaptive-scrambling-distance"),
@@ -67,6 +70,7 @@ url_manual_mapping = (
("bpy.types.cyclesrendersettings.preview_denoising_prefilter*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-preview-denoising-prefilter"),
("bpy.types.cyclesrendersettings.preview_scrambling_distance*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-preview-scrambling-distance"),
("bpy.types.fluiddomainsettings.sndparticle_potential_radius*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-radius"),
+ ("bpy.types.brushgpencilsettings.use_stroke_random_strength*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-stroke-random-strength"),
("bpy.types.cyclesrendersettings.film_transparent_roughness*", "render/cycles/render_settings/film.html#bpy-types-cyclesrendersettings-film-transparent-roughness"),
("bpy.types.cyclesrendersettings.preview_adaptive_threshold*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-preview-adaptive-threshold"),
("bpy.types.fluiddomainsettings.openvdb_cache_compress_type*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-openvdb-cache-compress-type"),
@@ -74,13 +78,19 @@ url_manual_mapping = (
("bpy.types.fluiddomainsettings.sndparticle_combined_export*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-combined-export"),
("bpy.types.fluiddomainsettings.use_collision_border_bottom*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-bottom"),
("bpy.types.fluiddomainsettings.vector_scale_with_magnitude*", "physics/fluid/type/domain/gas/viewport_display.html#bpy-types-fluiddomainsettings-vector-scale-with-magnitude"),
+ ("bpy.types.lineartgpencilmodifier.use_face_mark_boundaries*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-face-mark-boundaries"),
("bpy.types.movietrackingstabilization.use_2d_stabilization*", "movie_clip/tracking/clip/sidebar/stabilization/panel.html#bpy-types-movietrackingstabilization-use-2d-stabilization"),
("bpy.types.spacespreadsheet.display_context_path_collapsed*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-display-context-path-collapsed"),
("bpy.types.toolsettings.annotation_stroke_placement_view2d*", "interface/annotate_tool.html#bpy-types-toolsettings-annotation-stroke-placement-view2d"),
("bpy.types.toolsettings.annotation_stroke_placement_view3d*", "interface/annotate_tool.html#bpy-types-toolsettings-annotation-stroke-placement-view3d"),
+ ("bpy.types.brushgpencilsettings.use_random_press_strength*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-random-press-strength"),
("bpy.types.fluiddomainsettings.use_collision_border_front*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-front"),
("bpy.types.fluiddomainsettings.use_collision_border_right*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-right"),
("bpy.types.sequencertimelineoverlay.waveform_display_type*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-waveform-display-type"),
+ ("bpy.types.view3doverlay.use_normals_constant_screen_size*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-use-normals-constant-screen-size"),
+ ("bpy.types.brushgpencilsettings.random_saturation_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-random-saturation-factor"),
+ ("bpy.types.brushgpencilsettings.use_settings_postprocess*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-settings-postprocess"),
+ ("bpy.types.brushgpencilsettings.use_stroke_random_radius*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-stroke-random-radius"),
("bpy.types.cyclesmaterialsettings.use_transparent_shadow*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-use-transparent-shadow"),
("bpy.types.cyclesobjectsettings.shadow_terminator_offset*", "render/cycles/object_settings/object_data.html#bpy-types-cyclesobjectsettings-shadow-terminator-offset"),
("bpy.types.cyclesobjectsettings.use_adaptive_subdivision*", "render/cycles/object_settings/adaptive_subdiv.html#bpy-types-cyclesobjectsettings-use-adaptive-subdivision"),
@@ -91,28 +101,44 @@ url_manual_mapping = (
("bpy.types.fluiddomainsettings.sndparticle_update_radius*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-update-radius"),
("bpy.types.fluiddomainsettings.use_collision_border_back*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-back"),
("bpy.types.fluiddomainsettings.use_collision_border_left*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-left"),
+ ("bpy.types.lineartgpencilmodifier.use_intersection_match*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-intersection-match"),
("bpy.types.rendersettings_simplify_gpencil_view_modifier*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-view-modifier"),
+ ("bpy.types.brushgpencilsettings.eraser_thickness_factor*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-eraser-thickness-factor"),
+ ("bpy.types.brushgpencilsettings.use_random_press_radius*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-random-press-radius"),
("bpy.types.brushgpencilsettings.use_settings_stabilizer*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-settings-stabilizer"),
("bpy.types.colormanagedsequencercolorspacesettings.name*", "render/color_management.html#bpy-types-colormanagedsequencercolorspacesettings-name"),
("bpy.types.cyclesrendersettings.max_transparent_bounces*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-max-transparent-bounces"),
("bpy.types.cyclesrendersettings.min_transparent_bounces*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-min-transparent-bounces"),
("bpy.types.fluiddomainsettings.use_collision_border_top*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-top"),
+ ("bpy.types.gpencilsculptsettings.intersection_threshold*", "grease_pencil/modes/draw/tools/cutter.html#bpy-types-gpencilsculptsettings-intersection-threshold"),
("bpy.types.gpencilsculptsettings.use_multiframe_falloff*", "grease_pencil/multiframe.html#bpy-types-gpencilsculptsettings-use-multiframe-falloff"),
+ ("bpy.types.lineartgpencilmodifier.use_intersection_mask*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-intersection-mask"),
("bpy.types.movietrackingsettings.use_keyframe_selection*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-use-keyframe-selection"),
("bpy.types.rendersettings.simplify_gpencil_antialiasing*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-antialiasing"),
("bpy.types.sequencertimelineoverlay.show_strip_duration*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-strip-duration"),
("bpy.types.spaceoutliner.use_filter_lib_override_system*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-lib-override-system"),
("bpy.types.toolsettings.use_transform_pivot_point_align*", "scene_layout/object/tools/tool_settings.html#bpy-types-toolsettings-use-transform-pivot-point-align"),
+ ("bpy.types.animvizmotionpaths.show_keyframe_action_all*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-show-keyframe-action-all"),
("bpy.types.brush.show_multiplane_scrape_planes_preview*", "sculpt_paint/sculpting/tools/multiplane_scrape.html#bpy-types-brush-show-multiplane-scrape-planes-preview"),
+ ("bpy.types.brushgpencilsettings.eraser_strength_factor*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-eraser-strength-factor"),
("bpy.types.cyclesmaterialsettings.volume_interpolation*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-volume-interpolation"),
("bpy.types.cyclesrendersettings.debug_optix_curves_api*", "render/cycles/render_settings/debug.html#bpy-types-cyclesrendersettings-debug-optix-curves-api"),
("bpy.types.cyclesrendersettings.denoising_input_passes*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-denoising-input-passes"),
("bpy.types.cyclesrendersettings.film_transparent_glass*", "render/cycles/render_settings/film.html#bpy-types-cyclesrendersettings-film-transparent-glass"),
("bpy.types.cyclesrendersettings.offscreen_dicing_scale*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-offscreen-dicing-scale"),
("bpy.types.fluiddomainsettings.sndparticle_bubble_drag*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-bubble-drag"),
+ ("bpy.types.lineartgpencilmodifier.use_crease_on_smooth*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-crease-on-smooth"),
+ ("bpy.types.lineartgpencilmodifier.use_face_mark_invert*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-face-mark-invert"),
("bpy.types.linestylegeometrymodifier_backbonestretcher*", "render/freestyle/view_layer/line_style/modifiers/geometry/backbone_stretcher.html#bpy-types-linestylegeometrymodifier-backbonestretcher"),
("bpy.types.linestylegeometrymodifier_sinusdisplacement*", "render/freestyle/view_layer/line_style/modifiers/geometry/sinus_displacement.html#bpy-types-linestylegeometrymodifier-sinusdisplacement"),
("bpy.types.sequencertoolsettings.snap_to_current_frame*", "video_editing/sequencer/editing.html#bpy-types-sequencertoolsettings-snap-to-current-frame"),
+ ("bpy.ops.object.geometry_nodes_input_attribute_toggle*", "modeling/modifiers/generate/geometry_nodes.html#bpy-ops-object-geometry-nodes-input-attribute-toggle"),
+ ("bpy.types.animvizmotionpaths.show_keyframe_highlight*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-show-keyframe-highlight"),
+ ("bpy.types.brushgpencilsettings.pen_subdivision_steps*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-pen-subdivision-steps"),
+ ("bpy.types.brushgpencilsettings.use_strength_pressure*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-use-strength-pressure"),
+ ("bpy.types.brushgpencilsettings.use_stroke_random_hue*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-stroke-random-hue"),
+ ("bpy.types.brushgpencilsettings.use_stroke_random_sat*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-stroke-random-sat"),
+ ("bpy.types.brushgpencilsettings.use_stroke_random_val*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-stroke-random-val"),
("bpy.types.colormanageddisplaysettings.display_device*", "render/color_management.html#bpy-types-colormanageddisplaysettings-display-device"),
("bpy.types.colormanagedviewsettings.use_curve_mapping*", "render/color_management.html#bpy-types-colormanagedviewsettings-use-curve-mapping"),
("bpy.types.cyclesrendersettings.sample_clamp_indirect*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-sample-clamp-indirect"),
@@ -126,11 +152,19 @@ url_manual_mapping = (
("bpy.types.gpencillayer.annotation_onion_before_range*", "interface/annotate_tool.html#bpy-types-gpencillayer-annotation-onion-before-range"),
("bpy.types.gpencillayer.use_annotation_onion_skinning*", "interface/annotate_tool.html#bpy-types-gpencillayer-use-annotation-onion-skinning"),
("bpy.types.greasepencil.use_adaptive_curve_resolution*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-use-adaptive-curve-resolution"),
+ ("bpy.types.lineartgpencilmodifier.stroke_depth_offset*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-stroke-depth-offset"),
+ ("bpy.types.lineartgpencilmodifier.use_crease_on_sharp*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-crease-on-sharp"),
("bpy.types.linestylegeometrymodifier_polygonalization*", "render/freestyle/view_layer/line_style/modifiers/geometry/polygonization.html#bpy-types-linestylegeometrymodifier-polygonalization"),
("bpy.types.sequencertimelineoverlay.show_strip_source*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-strip-source"),
("bpy.types.toolsettings.use_gpencil_automerge_strokes*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-automerge-strokes"),
("bpy.types.toolsettings.use_proportional_edit_objects*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-use-proportional-edit-objects"),
("bpy.ops.view3d.edit_mesh_extrude_move_shrink_fatten*", "modeling/meshes/editing/face/extrude_faces_normal.html#bpy-ops-view3d-edit-mesh-extrude-move-shrink-fatten"),
+ ("bpy.types.brushgpencilsettings.active_smooth_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-active-smooth-factor"),
+ ("bpy.types.brushgpencilsettings.extend_stroke_factor*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-extend-stroke-factor"),
+ ("bpy.types.brushgpencilsettings.use_random_press_hue*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-random-press-hue"),
+ ("bpy.types.brushgpencilsettings.use_random_press_sat*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-random-press-sat"),
+ ("bpy.types.brushgpencilsettings.use_random_press_val*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-random-press-val"),
+ ("bpy.types.brushgpencilsettings.use_stroke_random_uv*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-stroke-random-uv"),
("bpy.types.cyclesmaterialsettings.homogeneous_volume*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-homogeneous-volume"),
("bpy.types.cyclesrendersettings.adaptive_min_samples*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-adaptive-min-samples"),
("bpy.types.cyclesrendersettings.debug_bvh_time_steps*", "render/cycles/render_settings/performance.html#bpy-types-cyclesrendersettings-debug-bvh-time-steps"),
@@ -153,11 +187,15 @@ url_manual_mapping = (
("bpy.types.rendersettings_simplify_gpencil_view_fill*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-view-fill"),
("bpy.types.sequencertoolsettings.snap_to_hold_offset*", "video_editing/sequencer/editing.html#bpy-types-sequencertoolsettings-snap-to-hold-offset"),
("bpy.types.toolsettings.use_mesh_automerge_and_split*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-mesh-automerge-and-split"),
+ ("bpy.types.animvizmotionpaths.show_keyframe_numbers*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-show-keyframe-numbers"),
("bpy.types.brush.cloth_constraint_softbody_strength*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-constraint-softbody-strength"),
("bpy.types.brush.elastic_deform_volume_preservation*", "sculpt_paint/sculpting/tools/elastic_deform.html#bpy-types-brush-elastic-deform-volume-preservation"),
("bpy.types.brushgpencilsettings.fill_simplify_level*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-simplify-level"),
+ ("bpy.types.brushgpencilsettings.random_value_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-random-value-factor"),
("bpy.types.brushgpencilsettings.use_jitter_pressure*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-jitter-pressure"),
+ ("bpy.types.brushgpencilsettings.use_random_press_uv*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-random-press-uv"),
("bpy.types.brushgpencilsettings.use_settings_random*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-settings-random"),
+ ("bpy.types.collection.lineart_use_intersection_mask*", "scene_layout/collections/collections.html#bpy-types-collection-lineart-use-intersection-mask"),
("bpy.types.colormanagedinputcolorspacesettings.name*", "editors/image/image_settings.html#bpy-types-colormanagedinputcolorspacesettings-name"),
("bpy.types.cyclesrendersettings.denoising_prefilter*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-denoising-prefilter"),
("bpy.types.cyclesrendersettings.preview_dicing_rate*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-preview-dicing-rate"),
@@ -171,9 +209,11 @@ url_manual_mapping = (
("bpy.types.fluiddomainsettings.sys_particle_maximum*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-sys-particle-maximum"),
("bpy.types.fluiddomainsettings.use_bubble_particles*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-use-bubble-particles"),
("bpy.types.freestylelineset.select_external_contour*", "render/freestyle/view_layer/line_set.html#bpy-types-freestylelineset-select-external-contour"),
+ ("bpy.types.lineartgpencilmodifier.use_custom_camera*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-custom-camera"),
("bpy.types.linestylegeometrymodifier_simplification*", "render/freestyle/view_layer/line_style/modifiers/geometry/simplification.html#bpy-types-linestylegeometrymodifier-simplification"),
("bpy.types.materialgpencilstyle.use_overlap_strokes*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-use-overlap-strokes"),
("bpy.types.sequencertimelineoverlay.show_strip_name*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-strip-name"),
+ ("bpy.types.sequencertimelineoverlay.show_thumbnails*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-thumbnails"),
("bpy.types.spacespreadsheet.geometry_component_type*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-geometry-component-type"),
("bpy.types.toolsettings.use_gpencil_weight_data_add*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-weight-data-add"),
("bpy.types.view3doverlay.texture_paint_mode_opacity*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-texture-paint-mode-opacity"),
@@ -189,6 +229,7 @@ url_manual_mapping = (
("bpy.types.cyclesrendersettings.adaptive_threshold*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-adaptive-threshold"),
("bpy.types.cyclesrendersettings.camera_cull_margin*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-camera-cull-margin"),
("bpy.types.cyclesrendersettings.debug_use_hair_bvh*", "render/cycles/render_settings/performance.html#bpy-types-cyclesrendersettings-debug-use-hair-bvh"),
+ ("bpy.types.fileassetselectparams.asset_library_ref*", "editors/asset_browser.html#bpy-types-fileassetselectparams-asset-library-ref"),
("bpy.types.fluiddomainsettings.export_manta_script*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-export-manta-script"),
("bpy.types.fluiddomainsettings.fractions_threshold*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-fractions-threshold"),
("bpy.types.fluiddomainsettings.particle_band_width*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-particle-band-width"),
@@ -200,26 +241,29 @@ url_manual_mapping = (
("bpy.types.freestylelineset.select_by_image_border*", "render/freestyle/view_layer/line_set.html#bpy-types-freestylelineset-select-by-image-border"),
("bpy.types.freestylesettings.kr_derivative_epsilon*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-kr-derivative-epsilon"),
("bpy.types.geometrynodecurveprimitivebeziersegment*", "modeling/geometry_nodes/curve_primitives/bezier_segment.html#bpy-types-geometrynodecurveprimitivebeziersegment"),
+ ("bpy.types.lineartgpencilmodifier.smooth_tolerance*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-smooth-tolerance"),
("bpy.types.linestylegeometrymodifier_perlinnoise1d*", "render/freestyle/view_layer/line_style/modifiers/geometry/perlin_noise_1d.html#bpy-types-linestylegeometrymodifier-perlinnoise1d"),
("bpy.types.linestylegeometrymodifier_perlinnoise2d*", "render/freestyle/view_layer/line_style/modifiers/geometry/perlin_noise_2d.html#bpy-types-linestylegeometrymodifier-perlinnoise2d"),
("bpy.types.materialgpencilstyle.use_stroke_holdout*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-use-stroke-holdout"),
("bpy.types.movietrackingsettings.use_tripod_solver*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-use-tripod-solver"),
("bpy.types.rendersettings.simplify_child_particles*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-child-particles"),
("bpy.types.rendersettings.use_high_quality_normals*", "render/eevee/render_settings/performance.html#bpy-types-rendersettings-use-high-quality-normals"),
- ("bpy.types.sequencerpreviewoverlay.show_annotation*", "video_editing/preview/introduction.html#bpy-types-sequencerpreviewoverlay-show-annotation"),
- ("bpy.types.sequencerpreviewoverlay.show_safe_areas*", "video_editing/preview/introduction.html#bpy-types-sequencerpreviewoverlay-show-safe-areas"),
+ ("bpy.types.sequencerpreviewoverlay.show_annotation*", "editors/video_sequencer/preview/display/overlays.html#bpy-types-sequencerpreviewoverlay-show-annotation"),
+ ("bpy.types.sequencerpreviewoverlay.show_safe_areas*", "editors/video_sequencer/preview/display/overlays.html#bpy-types-sequencerpreviewoverlay-show-safe-areas"),
("bpy.types.sequencertoolsettings.snap_ignore_muted*", "video_editing/sequencer/editing.html#bpy-types-sequencertoolsettings-snap-ignore-muted"),
("bpy.types.sequencertoolsettings.snap_ignore_sound*", "video_editing/sequencer/editing.html#bpy-types-sequencertoolsettings-snap-ignore-sound"),
("bpy.types.spaceoutliner.use_filter_case_sensitive*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-case-sensitive"),
("bpy.types.spaceoutliner.use_filter_object_content*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-content"),
+ ("bpy.types.spacesequenceeditor.show_gizmo_navigate*", "editors/video_sequencer/preview/display/gizmos.html#bpy-types-spacesequenceeditor-show-gizmo-navigate"),
("bpy.types.toolsettings.use_proportional_connected*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-use-proportional-connected"),
("bpy.types.toolsettings.use_proportional_projected*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-use-proportional-projected"),
("bpy.types.view3doverlay.vertex_paint_mode_opacity*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-vertex-paint-mode-opacity"),
- ("bpy.types.viewlayer.use_pass_cryptomatte_accurate*", "render/layers/passes.html#bpy-types-viewlayer-use-pass-cryptomatte-accurate"),
("bpy.types.viewlayer.use_pass_cryptomatte_material*", "render/layers/passes.html#bpy-types-viewlayer-use-pass-cryptomatte-material"),
("bpy.ops.gpencil.vertex_color_brightness_contrast*", "grease_pencil/modes/vertex_paint/editing.html#bpy-ops-gpencil-vertex-color-brightness-contrast"),
("bpy.ops.view3d.edit_mesh_extrude_individual_move*", "modeling/meshes/editing/face/extrude_faces.html#bpy-ops-view3d-edit-mesh-extrude-individual-move"),
("bpy.ops.view3d.edit_mesh_extrude_manifold_normal*", "modeling/meshes/tools/extrude_manifold.html#bpy-ops-view3d-edit-mesh-extrude-manifold-normal"),
+ ("bpy.types.brushgpencilsettings.pen_smooth_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-pen-smooth-factor"),
+ ("bpy.types.brushgpencilsettings.random_hue_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-random-hue-factor"),
("bpy.types.cyclescurverendersettings.subdivisions*", "render/cycles/render_settings/hair.html#bpy-types-cyclescurverendersettings-subdivisions"),
("bpy.types.cyclesmaterialsettings.sample_as_light*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-sample-as-light"),
("bpy.types.cyclesmaterialsettings.volume_sampling*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-volume-sampling"),
@@ -248,6 +292,8 @@ url_manual_mapping = (
("bpy.types.linestylegeometrymodifier_guidinglines*", "render/freestyle/view_layer/line_style/modifiers/geometry/guiding_lines.html#bpy-types-linestylegeometrymodifier-guidinglines"),
("bpy.types.linestylegeometrymodifier_spatialnoise*", "render/freestyle/view_layer/line_style/modifiers/geometry/spatial_noise.html#bpy-types-linestylegeometrymodifier-spatialnoise"),
("bpy.types.linestylethicknessmodifier_calligraphy*", "render/freestyle/view_layer/line_style/modifiers/thickness/calligraphy.html#bpy-types-linestylethicknessmodifier-calligraphy"),
+ ("bpy.types.materiallineart.use_material_mask_bits*", "render/materials/line_art.html#bpy-types-materiallineart-use-material-mask-bits"),
+ ("bpy.types.movietrackingdopesheet.use_invert_sort*", "movie_clip/tracking/dope_sheet.html#bpy-types-movietrackingdopesheet-use-invert-sort"),
("bpy.types.rendersettings_simplify_gpencil_onplay*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-onplay"),
("bpy.types.rigidbodyconstraint.breaking_threshold*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-breaking-threshold"),
("bpy.types.spaceclipeditor.use_manual_calibration*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-use-manual-calibration"),
@@ -255,14 +301,19 @@ url_manual_mapping = (
("bpy.types.spaceoutliner.use_filter_object_camera*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-camera"),
("bpy.types.spaceoutliner.use_filter_object_others*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-others"),
("bpy.types.spacesequenceeditor.show_strip_overlay*", "editors/video_sequencer/sequencer/display.html#bpy-types-spacesequenceeditor-show-strip-overlay"),
+ ("bpy.types.spaceuveditor.custom_grid_subdivisions*", "editors/uv/sidebar.html#bpy-types-spaceuveditor-custom-grid-subdivisions"),
("bpy.types.toolsettings.proportional_edit_falloff*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-proportional-edit-falloff"),
("bpy.types.toolsettings.use_edge_path_live_unwrap*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-edge-path-live-unwrap"),
("bpy.types.toolsettings.use_gpencil_draw_additive*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-draw-additive"),
("bpy.types.toolsettings.use_snap_backface_culling*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-backface-culling"),
+ ("bpy.types.toolsettings.use_snap_uv_grid_absolute*", "editors/uv/controls/snapping.html#bpy-types-toolsettings-use-snap-uv-grid-absolute"),
("bpy.types.toolsettings.use_transform_data_origin*", "scene_layout/object/tools/tool_settings.html#bpy-types-toolsettings-use-transform-data-origin"),
("bpy.types.view3doverlay.sculpt_mode_mask_opacity*", "sculpt_paint/sculpting/editing/mask.html#bpy-types-view3doverlay-sculpt-mode-mask-opacity"),
("bpy.ops.mesh.customdata_custom_splitnormals_add*", "modeling/meshes/properties/custom_data.html#bpy-ops-mesh-customdata-custom-splitnormals-add"),
("bpy.ops.outliner.collection_indirect_only_clear*", "render/layers/introduction.html#bpy-ops-outliner-collection-indirect-only-clear"),
+ ("bpy.types.animvizmotionpaths.show_frame_numbers*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-show-frame-numbers"),
+ ("bpy.types.brushgpencilsettings.pen_smooth_steps*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-pen-smooth-steps"),
+ ("bpy.types.brushgpencilsettings.show_fill_extend*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-show-fill-extend"),
("bpy.types.cyclesrendersettings.max_subdivisions*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-max-subdivisions"),
("bpy.types.cyclesrendersettings.preview_denoiser*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-preview-denoiser"),
("bpy.types.cyclesrendersettings.sampling_pattern*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-sampling-pattern"),
@@ -293,7 +344,7 @@ url_manual_mapping = (
("bpy.types.materialgpencilstyle.use_fill_holdout*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-use-fill-holdout"),
("bpy.types.particlesettings.use_parent_particles*", "physics/particles/emitter/render.html#bpy-types-particlesettings-use-parent-particles"),
("bpy.types.rigidbodyconstraint.solver_iterations*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-solver-iterations"),
- ("bpy.types.sequencerpreviewoverlay.show_metadata*", "video_editing/preview/introduction.html#bpy-types-sequencerpreviewoverlay-show-metadata"),
+ ("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"),
@@ -307,6 +358,9 @@ url_manual_mapping = (
("bpy.types.viewlayer.use_pass_cryptomatte_object*", "render/layers/passes.html#bpy-types-viewlayer-use-pass-cryptomatte-object"),
("bpy.ops.armature.rigify_apply_selection_colors*", "addons/rigging/rigify/metarigs.html#bpy-ops-armature-rigify-apply-selection-colors"),
("bpy.types.brushgpencilsettings.fill_layer_mode*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-layer-mode"),
+ ("bpy.types.brushgpencilsettings.random_strength*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-random-strength"),
+ ("bpy.types.brushgpencilsettings.simplify_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-simplify-factor"),
+ ("bpy.types.collection.lineart_intersection_mask*", "scene_layout/collections/collections.html#bpy-types-collection-lineart-intersection-mask"),
("bpy.types.cyclesobjectsettings.use_camera_cull*", "render/cycles/object_settings/object_data.html#bpy-types-cyclesobjectsettings-use-camera-cull"),
("bpy.types.cyclesobjectsettings.use_motion_blur*", "render/cycles/object_settings/object_data.html#bpy-types-cyclesobjectsettings-use-motion-blur"),
("bpy.types.cyclesrendersettings.diffuse_bounces*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-diffuse-bounces"),
@@ -325,6 +379,8 @@ url_manual_mapping = (
("bpy.types.freestylesettings.use_view_map_cache*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-use-view-map-cache"),
("bpy.types.geometrynodecurvehandletypeselection*", "modeling/geometry_nodes/curve/handle_type_selection.html#bpy-types-geometrynodecurvehandletypeselection"),
("bpy.types.greasepencil.curve_edit_corner_angle*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-corner-angle"),
+ ("bpy.types.lineartgpencilmodifier.source_camera*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-source-camera"),
+ ("bpy.types.lineartgpencilmodifier.use_face_mark*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-face-mark"),
("bpy.types.linestylegeometrymodifier_tipremover*", "render/freestyle/view_layer/line_style/modifiers/geometry/tip_remover.html#bpy-types-linestylegeometrymodifier-tipremover"),
("bpy.types.movieclipuser.use_render_undistorted*", "editors/clip/display/clip_display.html#bpy-types-movieclipuser-use-render-undistorted"),
("bpy.types.movietrackingcamera.distortion_model*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-distortion-model"),
@@ -345,9 +401,11 @@ url_manual_mapping = (
("bpy.types.brushgpencilsettings.fill_direction*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-direction"),
("bpy.types.brushgpencilsettings.fill_draw_mode*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-draw-mode"),
("bpy.types.brushgpencilsettings.fill_threshold*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-threshold"),
+ ("bpy.types.brushgpencilsettings.use_fill_limit*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-use-fill-limit"),
("bpy.types.clothsettings.vertex_group_pressure*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-vertex-group-pressure"),
("bpy.types.cyclesmaterialsettings.displacement*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-displacement"),
("bpy.types.cyclesrendersettings.debug_bvh_type*", "render/cycles/render_settings/debug.html#bpy-types-cyclesrendersettings-debug-bvh-type"),
+ ("bpy.types.cyclesrendersettings.fast_gi_method*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-fast-gi-method"),
("bpy.types.cyclesrendersettings.glossy_bounces*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-glossy-bounces"),
("bpy.types.cyclesrendersettings.volume_bounces*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-volume-bounces"),
("bpy.types.cyclesworldsettings.sampling_method*", "render/cycles/world_settings.html#bpy-types-cyclesworldsettings-sampling-method"),
@@ -376,9 +434,12 @@ url_manual_mapping = (
("bpy.types.particlesettings.use_modifier_stack*", "physics/particles/emitter/emission.html#bpy-types-particlesettings-use-modifier-stack"),
("bpy.types.rendersettings.sequencer_gl_preview*", "video_editing/preview/sidebar.html#bpy-types-rendersettings-sequencer-gl-preview"),
("bpy.types.rendersettings.simplify_subdivision*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-subdivision"),
+ ("bpy.types.sequencerpreviewoverlay.show_cursor*", "editors/video_sequencer/preview/display/overlays.html#bpy-types-sequencerpreviewoverlay-show-cursor"),
("bpy.types.spacegrapheditor.show_extrapolation*", "editors/graph_editor/introduction.html#bpy-types-spacegrapheditor-show-extrapolation"),
("bpy.types.spaceoutliner.use_filter_collection*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-collection"),
+ ("bpy.types.spacesequenceeditor.cursor_location*", "video_editing/preview/sidebar.html#bpy-types-spacesequenceeditor-cursor-location"),
("bpy.types.spacesequenceeditor.display_channel*", "video_editing/preview/sidebar.html#bpy-types-spacesequenceeditor-display-channel"),
+ ("bpy.types.spacesequenceeditor.show_gizmo_tool*", "editors/video_sequencer/preview/display/gizmos.html#bpy-types-spacesequenceeditor-show-gizmo-tool"),
("bpy.types.spacesequenceeditor.show_region_hud*", "video_editing/sequencer/navigating.html#bpy-types-spacesequenceeditor-show-region-hud"),
("bpy.types.spacespreadsheet.show_only_selected*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-show-only-selected"),
("bpy.types.spacespreadsheetrowfilter.operation*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-operation"),
@@ -386,12 +447,12 @@ url_manual_mapping = (
("bpy.types.toolsettings.use_snap_grid_absolute*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-grid-absolute"),
("bpy.types.view3doverlay.show_face_orientation*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-face-orientation"),
("bpy.ops.gpencil.bake_grease_pencil_animation*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-bake-grease-pencil-animation"),
- ("bpy.ops.object.blenderkit_material_thumbnail*", "addons/3d_view/blenderkit.html#bpy-ops-object-blenderkit-material-thumbnail"),
("bpy.ops.object.multires_higher_levels_delete*", "modeling/modifiers/generate/multiresolution.html#bpy-ops-object-multires-higher-levels-delete"),
("bpy.ops.object.vertex_group_copy_to_selected*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-copy-to-selected"),
("bpy.ops.outliner.collection_duplicate_linked*", "editors/outliner/editing.html#bpy-ops-outliner-collection-duplicate-linked"),
("bpy.ops.view3d.edit_mesh_extrude_move_normal*", "modeling/meshes/editing/face/extrude_faces.html#bpy-ops-view3d-edit-mesh-extrude-move-normal"),
("bpy.types.bakesettings.use_pass_transmission*", "render/cycles/baking.html#bpy-types-bakesettings-use-pass-transmission"),
+ ("bpy.types.brushgpencilsettings.input_samples*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-input-samples"),
("bpy.types.clothsettings.internal_compression*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-internal-compression"),
("bpy.types.cyclescamerasettings.panorama_type*", "render/cycles/object_settings/cameras.html#bpy-types-cyclescamerasettings-panorama-type"),
("bpy.types.cyclesrendersettings.dicing_camera*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-dicing-camera"),
@@ -425,6 +486,7 @@ url_manual_mapping = (
("bpy.types.greasepencil.edit_curve_resolution*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-edit-curve-resolution"),
("bpy.types.linestylegeometrymodifier_2doffset*", "render/freestyle/view_layer/line_style/modifiers/geometry/2d_offset.html#bpy-types-linestylegeometrymodifier-2doffset"),
("bpy.types.linestylegeometrymodifier_sampling*", "render/freestyle/view_layer/line_style/modifiers/geometry/sampling.html#bpy-types-linestylegeometrymodifier-sampling"),
+ ("bpy.types.movietrackingdopesheet.sort_method*", "movie_clip/tracking/dope_sheet.html#bpy-types-movietrackingdopesheet-sort-method"),
("bpy.types.nodesocketinterface*.default_value*", "interface/controls/nodes/groups.html#bpy-types-nodesocketinterface-default-value"),
("bpy.types.rendersettings.line_thickness_mode*", "render/freestyle/render.html#bpy-types-rendersettings-line-thickness-mode"),
("bpy.types.rendersettings.motion_blur_shutter*", "render/cycles/render_settings/motion_blur.html#bpy-types-rendersettings-motion-blur-shutter"),
@@ -434,9 +496,12 @@ url_manual_mapping = (
("bpy.types.spaceclipeditor.show_green_channel*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-show-green-channel"),
("bpy.types.spaceoutliner.show_restrict_column*", "editors/outliner/interface.html#bpy-types-spaceoutliner-show-restrict-column"),
("bpy.types.spacespreadsheet.object_eval_state*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-object-eval-state"),
+ ("bpy.types.spaceuveditor.display_stretch_type*", "editors/uv/overlays.html#bpy-types-spaceuveditor-display-stretch-type"),
("bpy.types.toolsettings.transform_pivot_point*", "editors/3dview/controls/pivot_point/index.html#bpy-types-toolsettings-transform-pivot-point"),
("bpy.types.toolsettings.use_proportional_edit*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-use-proportional-edit"),
("bpy.types.volumedisplay.interpolation_method*", "modeling/volumes/properties.html#bpy-types-volumedisplay-interpolation-method"),
+ ("bpy.types.brushgpencilsettings.angle_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-angle-factor"),
+ ("bpy.types.brushgpencilsettings.pen_strength*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-pen-strength"),
("bpy.types.clothsettings.use_pressure_volume*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-use-pressure-volume"),
("bpy.types.clothsettings.vertex_group_intern*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-vertex-group-intern"),
("bpy.types.colormanagedviewsettings.exposure*", "render/color_management.html#bpy-types-colormanagedviewsettings-exposure"),
@@ -459,11 +524,13 @@ url_manual_mapping = (
("bpy.types.geometrynodeinputsplineresolution*", "modeling/geometry_nodes/curve/spline_resolution.html#bpy-types-geometrynodeinputsplineresolution"),
("bpy.types.greasepencil.curve_edit_threshold*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-threshold"),
("bpy.types.materialgpencilstyle.stroke_style*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-stroke-style"),
+ ("bpy.types.materiallineart.use_material_mask*", "render/materials/line_art.html#bpy-types-materiallineart-use-material-mask"),
("bpy.types.objectlineart.use_crease_override*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart-use-crease-override"),
("bpy.types.rendersettings.preview_pixel_size*", "render/cycles/render_settings/performance.html#bpy-types-rendersettings-preview-pixel-size"),
("bpy.types.rendersettings.use_crop_to_border*", "render/output/properties/format.html#bpy-types-rendersettings-use-crop-to-border"),
("bpy.types.rendersettings.use_file_extension*", "render/output/properties/output.html#bpy-types-rendersettings-use-file-extension"),
("bpy.types.sculpt.constant_detail_resolution*", "sculpt_paint/sculpting/tool_settings/dyntopo.html#bpy-types-sculpt-constant-detail-resolution"),
+ ("bpy.types.sequencertoolsettings.pivot_point*", "editors/video_sequencer/preview/controls/pivot_point.html#bpy-types-sequencertoolsettings-pivot-point"),
("bpy.types.spaceclipeditor.annotation_source*", "movie_clip/tracking/clip/sidebar/view.html#bpy-types-spaceclipeditor-annotation-source"),
("bpy.types.spaceclipeditor.show_blue_channel*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-show-blue-channel"),
("bpy.types.spacefilebrowser.system_bookmarks*", "editors/file_browser.html#bpy-types-spacefilebrowser-system-bookmarks"),
@@ -471,6 +538,7 @@ url_manual_mapping = (
("bpy.types.spaceoutliner.use_filter_complete*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-complete"),
("bpy.types.spacespreadsheet.attribute_domain*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-attribute-domain"),
("bpy.types.spacespreadsheetrowfilter.enabled*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-enabled"),
+ ("bpy.types.spaceuveditor.show_modified_edges*", "editors/uv/overlays.html#bpy-types-spaceuveditor-show-modified-edges"),
("bpy.types.spaceview3d.transform_orientation*", "editors/3dview/controls/orientation.html#bpy-types-spaceview3d-transform-orientation"),
("bpy.types.spaceview3d.use_local_collections*", "editors/3dview/sidebar.html#bpy-types-spaceview3d-use-local-collections"),
("bpy.types.toolsettings.use_snap_peel_object*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-peel-object"),
@@ -482,6 +550,7 @@ url_manual_mapping = (
("bpy.ops.scene.freestyle_alpha_modifier_add*", "render/freestyle/view_layer/line_style/alpha.html#bpy-ops-scene-freestyle-alpha-modifier-add"),
("bpy.ops.scene.freestyle_color_modifier_add*", "render/freestyle/view_layer/line_style/color.html#bpy-ops-scene-freestyle-color-modifier-add"),
("bpy.types.brush.cloth_simulation_area_type*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-simulation-area-type"),
+ ("bpy.types.brushgpencilsettings.eraser_mode*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-eraser-mode"),
("bpy.types.brushgpencilsettings.fill_factor*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-factor"),
("bpy.types.curve.bevel_factor_mapping_start*", "modeling/curves/properties/geometry.html#bpy-types-curve-bevel-factor-mapping-start"),
("bpy.types.cyclescamerasettings.fisheye_fov*", "render/cycles/object_settings/cameras.html#bpy-types-cyclescamerasettings-fisheye-fov"),
@@ -512,6 +581,8 @@ url_manual_mapping = (
("bpy.types.freestylesettings.as_render_pass*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-as-render-pass"),
("bpy.types.freestylesettings.use_smoothness*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-use-smoothness"),
("bpy.types.geometrynodecurvequadraticbezier*", "modeling/geometry_nodes/curve_primitives/quadratic_bezier.html#bpy-types-geometrynodecurvequadraticbezier"),
+ ("bpy.types.lineartgpencilmodifier.use_cache*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-cache"),
+ ("bpy.types.lineartgpencilmodifier.use_loose*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-loose"),
("bpy.types.materialgpencilstyle.show_stroke*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-show-stroke"),
("bpy.types.mesh.use_customdata_vertex_bevel*", "modeling/meshes/properties/custom_data.html#bpy-types-mesh-use-customdata-vertex-bevel"),
("bpy.types.movietrackingcamera.focal_length*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-focal-length"),
@@ -522,6 +593,8 @@ url_manual_mapping = (
("bpy.types.scenegpencil.antialias_threshold*", "render/cycles/render_settings/grease_pencil.html#bpy-types-scenegpencil-antialias-threshold"),
("bpy.types.spaceclipeditor.show_red_channel*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-show-red-channel"),
("bpy.types.spaceclipeditor.use_mute_footage*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-use-mute-footage"),
+ ("bpy.types.spacenodeoverlay.show_wire_color*", "interface/controls/nodes/introduction.html#bpy-types-spacenodeoverlay-show-wire-color"),
+ ("bpy.types.spacesequenceeditor.display_mode*", "video_editing/preview/display_mode.html#bpy-types-spacesequenceeditor-display-mode"),
("bpy.types.spacesequenceeditor.overlay_type*", "video_editing/preview/sidebar.html#bpy-types-spacesequenceeditor-overlay-type"),
("bpy.types.spaceuveditor.sticky_select_mode*", "editors/uv/selecting.html#bpy-types-spaceuveditor-sticky-select-mode"),
("bpy.types.spaceview3d.show_object_viewport*", "editors/3dview/display/visibility.html#bpy-types-spaceview3d-show-object-viewport"),
@@ -538,9 +611,11 @@ url_manual_mapping = (
("bpy.ops.outliner.collection_holdout_clear*", "render/layers/introduction.html#bpy-ops-outliner-collection-holdout-clear"),
("bpy.ops.sculpt.face_set_change_visibility*", "sculpt_paint/sculpting/editing/face_sets.html#bpy-ops-sculpt-face-set-change-visibility"),
("bpy.ops.sculpt.face_sets_randomize_colors*", "sculpt_paint/sculpting/editing/face_sets.html#bpy-ops-sculpt-face-sets-randomize-colors"),
+ ("bpy.types.animvizmotionpaths.frame_before*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-frame-before"),
("bpy.types.brush.disconnected_distance_max*", "sculpt_paint/sculpting/tools/pose.html#bpy-types-brush-disconnected-distance-max"),
("bpy.types.brush.surface_smooth_iterations*", "sculpt_paint/sculpting/tools/smooth.html#bpy-types-brush-surface-smooth-iterations"),
("bpy.types.brushgpencilsettings.pen_jitter*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-pen-jitter"),
+ ("bpy.types.brushgpencilsettings.show_lasso*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-show-lasso"),
("bpy.types.cyclescurverendersettings.shape*", "render/cycles/render_settings/hair.html#bpy-types-cyclescurverendersettings-shape"),
("bpy.types.cyclesrendersettings.ao_bounces*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-ao-bounces"),
("bpy.types.cyclesrendersettings.time_limit*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-time-limit"),
@@ -566,6 +641,7 @@ url_manual_mapping = (
("bpy.types.gpencilsculptsettings.lock_axis*", "grease_pencil/modes/draw/drawing_planes.html#bpy-types-gpencilsculptsettings-lock-axis"),
("bpy.types.imageformatsettings.file_format*", "render/output/properties/output.html#bpy-types-imageformatsettings-file-format"),
("bpy.types.imagepaint.use_backface_culling*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-use-backface-culling"),
+ ("bpy.types.lineartgpencilmodifier.overscan*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-overscan"),
("bpy.types.linestyle*modifier_curvature_3d*", "render/freestyle/view_layer/line_style/modifiers/color/curvature_3d.html#bpy-types-linestyle-modifier-curvature-3d"),
("bpy.types.materialgpencilstyle.fill_color*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-fill-color"),
("bpy.types.materialgpencilstyle.fill_style*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-fill-style"),
@@ -580,10 +656,13 @@ url_manual_mapping = (
("bpy.types.rendersettings.use_single_layer*", "render/layers/view_layer.html#bpy-types-rendersettings-use-single-layer"),
("bpy.types.sceneeevee.use_taa_reprojection*", "render/eevee/render_settings/sampling.html#bpy-types-sceneeevee-use-taa-reprojection"),
("bpy.types.sequenceeditor.use_overlay_lock*", "video_editing/preview/sidebar.html#bpy-types-sequenceeditor-use-overlay-lock"),
+ ("bpy.types.spaceclipeditor.cursor_location*", "editors/clip/sidebar.html#bpy-types-spaceclipeditor-cursor-location"),
("bpy.types.spacefilebrowser.recent_folders*", "editors/file_browser.html#bpy-types-spacefilebrowser-recent-folders"),
("bpy.types.spacefilebrowser.system_folders*", "editors/file_browser.html#bpy-types-spacefilebrowser-system-folders"),
+ ("bpy.types.spacenodeeditor.show_annotation*", "interface/controls/nodes/introduction.html#bpy-types-spacenodeeditor-show-annotation"),
("bpy.types.spaceoutliner.use_filter_object*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object"),
("bpy.types.spacesequenceeditor.use_proxies*", "video_editing/preview/sidebar.html#bpy-types-spacesequenceeditor-use-proxies"),
+ ("bpy.types.spaceuveditor.edge_display_type*", "editors/uv/overlays.html#bpy-types-spaceuveditor-edge-display-type"),
("bpy.types.spaceuveditor.show_pixel_coords*", "editors/uv/sidebar.html#bpy-types-spaceuveditor-show-pixel-coords"),
("bpy.types.spaceview3d.show_reconstruction*", "editors/3dview/display/overlays.html#bpy-types-spaceview3d-show-reconstruction"),
("bpy.types.toolsettings.gpencil_selectmode*", "grease_pencil/selecting.html#bpy-types-toolsettings-gpencil-selectmode"),
@@ -593,6 +672,7 @@ url_manual_mapping = (
("bpy.types.toolsettings.use_snap_translate*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-translate"),
("bpy.types.toolsettings.use_uv_select_sync*", "editors/uv/selecting.html#bpy-types-toolsettings-use-uv-select-sync"),
("bpy.types.view3doverlay.wireframe_opacity*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-wireframe-opacity"),
+ ("bpy.ops.asset.open_containing_blend_file*", "editors/asset_browser.html#bpy-ops-asset-open-containing-blend-file"),
("bpy.ops.gpencil.active_frames_delete_all*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-active-frames-delete-all"),
("bpy.ops.gpencil.stroke_merge_by_distance*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-stroke-merge-by-distance"),
("bpy.ops.node.collapse_hide_unused_toggle*", "interface/controls/nodes/editing.html#bpy-ops-node-collapse-hide-unused-toggle"),
@@ -601,8 +681,11 @@ url_manual_mapping = (
("bpy.ops.object.modifier_copy_to_selected*", "modeling/modifiers/introduction.html#bpy-ops-object-modifier-copy-to-selected"),
("bpy.ops.preferences.app_template_install*", "advanced/app_templates.html#bpy-ops-preferences-app-template-install"),
("bpy.types.actionposemarkers.active_index*", "animation/armatures/properties/pose_library.html#bpy-types-actionposemarkers-active-index"),
+ ("bpy.types.animvizmotionpaths.frame_after*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-frame-after"),
+ ("bpy.types.animvizmotionpaths.frame_start*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-frame-start"),
("bpy.types.bakesettings.use_pass_indirect*", "render/cycles/baking.html#bpy-types-bakesettings-use-pass-indirect"),
("bpy.types.brush.cloth_force_falloff_type*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-force-falloff-type"),
+ ("bpy.types.brushgpencilsettings.caps_type*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-caps-type"),
("bpy.types.brushgpencilsettings.fill_leak*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-leak"),
("bpy.types.brushgpencilsettings.show_fill*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-show-fill"),
("bpy.types.brushgpencilsettings.uv_random*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-uv-random"),
@@ -655,12 +738,15 @@ url_manual_mapping = (
("bpy.types.shadernodesubsurfacescattering*", "render/shader_nodes/shader/sss.html#bpy-types-shadernodesubsurfacescattering"),
("bpy.types.spaceclipeditor.lock_selection*", "editors/clip/introduction.html#bpy-types-spaceclipeditor-lock-selection"),
("bpy.types.spacedopesheeteditor.auto_snap*", "editors/dope_sheet/editing.html#bpy-types-spacedopesheeteditor-auto-snap"),
+ ("bpy.types.spacenodeoverlay.show_overlays*", "interface/controls/nodes/introduction.html#bpy-types-spacenodeoverlay-show-overlays"),
("bpy.types.spaceoutliner.show_mode_column*", "editors/outliner/interface.html#bpy-types-spaceoutliner-show-mode-column"),
+ ("bpy.types.spacesequenceeditor.show_gizmo*", "editors/video_sequencer/preview/display/gizmos.html#bpy-types-spacesequenceeditor-show-gizmo"),
("bpy.types.spacetexteditor.use_match_case*", "editors/text_editor.html#bpy-types-spacetexteditor-use-match-case"),
("bpy.types.spaceview3d.show_object_select*", "editors/3dview/display/visibility.html#bpy-types-spaceview3d-show-object-select"),
("bpy.types.toolsettings.use_lock_relative*", "sculpt_paint/weight_paint/tool_settings/options.html#bpy-types-toolsettings-use-lock-relative"),
("bpy.types.vertexpaint.use_group_restrict*", "sculpt_paint/weight_paint/tool_settings/options.html#bpy-types-vertexpaint-use-group-restrict"),
("bpy.types.volumedisplay.wireframe_detail*", "modeling/volumes/properties.html#bpy-types-volumedisplay-wireframe-detail"),
+ ("bpy.types.windowmanager.asset_path_dummy*", "editors/asset_browser.html#bpy-types-windowmanager-asset-path-dummy"),
("bpy.ops.armature.rigify_add_bone_groups*", "addons/rigging/rigify/metarigs.html#bpy-ops-armature-rigify-add-bone-groups"),
("bpy.ops.object.assign_property_defaults*", "animation/armatures/posing/editing/apply.html#bpy-ops-object-assign-property-defaults"),
("bpy.ops.object.vertex_group_limit_total*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-limit-total"),
@@ -669,12 +755,16 @@ url_manual_mapping = (
("bpy.ops.outliner.collection_hide_inside*", "editors/outliner/editing.html#bpy-ops-outliner-collection-hide-inside"),
("bpy.ops.outliner.collection_holdout_set*", "render/layers/introduction.html#bpy-ops-outliner-collection-holdout-set"),
("bpy.ops.outliner.collection_show_inside*", "editors/outliner/editing.html#bpy-ops-outliner-collection-show-inside"),
+ ("bpy.ops.poselib.restore_previous_action*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-restore-previous-action"),
("bpy.ops.preferences.reset_default_theme*", "editors/preferences/themes.html#bpy-ops-preferences-reset-default-theme"),
("bpy.ops.sequencer.strip_transform_clear*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-strip-transform-clear"),
("bpy.ops.spreadsheet.add_row_filter_rule*", "editors/spreadsheet.html#bpy-ops-spreadsheet-add-row-filter-rule"),
("bpy.types.animdata.action_extrapolation*", "editors/nla/sidebar.html#bpy-types-animdata-action-extrapolation"),
+ ("bpy.types.animvizmotionpaths.frame_step*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-frame-step"),
("bpy.types.bakesettings.max_ray_distance*", "render/cycles/baking.html#bpy-types-bakesettings-max-ray-distance"),
("bpy.types.brush.multiplane_scrape_angle*", "sculpt_paint/sculpting/tools/multiplane_scrape.html#bpy-types-brush-multiplane-scrape-angle"),
+ ("bpy.types.brushgpencilsettings.hardness*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-hardness"),
+ ("bpy.types.brushgpencilsettings.use_trim*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-trim"),
("bpy.types.clothsettings.internal_spring*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-internal-spring"),
("bpy.types.clothsettings.pressure_factor*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-pressure-factor"),
("bpy.types.colormanagedviewsettings.look*", "render/color_management.html#bpy-types-colormanagedviewsettings-look"),
@@ -709,6 +799,7 @@ url_manual_mapping = (
("bpy.types.layercollection.hide_viewport*", "editors/outliner/interface.html#bpy-types-layercollection-hide-viewport"),
("bpy.types.layercollection.indirect_only*", "editors/outliner/interface.html#bpy-types-layercollection-indirect-only"),
("bpy.types.material.use_sss_translucency*", "render/eevee/materials/settings.html#bpy-types-material-use-sss-translucency"),
+ ("bpy.types.materiallineart.mat_occlusion*", "render/materials/line_art.html#bpy-types-materiallineart-mat-occlusion"),
("bpy.types.movietrackingcamera.principal*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-principal"),
("bpy.types.object.use_camera_lock_parent*", "scene_layout/object/properties/relations.html#bpy-types-object-use-camera-lock-parent"),
("bpy.types.object.visible_volume_scatter*", "render/cycles/object_settings/object_data.html#bpy-types-object-visible-volume-scatter"),
@@ -724,6 +815,7 @@ url_manual_mapping = (
("bpy.types.spacetexteditor.margin_column*", "editors/text_editor.html#bpy-types-spacetexteditor-margin-column"),
("bpy.types.spacetexteditor.use_find_wrap*", "editors/text_editor.html#bpy-types-spacetexteditor-use-find-wrap"),
("bpy.types.spaceuveditor.pixel_snap_mode*", "modeling/meshes/uv/editing.html#bpy-types-spaceuveditor-pixel-snap-mode"),
+ ("bpy.types.spaceuveditor.use_custom_grid*", "editors/uv/sidebar.html#bpy-types-spaceuveditor-use-custom-grid"),
("bpy.types.spaceuveditor.use_live_unwrap*", "modeling/meshes/uv/editing.html#bpy-types-spaceuveditor-use-live-unwrap"),
("bpy.types.toolsettings.double_threshold*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-double-threshold"),
("bpy.types.toolsettings.lock_object_mode*", "interface/window_system/topbar.html#bpy-types-toolsettings-lock-object-mode"),
@@ -738,7 +830,7 @@ url_manual_mapping = (
("bpy.ops.mesh.vertices_smooth_laplacian*", "modeling/meshes/editing/vertex/laplacian_smooth.html#bpy-ops-mesh-vertices-smooth-laplacian"),
("bpy.ops.object.multires_rebuild_subdiv*", "modeling/modifiers/generate/multiresolution.html#bpy-ops-object-multires-rebuild-subdiv"),
("bpy.ops.sequencer.select_side_of_frame*", "video_editing/sequencer/selecting.html#bpy-ops-sequencer-select-side-of-frame"),
- ("bpy.ops.view3d.blenderkit_set_category*", "addons/3d_view/blenderkit.html#bpy-ops-view3d-blenderkit-set-category"),
+ ("bpy.types.animvizmotionpaths.frame_end*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-frame-end"),
("bpy.types.armature.rigify_colors_index*", "addons/rigging/rigify/metarigs.html#bpy-types-armature-rigify-colors-index"),
("bpy.types.armature.rigify_theme_to_add*", "addons/rigging/rigify/metarigs.html#bpy-types-armature-rigify-theme-to-add"),
("bpy.types.bakesettings.use_pass_direct*", "render/cycles/baking.html#bpy-types-bakesettings-use-pass-direct"),
@@ -785,11 +877,13 @@ url_manual_mapping = (
("bpy.types.spacepreferences.filter_type*", "editors/preferences/keymap.html#bpy-types-spacepreferences-filter-type"),
("bpy.types.spacetexteditor.replace_text*", "editors/text_editor.html#bpy-types-spacetexteditor-replace-text"),
("bpy.types.spacetexteditor.use_find_all*", "editors/text_editor.html#bpy-types-spacetexteditor-use-find-all"),
+ ("bpy.types.toolsettings.snap_uv_element*", "editors/uv/controls/snapping.html#bpy-types-toolsettings-snap-uv-element"),
("bpy.types.toolsettings.use_snap_rotate*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-rotate"),
("bpy.types.view3doverlay.display_handle*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-display-handle"),
("bpy.types.volumedisplay.wireframe_type*", "modeling/volumes/properties.html#bpy-types-volumedisplay-wireframe-type"),
("bpy.ops.anim.channels_editable_toggle*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-editable-toggle"),
("bpy.ops.curve.normals_make_consistent*", "modeling/curves/editing/control_points.html#bpy-ops-curve-normals-make-consistent"),
+ ("bpy.ops.ed.lib_id_load_custom_preview*", "editors/asset_browser.html#bpy-ops-ed-lib-id-load-custom-preview"),
("bpy.ops.gpencil.frame_clean_duplicate*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-frame-clean-duplicate"),
("bpy.ops.gpencil.stroke_simplify_fixed*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-simplify-fixed"),
("bpy.ops.mesh.faces_select_linked_flat*", "modeling/meshes/selecting/linked.html#bpy-ops-mesh-faces-select-linked-flat"),
@@ -803,15 +897,19 @@ url_manual_mapping = (
("bpy.ops.outliner.collection_duplicate*", "editors/outliner/editing.html#bpy-ops-outliner-collection-duplicate"),
("bpy.ops.pose.select_constraint_target*", "animation/armatures/posing/selecting.html#bpy-ops-pose-select-constraint-target"),
("bpy.ops.sequencer.change_effect_input*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-change-effect-input"),
+ ("bpy.ops.sequencer.strip_color_tag_set*", "video_editing/sequencer/sidebar/strip.html#bpy-ops-sequencer-strip-color-tag-set"),
("bpy.ops.sequencer.strip_transform_fit*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-strip-transform-fit"),
("bpy.types.armature.rigify_colors_lock*", "addons/rigging/rigify/metarigs.html#bpy-types-armature-rigify-colors-lock"),
("bpy.types.bakesettings.cage_extrusion*", "render/cycles/baking.html#bpy-types-bakesettings-cage-extrusion"),
("bpy.types.bakesettings.use_pass_color*", "render/cycles/baking.html#bpy-types-bakesettings-use-pass-color"),
("bpy.types.brush.boundary_falloff_type*", "sculpt_paint/sculpting/tools/boundary.html#bpy-types-brush-boundary-falloff-type"),
("bpy.types.brush.texture_overlay_alpha*", "sculpt_paint/brush/cursor.html#bpy-types-brush-texture-overlay-alpha"),
+ ("bpy.types.brushgpencilsettings.aspect*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-aspect"),
+ ("bpy.types.brushgpencilsettings.dilate*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-dilate"),
("bpy.types.brushgpencilsettings.random*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-random"),
("bpy.types.clothsettings.target_volume*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-target-volume"),
("bpy.types.colormanageddisplaysettings*", "render/color_management.html#bpy-types-colormanageddisplaysettings"),
+ ("bpy.types.colorramp.hue_interpolation*", "interface/controls/templates/color_ramp.html#bpy-types-colorramp-hue-interpolation"),
("bpy.types.compositornodebilateralblur*", "compositing/types/filter/bilateral_blur.html#bpy-types-compositornodebilateralblur"),
("bpy.types.compositornodedistancematte*", "compositing/types/matte/distance_key.html#bpy-types-compositornodedistancematte"),
("bpy.types.compositornodesetalpha.mode*", "compositing/types/converter/set_alpha.html#bpy-types-compositornodesetalpha-mode"),
@@ -834,6 +932,7 @@ url_manual_mapping = (
("bpy.types.greasepencil.use_curve_edit*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-use-curve-edit"),
("bpy.types.imagepaint.screen_grab_size*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-screen-grab-size"),
("bpy.types.linestyle*modifier_material*", "render/freestyle/view_layer/line_style/modifiers/color/material.html#bpy-types-linestyle-modifier-material"),
+ ("bpy.types.motionpath.use_custom_color*", "animation/motion_paths.html#bpy-types-motionpath-use-custom-color"),
("bpy.types.movietrackingcamera.brown_k*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-brown-k"),
("bpy.types.movietrackingcamera.brown_p*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-brown-p"),
("bpy.types.object.visible_transmission*", "render/cycles/object_settings/object_data.html#bpy-types-object-visible-transmission"),
@@ -883,8 +982,11 @@ url_manual_mapping = (
("bpy.types.brush.boundary_deform_type*", "sculpt_paint/sculpting/tools/boundary.html#bpy-types-brush-boundary-deform-type"),
("bpy.types.brush.cursor_overlay_alpha*", "sculpt_paint/brush/cursor.html#bpy-types-brush-cursor-overlay-alpha"),
("bpy.types.brush.normal_radius_factor*", "sculpt_paint/sculpting/tool_settings/brush_settings.html#bpy-types-brush-normal-radius-factor"),
+ ("bpy.types.brush.smooth_stroke_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brush-smooth-stroke-factor"),
+ ("bpy.types.brush.smooth_stroke_radius*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brush-smooth-stroke-radius"),
("bpy.types.brush.topology_rake_factor*", "sculpt_paint/sculpting/tool_settings/dyntopo.html#bpy-types-brush-topology-rake-factor"),
("bpy.types.brush.use_pose_ik_anchored*", "sculpt_paint/sculpting/tools/pose.html#bpy-types-brush-use-pose-ik-anchored"),
+ ("bpy.types.brushgpencilsettings.angle*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-angle"),
("bpy.types.clothsettings.use_pressure*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-use-pressure"),
("bpy.types.compositornodeantialiasing*", "compositing/types/filter/anti_aliasing.html#bpy-types-compositornodeantialiasing"),
("bpy.types.compositornodechannelmatte*", "compositing/types/matte/channel_key.html#bpy-types-compositornodechannelmatte"),
@@ -921,6 +1023,7 @@ url_manual_mapping = (
("bpy.types.spacefilebrowser.bookmarks*", "editors/file_browser.html#bpy-types-spacefilebrowser-bookmarks"),
("bpy.types.spaceoutliner.display_mode*", "editors/outliner/interface.html#bpy-types-spaceoutliner-display-mode"),
("bpy.types.spaceoutliner.filter_state*", "editors/outliner/interface.html#bpy-types-spaceoutliner-filter-state"),
+ ("bpy.types.spaceuveditor.show_stretch*", "editors/uv/overlays.html#bpy-types-spaceuveditor-show-stretch"),
("bpy.types.toolsettings.keyframe_type*", "editors/timeline.html#bpy-types-toolsettings-keyframe-type"),
("bpy.types.toolsettings.snap_elements*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-snap-elements"),
("bpy.types.toolsettings.use_snap_self*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-self"),
@@ -942,16 +1045,18 @@ url_manual_mapping = (
("bpy.ops.object.material_slot_assign*", "render/materials/assignment.html#bpy-ops-object-material-slot-assign"),
("bpy.ops.object.material_slot_select*", "render/materials/assignment.html#bpy-ops-object-material-slot-select"),
("bpy.ops.object.multires_unsubdivide*", "modeling/modifiers/generate/multiresolution.html#bpy-ops-object-multires-unsubdivide"),
+ ("bpy.ops.object.paths_update_visible*", "animation/motion_paths.html#bpy-ops-object-paths-update-visible"),
("bpy.ops.object.transforms_to_deltas*", "scene_layout/object/editing/apply.html#bpy-ops-object-transforms-to-deltas"),
("bpy.ops.outliner.collection_disable*", "editors/outliner/editing.html#bpy-ops-outliner-collection-disable"),
("bpy.ops.outliner.collection_isolate*", "editors/outliner/editing.html#bpy-ops-outliner-collection-isolate"),
("bpy.ops.pose.visual_transform_apply*", "animation/armatures/posing/editing/apply.html#bpy-ops-pose-visual-transform-apply"),
+ ("bpy.ops.poselib.convert_old_poselib*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-convert-old-poselib"),
("bpy.ops.render.shutter_curve_preset*", "render/cycles/render_settings/motion_blur.html#bpy-ops-render-shutter-curve-preset"),
("bpy.ops.sequencer.view_ghost_border*", "video_editing/preview/sidebar.html#bpy-ops-sequencer-view-ghost-border"),
("bpy.ops.ui.override_type_set_button*", "files/linked_libraries/library_overrides.html#bpy-ops-ui-override-type-set-button"),
- ("bpy.ops.view3d.blenderkit_asset_bar*", "addons/3d_view/blenderkit.html#bpy-ops-view3d-blenderkit-asset-bar"),
("bpy.types.animdata.action_influence*", "editors/nla/sidebar.html#bpy-types-animdata-action-influence"),
("bpy.types.armature.layers_protected*", "animation/armatures/properties/skeleton.html#bpy-types-armature-layers-protected"),
+ ("bpy.types.assetmetadata.description*", "editors/asset_browser.html#bpy-types-assetmetadata-description"),
("bpy.types.bakesettings.normal_space*", "render/cycles/baking.html#bpy-types-bakesettings-normal-space"),
("bpy.types.brush.crease_pinch_factor*", "sculpt_paint/sculpting/tools/snake_hook.html#bpy-types-brush-crease-pinch-factor"),
("bpy.types.brush.elastic_deform_type*", "sculpt_paint/sculpting/tools/elastic_deform.html#bpy-types-brush-elastic-deform-type"),
@@ -960,6 +1065,7 @@ url_manual_mapping = (
("bpy.types.brush.use_primary_overlay*", "sculpt_paint/brush/cursor.html#bpy-types-brush-use-primary-overlay"),
("bpy.types.brushtextureslot.map_mode*", "sculpt_paint/brush/texture.html#bpy-types-brushtextureslot-map-mode"),
("bpy.types.camera.passepartout_alpha*", "render/cameras.html#bpy-types-camera-passepartout-alpha"),
+ ("bpy.types.colorrampelement.position*", "interface/controls/templates/color_ramp.html#bpy-types-colorrampelement-position"),
("bpy.types.compositornodechromamatte*", "compositing/types/matte/chroma_key.html#bpy-types-compositornodechromamatte"),
("bpy.types.compositornodedilateerode*", "compositing/types/filter/dilate_erode.html#bpy-types-compositornodedilateerode"),
("bpy.types.compositornodeellipsemask*", "compositing/types/matte/ellipse_mask.html#bpy-types-compositornodeellipsemask"),
@@ -988,6 +1094,7 @@ url_manual_mapping = (
("bpy.types.materialgpencilstyle.flip*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-flip"),
("bpy.types.materialgpencilstyle.mode*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-mode"),
("bpy.types.modifier.show_in_editmode*", "modeling/modifiers/introduction.html#bpy-types-modifier-show-in-editmode"),
+ ("bpy.types.motionpath.line_thickness*", "animation/motion_paths.html#bpy-types-motionpath-line-thickness"),
("bpy.types.object.empty_display_size*", "modeling/empties.html#bpy-types-object-empty-display-size"),
("bpy.types.object.empty_display_type*", "modeling/empties.html#bpy-types-object-empty-display-type"),
("bpy.types.regionview3d.use_box_clip*", "editors/3dview/navigate/views.html#bpy-types-regionview3d-use-box-clip"),
@@ -1015,6 +1122,7 @@ url_manual_mapping = (
("bpy.types.volumedisplay.slice_depth*", "modeling/volumes/properties.html#bpy-types-volumedisplay-slice-depth"),
("bpy.types.worldmistsettings.falloff*", "render/cycles/world_settings.html#bpy-types-worldmistsettings-falloff"),
("bpy.ops.clip.lock_selection_toggle*", "editors/clip/introduction.html#bpy-ops-clip-lock-selection-toggle"),
+ ("bpy.ops.ed.lib_id_generate_preview*", "editors/asset_browser.html#bpy-ops-ed-lib-id-generate-preview"),
("bpy.ops.mesh.customdata_mask_clear*", "modeling/meshes/properties/custom_data.html#bpy-ops-mesh-customdata-mask-clear"),
("bpy.ops.mesh.customdata_skin_clear*", "modeling/meshes/properties/custom_data.html#bpy-ops-mesh-customdata-skin-clear"),
("bpy.ops.mesh.extrude_vertices_move*", "modeling/meshes/editing/vertex/extrude_vertices.html#bpy-ops-mesh-extrude-vertices-move"),
@@ -1040,6 +1148,7 @@ url_manual_mapping = (
("bpy.ops.sequencer.export_subtitles*", "video_editing/preview/introduction.html#bpy-ops-sequencer-export-subtitles"),
("bpy.ops.transform.edge_bevelweight*", "modeling/meshes/editing/edge/edge_data.html#bpy-ops-transform-edge-bevelweight"),
("bpy.ops.wm.previews_batch_generate*", "files/blend/previews.html#bpy-ops-wm-previews-batch-generate"),
+ ("bpy.types.assetmetadata.active_tag*", "editors/asset_browser.html#bpy-types-assetmetadata-active-tag"),
("bpy.types.bakesettings.cage_object*", "render/cycles/baking.html#bpy-types-bakesettings-cage-object"),
("bpy.types.bone.use_relative_parent*", "animation/armatures/bones/properties/relations.html#bpy-types-bone-use-relative-parent"),
("bpy.types.brush.auto_smooth_factor*", "sculpt_paint/sculpting/tool_settings/brush_settings.html#bpy-types-brush-auto-smooth-factor"),
@@ -1092,6 +1201,7 @@ url_manual_mapping = (
("bpy.types.shadernodeoutputmaterial*", "render/shader_nodes/output/material.html#bpy-types-shadernodeoutputmaterial"),
("bpy.types.shadernodetexenvironment*", "render/shader_nodes/textures/environment.html#bpy-types-shadernodetexenvironment"),
("bpy.types.spacesequenceeditor.show*", "video_editing/preview/introduction.html#bpy-types-spacesequenceeditor-show"),
+ ("bpy.types.spaceuveditor.show_faces*", "editors/uv/overlays.html#bpy-types-spaceuveditor-show-faces"),
("bpy.types.spaceuveditor.uv_opacity*", "editors/uv/overlays.html#bpy-types-spaceuveditor-uv-opacity"),
("bpy.types.subdividegpencilmodifier*", "grease_pencil/modifiers/generate/subdivide.html#bpy-types-subdividegpencilmodifier"),
("bpy.types.thicknessgpencilmodifier*", "grease_pencil/modifiers/deform/thickness.html#bpy-types-thicknessgpencilmodifier"),
@@ -1117,9 +1227,9 @@ url_manual_mapping = (
("bpy.ops.mesh.vert_connect_concave*", "modeling/meshes/editing/mesh/cleanup.html#bpy-ops-mesh-vert-connect-concave"),
("bpy.ops.object.multires_subdivide*", "modeling/modifiers/generate/multiresolution.html#bpy-ops-object-multires-subdivide"),
("bpy.ops.object.vertex_group_clean*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-clean"),
+ ("bpy.ops.poselib.create_pose_asset*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-create-pose-asset"),
("bpy.ops.preferences.theme_install*", "editors/preferences/themes.html#bpy-ops-preferences-theme-install"),
("bpy.ops.render.play-rendered-anim*", "render/output/animation_player.html#bpy-ops-render-play-rendered-anim"),
- ("bpy.ops.scene.blenderkit_download*", "addons/3d_view/blenderkit.html#bpy-ops-scene-blenderkit-download"),
("bpy.ops.sculpt.set_pivot_position*", "sculpt_paint/sculpting/editing/sculpt.html#bpy-ops-sculpt-set-pivot-position"),
("bpy.ops.sequencer.image_strip_add*", "video_editing/sequencer/strips/image.html#bpy-ops-sequencer-image-strip-add"),
("bpy.ops.sequencer.movie_strip_add*", "video_editing/sequencer/strips/movie.html#bpy-ops-sequencer-movie-strip-add"),
@@ -1127,11 +1237,13 @@ url_manual_mapping = (
("bpy.ops.sequencer.sound_strip_add*", "video_editing/sequencer/strips/sound.html#bpy-ops-sequencer-sound-strip-add"),
("bpy.ops.ui.remove_override_button*", "files/linked_libraries/library_overrides.html#bpy-ops-ui-remove-override-button"),
("bpy.ops.view3d.view_center_camera*", "editors/3dview/navigate/camera_view.html#bpy-ops-view3d-view-center-camera"),
+ ("bpy.types.animvizmotionpaths.type*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-type"),
("bpy.types.armaturegpencilmodifier*", "grease_pencil/modifiers/deform/armature.html#bpy-types-armaturegpencilmodifier"),
("bpy.types.brush.cloth_deform_type*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-deform-type"),
("bpy.types.brush.cloth_sim_falloff*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-sim-falloff"),
("bpy.types.brush.slide_deform_type*", "sculpt_paint/sculpting/tools/slide_relax.html#bpy-types-brush-slide-deform-type"),
("bpy.types.camera.show_composition*", "render/cameras.html#bpy-types-camera-show-composition"),
+ ("bpy.types.colorramp.interpolation*", "interface/controls/templates/color_ramp.html#bpy-types-colorramp-interpolation"),
("bpy.types.compositornodealphaover*", "compositing/types/color/alpha_over.html#bpy-types-compositornodealphaover"),
("bpy.types.compositornodebokehblur*", "compositing/types/filter/bokeh_blur.html#bpy-types-compositornodebokehblur"),
("bpy.types.compositornodecomposite*", "compositing/types/output/composite.html#bpy-types-compositornodecomposite"),
@@ -1189,7 +1301,7 @@ url_manual_mapping = (
("bpy.types.rendersettings.fps_base*", "render/output/properties/format.html#bpy-types-rendersettings-fps-base"),
("bpy.types.rigidbodyobject.enabled*", "physics/rigid_body/properties/settings.html#bpy-types-rigidbodyobject-enabled"),
("bpy.types.sceneeevee.use_overscan*", "render/eevee/render_settings/film.html#bpy-types-sceneeevee-use-overscan"),
- ("bpy.types.sequencerpreviewoverlay*", "video_editing/preview/introduction.html#bpy-types-sequencerpreviewoverlay"),
+ ("bpy.types.sequencerpreviewoverlay*", "editors/video_sequencer/preview/display/overlays.html#bpy-types-sequencerpreviewoverlay"),
("bpy.types.sequencetransform.scale*", "video_editing/sequencer/sidebar/strip.html#bpy-types-sequencetransform-scale"),
("bpy.types.shadernodeeeveespecular*", "render/shader_nodes/shader/specular_bsdf.html#bpy-types-shadernodeeeveespecular"),
("bpy.types.shadernodehuesaturation*", "render/shader_nodes/color/hue_saturation.html#bpy-types-shadernodehuesaturation"),
@@ -1237,7 +1349,6 @@ url_manual_mapping = (
("bpy.ops.sequencer.select_grouped*", "video_editing/sequencer/selecting.html#bpy-ops-sequencer-select-grouped"),
("bpy.ops.sequencer.select_handles*", "video_editing/sequencer/selecting.html#bpy-ops-sequencer-select-handles"),
("bpy.ops.uv.average_islands_scale*", "modeling/meshes/uv/editing.html#bpy-ops-uv-average-islands-scale"),
- ("bpy.ops.view3d.blenderkit_search*", "addons/3d_view/blenderkit.html#bpy-ops-view3d-blenderkit-search"),
("bpy.types.armature.axes_position*", "animation/armatures/properties/display.html#bpy-types-armature-axes-position"),
("bpy.types.armature.pose_position*", "animation/armatures/properties/skeleton.html#bpy-types-armature-pose-position"),
("bpy.types.bakesettings.use_clear*", "render/cycles/baking.html#bpy-types-bakesettings-use-clear"),
@@ -1250,6 +1361,7 @@ url_manual_mapping = (
("bpy.types.camerasolverconstraint*", "animation/constraints/motion_tracking/camera_solver.html#bpy-types-camerasolverconstraint"),
("bpy.types.clothcollisionsettings*", "physics/cloth/settings/collisions.html#bpy-types-clothcollisionsettings"),
("bpy.types.collection.hide_select*", "editors/outliner/interface.html#bpy-types-collection-hide-select"),
+ ("bpy.types.colorrampelement.color*", "interface/controls/templates/color_ramp.html#bpy-types-colorrampelement-color"),
("bpy.types.compositornodecurvergb*", "compositing/types/color/rgb_curves.html#bpy-types-compositornodecurvergb"),
("bpy.types.compositornodecurvevec*", "compositing/types/vector/vector_curves.html#bpy-types-compositornodecurvevec"),
("bpy.types.compositornodedisplace*", "compositing/types/distort/displace.html#bpy-types-compositornodedisplace"),
@@ -1290,6 +1402,7 @@ url_manual_mapping = (
("bpy.types.material.line_priority*", "render/freestyle/material.html#bpy-types-material-line-priority"),
("bpy.types.mesh.auto_smooth_angle*", "modeling/meshes/structure.html#bpy-types-mesh-auto-smooth-angle"),
("bpy.types.modifier.show_viewport*", "modeling/modifiers/introduction.html#bpy-types-modifier-show-viewport"),
+ ("bpy.types.motionpath.frame_start*", "animation/motion_paths.html#bpy-types-motionpath-frame-start"),
("bpy.types.object.visible_diffuse*", "render/cycles/object_settings/object_data.html#bpy-types-object-visible-diffuse"),
("bpy.types.objectsolverconstraint*", "animation/constraints/motion_tracking/object_solver.html#bpy-types-objectsolverconstraint"),
("bpy.types.opacitygpencilmodifier*", "grease_pencil/modifiers/color/opacity.html#bpy-types-opacitygpencilmodifier"),
@@ -1347,6 +1460,8 @@ url_manual_mapping = (
("bpy.ops.outliner.show_one_level*", "editors/outliner/editing.html#bpy-ops-outliner-show-one-level"),
("bpy.ops.paint.brush_colors_flip*", "sculpt_paint/texture_paint/tool_settings/brush_settings.html#bpy-ops-paint-brush-colors-flip"),
("bpy.ops.paint.weight_from_bones*", "sculpt_paint/weight_paint/editing.html#bpy-ops-paint-weight-from-bones"),
+ ("bpy.ops.pose.blend_to_neighbour*", "animation/armatures/posing/editing/in_betweens.html#bpy-ops-pose-blend-to-neighbour"),
+ ("bpy.ops.pose.paths_range_update*", "animation/motion_paths.html#bpy-ops-pose-paths-range-update"),
("bpy.ops.poselib.action_sanitize*", "animation/armatures/properties/pose_library.html#bpy-ops-poselib-action-sanitize"),
("bpy.ops.preferences.studiolight*", "editors/preferences/lights.html#bpy-ops-preferences-studiolight"),
("bpy.ops.scene.view_layer_remove*", "render/layers/introduction.html#bpy-ops-scene-view-layer-remove"),
@@ -1398,6 +1513,7 @@ url_manual_mapping = (
("bpy.types.geometrynodetrimcurve*", "modeling/geometry_nodes/curve/trim_curve.html#bpy-types-geometrynodetrimcurve"),
("bpy.types.gpencilsculptsettings*", "grease_pencil/properties/index.html#bpy-types-gpencilsculptsettings"),
("bpy.types.keyframe.handle_right*", "editors/graph_editor/fcurves/properties.html#bpy-types-keyframe-handle-right"),
+ ("bpy.types.lengthgpencilmodifier*", "grease_pencil/modifiers/generate/length.html#bpy-types-lengthgpencilmodifier"),
("bpy.types.light.cutoff_distance*", "render/eevee/lighting.html#bpy-types-light-cutoff-distance"),
("bpy.types.lockedtrackconstraint*", "animation/constraints/tracking/locked_track.html#bpy-types-lockedtrackconstraint"),
("bpy.types.material.blend_method*", "render/eevee/materials/settings.html#bpy-types-material-blend-method"),
@@ -1454,14 +1570,17 @@ url_manual_mapping = (
("bpy.ops.spreadsheet.toggle_pin*", "editors/spreadsheet.html#bpy-ops-spreadsheet-toggle-pin"),
("bpy.ops.uv.follow_active_quads*", "modeling/meshes/editing/uv.html#bpy-ops-uv-follow-active-quads"),
("bpy.types.arraygpencilmodifier*", "grease_pencil/modifiers/generate/array.html#bpy-types-arraygpencilmodifier"),
+ ("bpy.types.assetmetadata.author*", "editors/asset_browser.html#bpy-types-assetmetadata-author"),
("bpy.types.bone.envelope_weight*", "animation/armatures/bones/properties/deform.html#bpy-types-bone-envelope-weight"),
("bpy.types.brush.use_persistent*", "sculpt_paint/sculpting/tools/layer.html#bpy-types-brush-use-persistent"),
+ ("bpy.types.brushgpencilsettings*", "grease_pencil/modes/draw/tools/index.html#bpy-types-brushgpencilsettings"),
("bpy.types.buildgpencilmodifier*", "grease_pencil/modifiers/generate/build.html#bpy-types-buildgpencilmodifier"),
("bpy.types.camera.sensor_height*", "render/cameras.html#bpy-types-camera-sensor-height"),
("bpy.types.colorbalancemodifier*", "video_editing/sequencer/sidebar/modifiers.html#bpy-types-colorbalancemodifier"),
("bpy.types.colorgpencilmodifier*", "grease_pencil/modifiers/color/hue_saturation.html#bpy-types-colorgpencilmodifier"),
+ ("bpy.types.colorramp.color_mode*", "interface/controls/templates/color_ramp.html#bpy-types-colorramp-color-mode"),
("bpy.types.compositornodefilter*", "compositing/types/filter/filter_node.html#bpy-types-compositornodefilter"),
- ("bpy.types.compositornodehuesat*", "compositing/types/color/hue_saturation.html#bpy-types-compositornodehuesat"),
+ ("bpy.types.compositornodehuesat*", "compositing/types/color/posterize.html#bpy-types-compositornodehuesat"),
("bpy.types.compositornodeidmask*", "compositing/types/converter/id_mask.html#bpy-types-compositornodeidmask"),
("bpy.types.compositornodeinvert*", "compositing/types/color/invert.html#bpy-types-compositornodeinvert"),
("bpy.types.compositornodekeying*", "compositing/types/matte/keying.html#bpy-types-compositornodekeying"),
@@ -1479,6 +1598,7 @@ url_manual_mapping = (
("bpy.types.followpathconstraint*", "animation/constraints/relationship/follow_path.html#bpy-types-followpathconstraint"),
("bpy.types.gaussianblursequence*", "video_editing/sequencer/strips/effects/blur.html#bpy-types-gaussianblursequence"),
("bpy.types.geometrynodeboundbox*", "modeling/geometry_nodes/geometry/bounding_box.html#bpy-types-geometrynodeboundbox"),
+ ("bpy.types.geometrynodedualmesh*", "modeling/geometry_nodes/mesh/dual_mesh.html#bpy-types-geometrynodedualmesh"),
("bpy.types.geometrynodematerial*", "-1"),
("bpy.types.geometrynodemeshcone*", "modeling/geometry_nodes/mesh_primitives/cone.html#bpy-types-geometrynodemeshcone"),
("bpy.types.geometrynodemeshcube*", "modeling/geometry_nodes/mesh_primitives/cube.html#bpy-types-geometrynodemeshcube"),
@@ -1493,8 +1613,10 @@ url_manual_mapping = (
("bpy.types.mesh.use_auto_smooth*", "modeling/meshes/structure.html#bpy-types-mesh-use-auto-smooth"),
("bpy.types.meshtovolumemodifier*", "modeling/modifiers/generate/mesh_to_volume.html#bpy-types-meshtovolumemodifier"),
("bpy.types.modifier.show_render*", "modeling/modifiers/introduction.html#bpy-types-modifier-show-render"),
+ ("bpy.types.motionpath.frame_end*", "animation/motion_paths.html#bpy-types-motionpath-frame-end"),
("bpy.types.noisegpencilmodifier*", "grease_pencil/modifiers/deform/noise.html#bpy-types-noisegpencilmodifier"),
("bpy.types.object.hide_viewport*", "scene_layout/object/properties/visibility.html#bpy-types-object-hide-viewport"),
+ ("bpy.types.object.show_in_front*", "scene_layout/object/properties/display.html#bpy-types-object-show-in-front"),
("bpy.types.posebone.rigify_type*", "addons/rigging/rigify/rig_types/index.html#bpy-types-posebone-rigify-type"),
("bpy.types.preferencesfilepaths*", "editors/preferences/file_paths.html#bpy-types-preferencesfilepaths"),
("bpy.types.rigidbodyobject.mass*", "physics/rigid_body/properties/settings.html#bpy-types-rigidbodyobject-mass"),
@@ -1557,10 +1679,11 @@ url_manual_mapping = (
("bpy.ops.pose.quaternions_flip*", "animation/armatures/posing/editing/flip_quats.html#bpy-ops-pose-quaternions-flip"),
("bpy.ops.pose.select_hierarchy*", "animation/armatures/posing/selecting.html#bpy-ops-pose-select-hierarchy"),
("bpy.ops.pose.transforms_clear*", "animation/armatures/posing/editing/clear.html#bpy-ops-pose-transforms-clear"),
+ ("bpy.ops.poselib.copy_as_asset*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-copy-as-asset"),
("bpy.ops.preferences.copy_prev*", "editors/preferences/introduction.html#bpy-ops-preferences-copy-prev"),
("bpy.ops.preferences.keyconfig*", "editors/preferences/keymap.html#bpy-ops-preferences-keyconfig"),
("bpy.ops.screen.repeat_history*", "interface/undo_redo.html#bpy-ops-screen-repeat-history"),
- ("bpy.ops.script.execute_preset*", "interface/controls/templates/list_presets.html#bpy-ops-script-execute-preset"),
+ ("bpy.ops.script.execute_preset*", "interface/window_system/tabs_panels.html#bpy-ops-script-execute-preset"),
("bpy.ops.sculpt.face_sets_init*", "sculpt_paint/sculpting/editing/face_sets.html#bpy-ops-sculpt-face-sets-init"),
("bpy.ops.sequencer.change_path*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-change-path"),
("bpy.ops.sequencer.refresh_all*", "video_editing/sequencer/navigating.html#bpy-ops-sequencer-refresh-all"),
@@ -1577,7 +1700,6 @@ url_manual_mapping = (
("bpy.types.bakesettings.target*", "render/cycles/baking.html#bpy-types-bakesettings-target"),
("bpy.types.brush.cloth_damping*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-damping"),
("bpy.types.brush.icon_filepath*", "sculpt_paint/brush/brush.html#bpy-types-brush-icon-filepath"),
- ("bpy.types.brush.smooth_stroke*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brush-smooth-stroke"),
("bpy.types.brush.tip_roundness*", "sculpt_paint/sculpting/tools/clay_strips.html#bpy-types-brush-tip-roundness"),
("bpy.types.camera.display_size*", "render/cameras.html#bpy-types-camera-display-size"),
("bpy.types.camera.sensor_width*", "render/cameras.html#bpy-types-camera-sensor-width"),
@@ -1594,6 +1716,7 @@ url_manual_mapping = (
("bpy.types.curve.use_fill_caps*", "modeling/curves/properties/geometry.html#bpy-types-curve-use-fill-caps"),
("bpy.types.curve.use_map_taper*", "modeling/curves/properties/geometry.html#bpy-types-curve-use-map-taper"),
("bpy.types.cyclesworldsettings*", "render/cycles/world_settings.html#bpy-types-cyclesworldsettings"),
+ ("bpy.types.dashgpencilmodifier*", "grease_pencil/modifiers/generate/dash.html#bpy-types-dashgpencilmodifier"),
("bpy.types.fluiddomainsettings*", "physics/fluid/type/domain/index.html#bpy-types-fluiddomainsettings"),
("bpy.types.geometrynodeboolean*", "modeling/geometry_nodes/input/boolean.html#bpy-types-geometrynodeboolean"),
("bpy.types.geometrynodeinputid*", "modeling/geometry_nodes/input/id.html#bpy-types-geometrynodeinputid"),
@@ -1643,6 +1766,7 @@ url_manual_mapping = (
("bpy.ops.armature.bone_layers*", "animation/armatures/bones/editing/change_layers.html#bpy-ops-armature-bone-layers"),
("bpy.ops.armature.select_less*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-less"),
("bpy.ops.armature.select_more*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-more"),
+ ("bpy.ops.asset.bundle_install*", "editors/asset_browser.html#bpy-ops-asset-bundle-install"),
("bpy.ops.clip.add_marker_move*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-add-marker-move"),
("bpy.ops.clip.bundles_to_mesh*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-bundles-to-mesh"),
("bpy.ops.clip.detect_features*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-detect-features"),
@@ -1673,6 +1797,7 @@ url_manual_mapping = (
("bpy.ops.object.transfer_mode*", "editors/3dview/modes.html#bpy-ops-object-transfer-mode"),
("bpy.ops.outliner.show_active*", "editors/outliner/editing.html#bpy-ops-outliner-show-active"),
("bpy.ops.paint.add_simple_uvs*", "sculpt_paint/texture_paint/tool_settings/texture_slots.html#bpy-ops-paint-add-simple-uvs"),
+ ("bpy.ops.pose.paths_calculate*", "animation/motion_paths.html#bpy-ops-pose-paths-calculate"),
("bpy.ops.pose.rigify_generate*", "addons/rigging/rigify/basics.html#bpy-ops-pose-rigify-generate"),
("bpy.ops.preferences.autoexec*", "editors/preferences/save_load.html#bpy-ops-preferences-autoexec"),
("bpy.ops.scene.view_layer_add*", "render/layers/introduction.html#bpy-ops-scene-view-layer-add"),
@@ -1686,11 +1811,11 @@ url_manual_mapping = (
("bpy.ops.transform.edge_slide*", "modeling/meshes/editing/edge/edge_slide.html#bpy-ops-transform-edge-slide"),
("bpy.ops.transform.vert_slide*", "modeling/meshes/editing/vertex/slide_vertices.html#bpy-ops-transform-vert-slide"),
("bpy.ops.uv.project_from_view*", "modeling/meshes/editing/uv.html#bpy-ops-uv-project-from-view"),
- ("bpy.ops.wm.blenderkit_logout*", "addons/3d_view/blenderkit.html#bpy-ops-wm-blenderkit-logout"),
("bpy.ops.wm.memory_statistics*", "advanced/operators.html#bpy-ops-wm-memory-statistics"),
("bpy.ops.wm.recover_auto_save*", "files/blend/open_save.html#bpy-ops-wm-recover-auto-save"),
("bpy.types.adjustmentsequence*", "video_editing/sequencer/strips/adjustment.html#bpy-types-adjustmentsequence"),
("bpy.types.alphaundersequence*", "video_editing/sequencer/strips/effects/alpha_over_under_overdrop.html#bpy-types-alphaundersequence"),
+ ("bpy.types.animvizmotionpaths*", "animation/motion_paths.html#bpy-types-animvizmotionpaths"),
("bpy.types.armature.show_axes*", "animation/armatures/properties/display.html#bpy-types-armature-show-axes"),
("bpy.types.armatureconstraint*", "animation/constraints/relationship/armature.html#bpy-types-armatureconstraint"),
("bpy.types.compositornodeblur*", "compositing/types/filter/blur_node.html#bpy-types-compositornodeblur"),
@@ -1791,6 +1916,7 @@ url_manual_mapping = (
("bpy.ops.node.preview_toggle*", "interface/controls/nodes/editing.html#bpy-ops-node-preview-toggle"),
("bpy.ops.object.origin_clear*", "scene_layout/object/editing/clear.html#bpy-ops-object-origin-clear"),
("bpy.ops.object.parent_clear*", "scene_layout/object/editing/parent.html#bpy-ops-object-parent-clear"),
+ ("bpy.ops.object.paths_update*", "animation/motion_paths.html#bpy-ops-object-paths-update"),
("bpy.ops.object.shade_smooth*", "scene_layout/object/editing/shading.html#bpy-ops-object-shade-smooth"),
("bpy.ops.object.voxel_remesh*", "modeling/meshes/retopology.html#bpy-ops-object-voxel-remesh"),
("bpy.ops.pose.armature_apply*", "animation/armatures/posing/editing/apply.html#bpy-ops-pose-armature-apply"),
@@ -1810,7 +1936,6 @@ url_manual_mapping = (
("bpy.ops.uv.cylinder_project*", "modeling/meshes/editing/uv.html#bpy-ops-uv-cylinder-project"),
("bpy.ops.uv.minimize_stretch*", "modeling/meshes/uv/editing.html#bpy-ops-uv-minimize-stretch"),
("bpy.ops.uv.select_edge_ring*", "editors/uv/selecting.html#bpy-ops-uv-select-edge-ring"),
- ("bpy.ops.wm.blenderkit_login*", "addons/3d_view/blenderkit.html#bpy-ops-wm-blenderkit-login"),
("bpy.ops.wm.save_as_mainfile*", "files/blend/open_save.html#bpy-ops-wm-save-as-mainfile"),
("bpy.types.alphaoversequence*", "video_editing/sequencer/strips/effects/alpha_over_under_overdrop.html#bpy-types-alphaoversequence"),
("bpy.types.armatureeditbones*", "animation/armatures/bones/editing/index.html#bpy-types-armatureeditbones"),
@@ -1903,6 +2028,7 @@ url_manual_mapping = (
("bpy.ops.mesh.symmetry_snap*", "modeling/meshes/editing/mesh/snap_symmetry.html#bpy-ops-mesh-symmetry-snap"),
("bpy.ops.node.group_ungroup*", "interface/controls/nodes/groups.html#bpy-ops-node-group-ungroup"),
("bpy.ops.object.gpencil_add*", "grease_pencil/primitives.html#bpy-ops-object-gpencil-add"),
+ ("bpy.ops.object.paths_clear*", "animation/motion_paths.html#bpy-ops-object-paths-clear"),
("bpy.ops.object.select_less*", "scene_layout/object/selecting.html#bpy-ops-object-select-less"),
("bpy.ops.object.select_more*", "scene_layout/object/selecting.html#bpy-ops-object-select-more"),
("bpy.ops.object.track_clear*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-track-clear"),
@@ -1941,6 +2067,8 @@ url_manual_mapping = (
("bpy.types.freestylelineset*", "render/freestyle/view_layer/line_set.html#bpy-types-freestylelineset"),
("bpy.types.image.alpha_mode*", "editors/image/image_settings.html#bpy-types-image-alpha-mode"),
("bpy.types.mask.frame_start*", "movie_clip/masking/sidebar.html#bpy-types-mask-frame-start"),
+ ("bpy.types.motionpath.color*", "animation/motion_paths.html#bpy-types-motionpath-color"),
+ ("bpy.types.motionpath.lines*", "animation/motion_paths.html#bpy-types-motionpath-lines"),
("bpy.types.multicamsequence*", "video_editing/sequencer/strips/effects/multicam.html#bpy-types-multicamsequence"),
("bpy.types.multiplysequence*", "video_editing/sequencer/strips/effects/multiply.html#bpy-types-multiplysequence"),
("bpy.types.multiresmodifier*", "modeling/modifiers/generate/multiresolution.html#bpy-types-multiresmodifier"),
@@ -1984,6 +2112,7 @@ url_manual_mapping = (
("bpy.ops.armature.separate*", "animation/armatures/bones/editing/separate_bones.html#bpy-ops-armature-separate"),
("bpy.ops.clip.clean_tracks*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-clean-tracks"),
("bpy.ops.clip.delete_track*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-delete-track"),
+ ("bpy.ops.clip.select_lasso*", "movie_clip/tracking/clip/selecting.html#bpy-ops-clip-select-lasso"),
("bpy.ops.clip.solve_camera*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-solve-camera"),
("bpy.ops.constraint.delete*", "animation/constraints/interface/header.html#bpy-ops-constraint-delete"),
("bpy.ops.curve.smooth_tilt*", "modeling/curves/editing/control_points.html#bpy-ops-curve-smooth-tilt"),
@@ -1996,6 +2125,7 @@ url_manual_mapping = (
("bpy.ops.graph.easing_type*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-easing-type"),
("bpy.ops.graph.handle_type*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-handle-type"),
("bpy.ops.mask.parent_clear*", "movie_clip/masking/editing.html#bpy-ops-mask-parent-clear"),
+ ("bpy.ops.mask.select_lasso*", "movie_clip/masking/selecting.html#bpy-ops-mask-select-lasso"),
("bpy.ops.mesh.bevel.vertex*", "modeling/meshes/editing/vertex/bevel_vertices.html#bpy-ops-mesh-bevel-vertex"),
("bpy.ops.mesh.delete_loose*", "modeling/meshes/editing/mesh/cleanup.html#bpy-ops-mesh-delete-loose"),
("bpy.ops.mesh.face_shading*", "modeling/meshes/editing/face/shading.html#bpy-ops-mesh-face-shading"),
@@ -2014,6 +2144,7 @@ url_manual_mapping = (
("bpy.ops.object.shade_flat*", "scene_layout/object/editing/shading.html#bpy-ops-object-shade-flat"),
("bpy.ops.pose.group_assign*", "animation/armatures/properties/bone_groups.html#bpy-ops-pose-group-assign"),
("bpy.ops.pose.group_select*", "animation/armatures/properties/bone_groups.html#bpy-ops-pose-group-select"),
+ ("bpy.ops.pose.paths_update*", "animation/motion_paths.html#bpy-ops-pose-paths-update"),
("bpy.ops.poselib.pose_move*", "animation/armatures/properties/pose_library.html#bpy-ops-poselib-pose-move"),
("bpy.ops.preferences.addon*", "editors/preferences/addons.html#bpy-ops-preferences-addon"),
("bpy.ops.scene.light_cache*", "render/eevee/render_settings/indirect_lighting.html#bpy-ops-scene-light-cache"),
@@ -2043,6 +2174,7 @@ url_manual_mapping = (
("bpy.types.fmodifierlimits*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierlimits"),
("bpy.types.imagepaint.mode*", "sculpt_paint/texture_paint/tool_settings/texture_slots.html#bpy-types-imagepaint-mode"),
("bpy.types.latticemodifier*", "modeling/modifiers/deform/lattice.html#bpy-types-latticemodifier"),
+ ("bpy.types.materiallineart*", "render/materials/line_art.html#bpy-types-materiallineart"),
("bpy.types.musgravetexture*", "render/materials/legacy_textures/types/musgrave.html#bpy-types-musgravetexture"),
("bpy.types.object.location*", "scene_layout/object/properties/transforms.html#bpy-types-object-location"),
("bpy.types.object.rotation*", "scene_layout/object/properties/transforms.html#bpy-types-object-rotation"),
@@ -2066,6 +2198,7 @@ url_manual_mapping = (
("bpy.types.subsurfmodifier*", "modeling/modifiers/generate/subdivision_surface.html#bpy-types-subsurfmodifier"),
("bpy.types.texturenodemath*", "editors/texture_node/types/converter/math.html#bpy-types-texturenodemath"),
("bpy.types.volume.filepath*", "modeling/volumes/properties.html#bpy-types-volume-filepath"),
+ ("bpy.ops.asset.tag_remove*", "editors/asset_browser.html#bpy-ops-asset-tag-remove"),
("bpy.ops.clip.join_tracks*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-join-tracks"),
("bpy.ops.constraint.apply*", "animation/constraints/interface/header.html#bpy-ops-constraint-apply"),
("bpy.ops.curve.select_row*", "modeling/surfaces/selecting.html#bpy-ops-curve-select-row"),
@@ -2087,6 +2220,7 @@ url_manual_mapping = (
("bpy.ops.node.mute_toggle*", "interface/controls/nodes/editing.html#bpy-ops-node-mute-toggle"),
("bpy.ops.object.hide_view*", "scene_layout/object/editing/show_hide.html#bpy-ops-object-hide-view"),
("bpy.ops.object.track_set*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-track-set"),
+ ("bpy.ops.pose.paths_clear*", "animation/motion_paths.html#bpy-ops-pose-paths-clear"),
("bpy.ops.pose.scale_clear*", "animation/armatures/posing/editing/clear.html#bpy-ops-pose-scale-clear"),
("bpy.ops.poselib.pose_add*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-pose-add"),
("bpy.ops.scene.view_layer*", "render/layers/introduction.html#bpy-ops-scene-view-layer"),
@@ -2191,6 +2325,7 @@ url_manual_mapping = (
("bpy.types.armature.show*", "animation/armatures/properties/display.html#bpy-types-armature-show"),
("bpy.types.armaturebones*", "animation/armatures/bones/index.html#bpy-types-armaturebones"),
("bpy.types.arraymodifier*", "modeling/modifiers/generate/array.html#bpy-types-arraymodifier"),
+ ("bpy.types.assetmetadata*", "editors/asset_browser.html#bpy-types-assetmetadata"),
("bpy.types.bevelmodifier*", "modeling/modifiers/generate/bevel.html#bpy-types-bevelmodifier"),
("bpy.types.buildmodifier*", "modeling/modifiers/generate/build.html#bpy-types-buildmodifier"),
("bpy.types.clothmodifier*", "physics/cloth/index.html#bpy-types-clothmodifier"),
@@ -2315,6 +2450,7 @@ url_manual_mapping = (
("bpy.types.weldmodifier*", "modeling/modifiers/generate/weld.html#bpy-types-weldmodifier"),
("bpy.types.wipesequence*", "video_editing/sequencer/strips/transitions/wipe.html#bpy-types-wipesequence"),
("bpy.ops.armature.fill*", "animation/armatures/bones/editing/fill_between_joints.html#bpy-ops-armature-fill"),
+ ("bpy.ops.asset.tag_add*", "editors/asset_browser.html#bpy-ops-asset-tag-add"),
("bpy.ops.clip.prefetch*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-prefetch"),
("bpy.ops.clip.set_axis*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-set-axis"),
("bpy.ops.file.pack_all*", "files/blend/packed_data.html#bpy-ops-file-pack-all"),
@@ -2399,6 +2535,7 @@ url_manual_mapping = (
("bpy.types.lightprobe*", "render/eevee/light_probes/index.html#bpy-types-lightprobe"),
("bpy.types.maskparent*", "movie_clip/masking/sidebar.html#bpy-types-maskparent"),
("bpy.types.maskspline*", "movie_clip/masking/sidebar.html#bpy-types-maskspline"),
+ ("bpy.types.motionpath*", "animation/motion_paths.html#bpy-types-motionpath"),
("bpy.types.node.color*", "interface/controls/nodes/sidebar.html#bpy-types-node-color"),
("bpy.types.node.label*", "interface/controls/nodes/sidebar.html#bpy-types-node-label"),
("bpy.types.nodesocket*", "interface/controls/nodes/parts.html#bpy-types-nodesocket"),
@@ -2408,6 +2545,7 @@ url_manual_mapping = (
("bpy.types.renderview*", "render/output/properties/stereoscopy/index.html#bpy-types-renderview"),
("bpy.types.sceneeevee*", "render/eevee/index.html#bpy-types-sceneeevee"),
("bpy.types.vectorfont*", "modeling/texts/index.html#bpy-types-vectorfont"),
+ ("bpy.ops.asset.clear*", "files/asset_libraries/introduction.html#bpy-ops-asset-clear"),
("bpy.ops.clip.reload*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-reload"),
("bpy.ops.curve.split*", "modeling/curves/editing/curve.html#bpy-ops-curve-split"),
("bpy.ops.file.cancel*", "editors/file_browser.html#bpy-ops-file-cancel"),
@@ -2427,7 +2565,6 @@ url_manual_mapping = (
("bpy.ops.uv.rip_move*", "modeling/meshes/uv/tools/rip.html#bpy-ops-uv-rip-move"),
("bpy.ops.view3d.snap*", "scene_layout/object/editing/snap.html#bpy-ops-view3d-snap"),
("bpy.ops.view3d.zoom*", "editors/3dview/navigate/navigation.html#bpy-ops-view3d-zoom"),
- ("bpy.ops.wm.url_open*", "addons/3d_view/blenderkit.html#bpy-ops-wm-url-open"),
("bpy.types.*texspace*", "modeling/meshes/uv/uv_texture_spaces.html#bpy-types-texspace"),
("bpy.types.arealight*", "render/lights/light_object.html#bpy-types-arealight"),
("bpy.types.blenddata*", "files/data_blocks.html#bpy-types-blenddata"),
@@ -2447,6 +2584,7 @@ url_manual_mapping = (
("bpy.types.uipiemenu*", "interface/controls/buttons/menus.html#bpy-types-uipiemenu"),
("bpy.types.uipopover*", "interface/controls/buttons/menus.html#bpy-types-uipopover"),
("bpy.types.viewlayer*", "render/layers/introduction.html#bpy-types-viewlayer"),
+ ("bpy.ops.asset.mark*", "files/asset_libraries/introduction.html#bpy-ops-asset-mark"),
("bpy.ops.collection*", "scene_layout/collections/collections.html#bpy-ops-collection"),
("bpy.ops.constraint*", "animation/constraints/index.html#bpy-ops-constraint"),
("bpy.ops.curve.draw*", "modeling/curves/tools/draw.html#bpy-ops-curve-draw"),
@@ -2508,7 +2646,6 @@ url_manual_mapping = (
("bpy.ops.uv.unwrap*", "modeling/meshes/editing/uv.html#bpy-ops-uv-unwrap"),
("bpy.ops.wm.append*", "files/linked_libraries/link_append.html#bpy-ops-wm-append"),
("bpy.ops.wm.search*", "interface/controls/templates/operator_search.html#bpy-ops-wm-search"),
- ("bpy.types.animviz*", "animation/motion_paths.html#bpy-types-animviz"),
("bpy.types.lattice*", "animation/lattice.html#bpy-types-lattice"),
("bpy.types.library*", "files/linked_libraries/index.html#bpy-types-library"),
("bpy.types.speaker*", "render/output/audio/speaker.html#bpy-types-speaker"),
diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py
index 514d61e239d..dcf904410dd 100644
--- a/release/scripts/startup/bl_operators/presets.py
+++ b/release/scripts/startup/bl_operators/presets.py
@@ -649,7 +649,7 @@ class AddPresetGpencilBrush(AddPresetBase, Operator):
"settings.uv_random",
"settings.pen_jitter",
"settings.use_jitter_pressure",
- "settings.trim",
+ "settings.use_trim",
]
preset_subdir = "gpencil_brush"
diff --git a/release/scripts/startup/bl_operators/sequencer.py b/release/scripts/startup/bl_operators/sequencer.py
index 26f1c12d2b8..1a56e77b7b7 100644
--- a/release/scripts/startup/bl_operators/sequencer.py
+++ b/release/scripts/startup/bl_operators/sequencer.py
@@ -216,11 +216,19 @@ class SequencerFadesAdd(Operator):
scene.animation_data.action = action
sequences = context.selected_sequences
+
+ if not sequences:
+ self.report({'ERROR'}, "No sequences selected")
+ return {'CANCELLED'}
+
if self.type in {'CURSOR_TO', 'CURSOR_FROM'}:
sequences = [
strip for strip in sequences
if strip.frame_final_start < scene.frame_current < strip.frame_final_end
]
+ if not sequences:
+ self.report({'ERROR'}, "Current frame not within strip framerange")
+ return {'CANCELLED'}
max_duration = min(sequences, key=lambda strip: strip.frame_final_duration).frame_final_duration
max_duration = floor(max_duration / 2.0) if self.type == 'IN_OUT' else max_duration
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py
index 85381f5ee3c..570a437c213 100644
--- a/release/scripts/startup/bl_ui/properties_constraint.py
+++ b/release/scripts/startup/bl_ui/properties_constraint.py
@@ -1146,6 +1146,30 @@ class ConstraintButtonsSubPanel:
col.prop(con, "frame_start", text="Frame Start")
col.prop(con, "frame_end", text="End")
+ def draw_transform_cache_velocity(self, context):
+ self.draw_transform_cache_subpanel(
+ context, self.layout.template_cache_file_velocity
+ )
+
+ def draw_transform_cache_procedural(self, context):
+ self.draw_transform_cache_subpanel(
+ context, self.layout.template_cache_file_procedural
+ )
+
+ def draw_transform_cache_time(self, context):
+ self.draw_transform_cache_subpanel(
+ context, self.layout.template_cache_file_time_settings
+ )
+
+ def draw_transform_cache_subpanel(self, context, template_func):
+ con = self.get_constraint(context)
+ if con.cache_file is None:
+ return
+
+ layout = self.layout
+ layout.use_property_split = True
+ layout.use_property_decorate = True
+ template_func(con, "cache_file")
# Child Of Constraint
@@ -1335,7 +1359,7 @@ class BONE_PT_bLockTrackConstraint(BoneConstraintPanel, ConstraintButtonsPanel,
self.draw_lock_track(context)
-# Disance Limit Constraint
+# Distance Limit Constraint
class OBJECT_PT_bDistLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
def draw(self, context):
@@ -1534,6 +1558,54 @@ class BONE_PT_bTransformCacheConstraint(BoneConstraintPanel, ConstraintButtonsPa
self.draw_transform_cache(context)
+class OBJECT_PT_bTransformCacheConstraint_velocity(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel):
+ bl_parent_id = "OBJECT_PT_bTransformCacheConstraint"
+ bl_label = "Velocity"
+
+ def draw(self, context):
+ self.draw_transform_cache_velocity(context)
+
+
+class BONE_PT_bTransformCacheConstraint_velocity(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel):
+ bl_parent_id = "BONE_PT_bTransformCacheConstraint"
+ bl_label = "Velocity"
+
+ def draw(self, context):
+ self.draw_transform_cache_velocity(context)
+
+
+class OBJECT_PT_bTransformCacheConstraint_procedural(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel):
+ bl_parent_id = "OBJECT_PT_bTransformCacheConstraint"
+ bl_label = "Render Procedural"
+
+ def draw(self, context):
+ self.draw_transform_cache_procedural(context)
+
+
+class BONE_PT_bTransformCacheConstraint_procedural(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel):
+ bl_parent_id = "BONE_PT_bTransformCacheConstraint"
+ bl_label = "Render Procedural"
+
+ def draw(self, context):
+ self.draw_transform_cache_procedural(context)
+
+
+class OBJECT_PT_bTransformCacheConstraint_time(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel):
+ bl_parent_id = "OBJECT_PT_bTransformCacheConstraint"
+ bl_label = "Time"
+
+ def draw(self, context):
+ self.draw_transform_cache_time(context)
+
+
+class BONE_PT_bTransformCacheConstraint_time(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel):
+ bl_parent_id = "BONE_PT_bTransformCacheConstraint"
+ bl_label = "Time"
+
+ def draw(self, context):
+ self.draw_transform_cache_time(context)
+
+
# Python Constraint
class OBJECT_PT_bPythonConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel):
@@ -1620,6 +1692,9 @@ classes = (
OBJECT_PT_bCameraSolverConstraint,
OBJECT_PT_bObjectSolverConstraint,
OBJECT_PT_bTransformCacheConstraint,
+ OBJECT_PT_bTransformCacheConstraint_time,
+ OBJECT_PT_bTransformCacheConstraint_procedural,
+ OBJECT_PT_bTransformCacheConstraint_velocity,
OBJECT_PT_bPythonConstraint,
OBJECT_PT_bArmatureConstraint,
OBJECT_PT_bArmatureConstraint_bones,
@@ -1657,6 +1732,9 @@ classes = (
BONE_PT_bCameraSolverConstraint,
BONE_PT_bObjectSolverConstraint,
BONE_PT_bTransformCacheConstraint,
+ BONE_PT_bTransformCacheConstraint_time,
+ BONE_PT_bTransformCacheConstraint_procedural,
+ BONE_PT_bTransformCacheConstraint_velocity,
BONE_PT_bPythonConstraint,
BONE_PT_bArmatureConstraint,
BONE_PT_bArmatureConstraint_bones,
diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py
index e33cf8d6cfb..82c5651e5f0 100644
--- a/release/scripts/startup/bl_ui/space_filebrowser.py
+++ b/release/scripts/startup/bl_ui/space_filebrowser.py
@@ -850,7 +850,7 @@ classes = (
def asset_path_str_get(self):
asset_file_handle = bpy.context.asset_file_handle
if asset_file_handle is None:
- return None
+ return ""
if asset_file_handle.local_id:
return "Current File"
diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py
index 1562870d64f..3a668f61539 100644
--- a/release/scripts/startup/bl_ui/space_graph.py
+++ b/release/scripts/startup/bl_ui/space_graph.py
@@ -298,6 +298,8 @@ class GRAPH_MT_key(Menu):
layout.operator("graph.decimate", text="Decimate (Allowed Change)").mode = 'ERROR'
layout.operator_context = operator_context
+ layout.menu("GRAPH_MT_slider", text="Slider Operators")
+
layout.operator("graph.clean").channels = False
layout.operator("graph.clean", text="Clean Channels").channels = True
layout.operator("graph.smooth")
@@ -337,6 +339,15 @@ class GRAPH_MT_key_snap(Menu):
layout.operator("graph.frame_jump", text="Cursor to Selection")
layout.operator("graph.snap_cursor_value", text="Cursor Value to Selection")
+class GRAPH_MT_slider(Menu):
+ bl_label = "Slider Operators"
+
+ def draw(self, _context):
+ layout = self.layout
+
+ layout.operator("graph.breakdown", text="Breakdown")
+ layout.operator("graph.blend_to_neighbor", text="Blend To Neighbor")
+
class GRAPH_MT_view_pie(Menu):
bl_label = "View"
@@ -475,6 +486,7 @@ classes = (
GRAPH_MT_key,
GRAPH_MT_key_transform,
GRAPH_MT_key_snap,
+ GRAPH_MT_slider,
GRAPH_MT_delete,
GRAPH_MT_context_menu,
GRAPH_MT_channel_context_menu,
diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py
index 518979a5ef3..99abc60db6f 100644
--- a/release/scripts/startup/bl_ui/space_topbar.py
+++ b/release/scripts/startup/bl_ui/space_topbar.py
@@ -481,6 +481,7 @@ class TOPBAR_MT_file_export(Menu):
bl_owner_use_filter = False
def draw(self, _context):
+ self.layout.operator("wm.obj_export", text="Wavefront OBJ (.obj) - New")
if bpy.app.build_options.collada:
self.layout.operator("wm.collada_export",
text="Collada (Default) (.dae)")
@@ -588,7 +589,7 @@ class TOPBAR_MT_edit(Menu):
layout.separator()
- layout.operator("ed.undo_history", text="Undo History...")
+ layout.menu("TOPBAR_MT_undo_history")
layout.separator()
diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py
index 6dbb964e771..e3ae536bc37 100644
--- a/release/scripts/startup/bl_ui/space_userpref.py
+++ b/release/scripts/startup/bl_ui/space_userpref.py
@@ -772,6 +772,17 @@ class USERPREF_PT_viewport_selection(ViewportPanel, CenterAlignMixIn, Panel):
layout.prop(system, "use_select_pick_depth")
+class USERPREF_PT_viewport_subdivision(ViewportPanel, CenterAlignMixIn, Panel):
+ bl_label = "Subdivision"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw_centered(self, context, layout):
+ prefs = context.preferences
+ system = prefs.system
+
+ layout.prop(system, "use_gpu_subdivision")
+
+
# -----------------------------------------------------------------------------
# Theme Panels
@@ -2342,6 +2353,7 @@ classes = (
USERPREF_PT_viewport_quality,
USERPREF_PT_viewport_textures,
USERPREF_PT_viewport_selection,
+ USERPREF_PT_viewport_subdivision,
USERPREF_PT_edit_objects,
USERPREF_PT_edit_objects_new,
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 01850676519..4d62d7072cb 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -698,6 +698,8 @@ class VIEW3D_PT_tools_weight_gradient(Panel, View3DPaintPanel):
@classmethod
def poll(cls, context):
settings = context.tool_settings.weight_paint
+ if settings is None:
+ return False
brush = settings.brush
return brush is not None
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index c8ddd86a195..6ce11e1eace 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -150,6 +150,7 @@ def mesh_node_items(context):
yield NodeItem("GeometryNodeSubdivisionSurface")
yield NodeItem("GeometryNodeTriangulate")
yield NodeItemCustom(draw=lambda self, layout, context: layout.separator())
+ yield NodeItem("GeometryNodeInputMeshEdgeAngle")
yield NodeItem("GeometryNodeInputMeshEdgeNeighbors")
yield NodeItem("GeometryNodeInputMeshEdgeVertices")
yield NodeItem("GeometryNodeInputMeshFaceArea")
@@ -753,6 +754,7 @@ geometry_node_categories = [
NodeItem("GeometryNodeImageTexture"),
]),
GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[
+ NodeItem("GeometryNodeAccumulateField"),
NodeItem("ShaderNodeMapRange"),
NodeItem("ShaderNodeFloatCurve"),
NodeItem("ShaderNodeClamp"),
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 0fff6d27031..932ef234342 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -413,14 +413,6 @@ void DM_calc_loop_tangents(DerivedMesh *dm,
const char (*tangent_names)[MAX_NAME],
int tangent_names_len);
-/* debug only */
-#ifndef NDEBUG
-char *DM_debug_info(DerivedMesh *dm);
-void DM_debug_print(DerivedMesh *dm);
-
-bool DM_is_valid(DerivedMesh *dm);
-#endif
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index ea8ee3f93b1..5dd98dbb9a3 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -253,12 +253,28 @@ void BKE_pose_channel_session_uuid_generate(struct bPoseChannel *pchan);
*/
struct bPoseChannel *BKE_pose_channel_find_name(const struct bPose *pose, const char *name);
/**
+ * Checks if the bone is on a visible armature layer
+ *
+ * \return true if on a visible layer, false otherwise.
+ */
+bool BKE_pose_is_layer_visible(const struct bArmature *arm, const struct bPoseChannel *pchan);
+/**
* Find the active pose-channel for an object
- * (we can't just use pose, as layer info is in armature)
*
- * \note #Object, not #bPose is used here, as we need layer info from Armature.
+ * \param check_arm_layer: checks if the bone is on a visible armature layer (this might be skipped
+ * (e.g. for "Show Active" from the Outliner).
+ * \return #bPoseChannel if found or NULL.
+ * \note #Object, not #bPose is used here, as we need info (layer/active bone) from Armature.
+ */
+struct bPoseChannel *BKE_pose_channel_active(struct Object *ob, const bool check_arm_layer);
+/**
+ * Find the active pose-channel for an object if it is on a visible armature layer
+ * (calls #BKE_pose_channel_active with check_arm_layer set to true)
+ *
+ * \return #bPoseChannel if found or NULL.
+ * \note #Object, not #bPose is used here, as we need info (layer/active bone) from Armature.
*/
-struct bPoseChannel *BKE_pose_channel_active(struct Object *ob);
+struct bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob);
/**
* Use this when detecting the "other selected bone",
* when we have multiple armatures in pose mode.
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 6197cb93c95..4733c96543e 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -186,11 +186,6 @@ void BKE_animdata_transfer_by_basepath(struct Main *bmain,
struct ID *dstID,
struct ListBase *basepaths);
-char *BKE_animdata_driver_path_hack(struct bContext *C,
- struct PointerRNA *ptr,
- struct PropertyRNA *prop,
- char *base_path);
-
/* ************************************* */
/* Batch AnimData API */
diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h
index 2c83bef7517..1e2dcf09b64 100644
--- a/source/blender/blenkernel/BKE_attribute.h
+++ b/source/blender/blenkernel/BKE_attribute.h
@@ -38,10 +38,6 @@ struct ID;
struct ReportList;
/* Attribute.domain */
-/**
- * \warning Careful when changing existing items.
- * Arrays may be initialized from this (e.g. #DATASET_layout_hierarchy).
- */
typedef enum AttributeDomain {
ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */
ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index fd30813a506..114d9e1e0d7 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -30,6 +30,39 @@
#include "BLI_float3.hh"
#include "BLI_function_ref.hh"
+/**
+ * This file defines classes that help to provide access to attribute data on a #GeometryComponent.
+ * The API for retrieving attributes is defined in `BKE_geometry_set.hh`, but this comment has some
+ * general comments about the system.
+ *
+ * Attributes are stored in geometry data, though they can also be stored in instances. Their
+ * storage is often tied to `CustomData`, which is a system to store "layers" of data with specific
+ * types and names. However, since `CustomData` was added to Blender before attributes were
+ * conceptualized, it combines the "legacy" style of task-specific attribute types with generic
+ * types like "Float". The attribute API here only provides access to generic types.
+ *
+ * Attributes are retrieved from geometry components by providing an "id" (#AttributeIDRef). This
+ * is most commonly just an attribute name. The attribute API on geometry components has some more
+ * advanced capabilities:
+ * 1. Read-only access: With a `const` geometry component, an attribute on the geometry cannot be
+ * modified, so the `for_write` and `for_output` versions of the API are not available. This is
+ * extremely important for writing coherent bug-free code. When an attribute is retrieved with
+ * write access, via #WriteAttributeLookup or #OutputAttribute, the geometry component must be
+ * tagged to clear caches that depend on the changed data.
+ * 2. Domain interpolation: When retrieving an attribute, a domain (#AttributeDomain) can be
+ * provided. If the attribute is stored on a different domain and conversion is possible, a
+ * version of the data interpolated to the requested domain will be provided. These conversions
+ * are implemented in each #GeometryComponent by `attribute_try_adapt_domain_impl`.
+ * 3. Implicit type conversion: In addition to interpolating domains, attribute types can be
+ * converted, using the conversions in `BKE_type_conversions.hh`. The #VArray / #GVArray system
+ * makes it possible to only convert necessary indices on-demand.
+ * 4. Anonymous attributes: The "id" used to look up an attribute can also be an anonymous
+ * attribute reference. Currently anonymous attributes are only used in geometry nodes.
+ * 5. Abstracted storage: Since the data returned from the API is usually a virtual array,
+ * it doesn't have to be stored contiguously (even though that is generally preferred). This
+ * allows accessing "legacy" attributes like `material_index`, which is stored in `MPoly`.
+ */
+
namespace blender::bke {
/**
@@ -181,11 +214,14 @@ struct ReadAttributeLookup {
* Used when looking up a "plain attribute" based on a name for reading from it and writing to it.
*/
struct WriteAttributeLookup {
- /* The virtual array that is used to read from and write to the attribute. */
+ /** The virtual array that is used to read from and write to the attribute. */
GVMutableArray varray;
- /* Domain the attributes lives on in the geometry. */
+ /** Domain the attributes lives on in the geometry component. */
AttributeDomain domain;
- /* Call this after changing the attribute to invalidate caches that depend on this attribute. */
+ /**
+ * Call this after changing the attribute to invalidate caches that depend on this attribute.
+ * \note Do not call this after the component the attribute is from has been destructed.
+ */
std::function<void()> tag_modified_fn;
/* Convenience function to check if the attribute has been found. */
@@ -205,6 +241,10 @@ struct WriteAttributeLookup {
* VMutableArray_Span in many cases).
* - An output attribute can live side by side with an existing attribute with a different domain
* or data type. The old attribute will only be overwritten when the #save function is called.
+ *
+ * \note The lifetime of an output attribute should not be longer than the the lifetime of the
+ * geometry component it comes from, since it can keep a reference to the component for use in
+ * the #save method.
*/
class OutputAttribute {
public:
diff --git a/source/blender/blenkernel/BKE_bpath.h b/source/blender/blenkernel/BKE_bpath.h
index bae151f6a72..bc9e3f01e96 100644
--- a/source/blender/blenkernel/BKE_bpath.h
+++ b/source/blender/blenkernel/BKE_bpath.h
@@ -49,6 +49,8 @@ typedef enum eBPathForeachFlag {
BKE_BPATH_FOREACH_PATH_SKIP_LINKED = (1 << 1),
/** Skip paths when their matching data is packed. */
BKE_BPATH_FOREACH_PATH_SKIP_PACKED = (1 << 2),
+ /** Resolve tokens within a virtual filepath to a single, concrete, filepath. */
+ BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN = (1 << 3),
/* Skip weak reference paths. Those paths are typically 'nice to have' extra information, but are
* not used as actual source of data by the current .blend file.
*
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h
index 46c1fe0d33d..7dfda7b5121 100644
--- a/source/blender/blenkernel/BKE_collection.h
+++ b/source/blender/blenkernel/BKE_collection.h
@@ -163,7 +163,21 @@ bool BKE_scene_collections_object_remove(struct Main *bmain,
struct Scene *scene,
struct Object *object,
const bool free_us);
+
+/**
+ * Check all collections in \a bmain (including embedded ones in scenes) for CollectionObject with
+ * NULL object pointer, and remove them.
+ */
void BKE_collections_object_remove_nulls(struct Main *bmain);
+
+/**
+ * Check all collections in \a bmain (including embedded ones in scenes) for duplicate
+ * CollectionObject with a same object pointer within a same object, and remove them.
+ *
+ * NOTE: Always keeps the first of the detected duplicates.
+ */
+void BKE_collections_object_remove_duplicates(struct Main *bmain);
+
/**
* Remove all NULL children from parent collections of changed \a collection.
* This is used for library remapping, where these pointers have been set to NULL.
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index ac864c7f82c..f50270ed4e7 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -282,8 +282,9 @@ bool CTX_data_dir(const char *member);
ListBase ctx_data_list; \
CollectionPointerLink *ctx_link; \
CTX_data_##member(C, &ctx_data_list); \
- for (ctx_link = ctx_data_list.first; ctx_link; ctx_link = ctx_link->next) { \
- Type instance = ctx_link->ptr.data;
+ for (ctx_link = (CollectionPointerLink *)ctx_data_list.first; ctx_link; \
+ ctx_link = ctx_link->next) { \
+ Type instance = (Type)ctx_link->ptr.data;
#define CTX_DATA_END \
} \
diff --git a/source/blender/blenkernel/BKE_fcurve_driver.h b/source/blender/blenkernel/BKE_fcurve_driver.h
index 18676dfcb38..7e4e0ad3c2a 100644
--- a/source/blender/blenkernel/BKE_fcurve_driver.h
+++ b/source/blender/blenkernel/BKE_fcurve_driver.h
@@ -105,6 +105,13 @@ void driver_change_variable_type(struct DriverVar *dvar, int type);
*/
void driver_variable_name_validate(struct DriverVar *dvar);
/**
+ * Ensure the driver variable's name is unique.
+ *
+ * Assumes the driver variable has already been assigned to the driver, so that
+ * the prev/next pointers can be used to find the other variables.
+ */
+void driver_variable_unique_name(struct DriverVar *dvar);
+/**
* Add a new driver variable.
*/
struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver);
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index 79f29e0954e..88e45baad15 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -93,41 +93,64 @@ class GeometryComponent {
GeometryComponentType type() const;
- /* Return true when any attribute with this name exists, including built in attributes. */
+ /**
+ * Return true when any attribute with this name exists, including built in attributes.
+ */
bool attribute_exists(const blender::bke::AttributeIDRef &attribute_id) const;
- /* Return the data type and domain of an attribute with the given name if it exists. */
+ /**
+ * Return the data type and domain of an attribute with the given name if it exists.
+ */
std::optional<AttributeMetaData> attribute_get_meta_data(
const blender::bke::AttributeIDRef &attribute_id) const;
- /* Returns true when the geometry component supports this attribute domain. */
+ /**
+ * Return true when the geometry component supports this attribute domain.
+ * \note Conceptually this function is static, the result is always the same for different
+ * instances of the same geometry component type.
+ */
bool attribute_domain_supported(const AttributeDomain domain) const;
- /* Can only be used with supported domain types. */
+ /**
+ * Return the length of a specific domain, or 0 if the domain is not supported.
+ */
virtual int attribute_domain_size(const AttributeDomain domain) const;
+ /**
+ * Return true if the attribute name corresponds to a built-in attribute with a hardcoded domain
+ * and data type.
+ */
bool attribute_is_builtin(const blender::StringRef attribute_name) const;
bool attribute_is_builtin(const blender::bke::AttributeIDRef &attribute_id) const;
- /* Get read-only access to the highest priority attribute with the given name.
- * Returns null if the attribute does not exist. */
+ /**
+ * Get read-only access to an attribute with the given name or id, on the highest priority domain
+ * if there is a name collision.
+ * \return null if the attribute does not exist.
+ */
blender::bke::ReadAttributeLookup attribute_try_get_for_read(
const blender::bke::AttributeIDRef &attribute_id) const;
- /* Get read and write access to the highest priority attribute with the given name.
- * Returns null if the attribute does not exist. */
+ /**
+ * Get read and write access to an attribute with the given name or id, on the highest priority
+ * domain if there is a name collision.
+ * \note #WriteAttributeLookup.tag_modified_fn must be called after modifying data.
+ * \return null if the attribute does not exist
+ */
blender::bke::WriteAttributeLookup attribute_try_get_for_write(
const blender::bke::AttributeIDRef &attribute_id);
- /* Get a read-only attribute for the domain based on the given attribute. This can be used to
+ /**
+ * Get a read-only attribute for the domain based on the given attribute. This can be used to
* interpolate from one domain to another.
- * Returns null if the interpolation is not implemented. */
+ * \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
{
return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain);
}
-
+ /* Use instead of the method above when the type is known at compile time for type safety. */
template<typename T>
blender::VArray<T> attribute_try_adapt_domain(const blender::VArray<T> &varray,
const AttributeDomain from_domain,
@@ -137,17 +160,19 @@ class GeometryComponent {
.template typed<T>();
}
- /* Returns true when the attribute has been deleted. */
+ /** Returns true when the attribute has been deleted. */
bool attribute_try_delete(const blender::bke::AttributeIDRef &attribute_id);
- /* Returns true when the attribute has been created. */
+ /** Returns true when the attribute has been created. */
bool attribute_try_create(const blender::bke::AttributeIDRef &attribute_id,
const AttributeDomain domain,
const CustomDataType data_type,
const AttributeInit &initializer);
- /* Try to create the builtin attribute with the given name. No data type or domain has to be
- * provided, because those are fixed for builtin attributes. */
+ /**
+ * Try to create the builtin attribute with the given name. No data type or domain has to be
+ * provided, because those are fixed for builtin attributes.
+ */
bool attribute_try_create_builtin(const blender::StringRef attribute_name,
const AttributeInit &initializer);
@@ -160,34 +185,41 @@ class GeometryComponent {
virtual bool is_empty() const;
- /* Get a virtual array to read the data of an attribute on the given domain and data type.
- * Returns null when the attribute does not exist or cannot be converted to the requested domain
- * and data type. */
+ /**
+ * Get a virtual array that refers to the data of an attribute, interpolated to the given domain
+ * 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,
const AttributeDomain domain,
const CustomDataType data_type) const;
- /* Get a virtual array to read the data of an attribute on the given domain. The data type is
- * left unchanged. Returns null when the attribute does not exist or cannot be adapted to the
- * requested domain. */
+ /**
+ * 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,
const AttributeDomain domain) const;
- /* Get a virtual array to read data of an attribute with the given data type. The domain is
- * left unchanged. Returns null when the attribute does not exist or cannot be converted to the
- * requested data type. */
+ /**
+ * Get a virtual array that refers to the data of an attribute converted to the given data type.
+ * The attribute's domain is left unchanged. Returns null when the attribute does not exist or
+ * cannot be converted.
+ */
blender::bke::ReadAttributeLookup attribute_try_get_for_read(
const blender::bke::AttributeIDRef &attribute_id, const CustomDataType data_type) const;
- /* Get a virtual array to read the data of an attribute. If that is not possible, the returned
- * virtual array will contain a default value. This never returns null. */
+ /**
+ * Get a virtual array that refers to the data of an attribute, interpolated to the given domain
+ * 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,
const AttributeDomain domain,
const CustomDataType data_type,
const void *default_value = nullptr) const;
-
- /* Should be used instead of the method above when the requested data type is known at compile
- * time for better type safety. */
+ /* 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,
@@ -214,16 +246,7 @@ class GeometryComponent {
const AttributeDomain domain,
const CustomDataType data_type,
const void *default_value = nullptr);
-
- /* Same as attribute_try_get_for_output, but should be used when the original values in the
- * attributes are not read, i.e. the attribute is used only for output. Since values are not read
- * from this attribute, no default value is necessary. */
- blender::bke::OutputAttribute attribute_try_get_for_output_only(
- const blender::bke::AttributeIDRef &attribute_id,
- const AttributeDomain domain,
- const CustomDataType data_type);
-
- /* Statically typed method corresponding to the equally named generic one. */
+ /* Use instead of the method above when the type is known at compile time for type safety. */
template<typename T>
blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output(
const blender::bke::AttributeIDRef &attribute_id,
@@ -235,7 +258,17 @@ class GeometryComponent {
return this->attribute_try_get_for_output(attribute_id, domain, data_type, &default_value);
}
- /* Statically typed method corresponding to the equally named generic one. */
+ /**
+ * Same as #attribute_try_get_for_output, but should be used when the original values in the
+ * attributes are not read, i.e. the attribute is used only for output. The can be faster because
+ * it can avoid interpolation and conversion of existing values. Since values are not read from
+ * this attribute, no default value is necessary.
+ */
+ blender::bke::OutputAttribute attribute_try_get_for_output_only(
+ const blender::bke::AttributeIDRef &attribute_id,
+ const AttributeDomain domain,
+ const CustomDataType data_type);
+ /* Use instead of the method above when the type is known at compile time for type safety. */
template<typename T>
blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output_only(
const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain)
@@ -339,7 +372,7 @@ struct GeometrySet {
*/
blender::Vector<const GeometryComponent *> get_components_for_read() const;
- void compute_boundbox_without_instances(blender::float3 *r_min, blender::float3 *r_max) const;
+ bool compute_boundbox_without_instances(blender::float3 *r_min, blender::float3 *r_max) const;
friend std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set);
@@ -889,6 +922,12 @@ class InstancesComponent : public GeometryComponent {
int instances_amount() const;
int references_amount() const;
+ /**
+ * Remove the indices that are not contained in the mask input, and remove unused instance
+ * references afterwards.
+ */
+ void remove_instances(const blender::IndexMask mask);
+
blender::Span<int> almost_unique_ids() const;
blender::bke::CustomDataAttributes &attributes();
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index 4db6da4b3ea..0709d05c0d1 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -36,6 +36,7 @@ struct ImageFormatData;
struct ImagePool;
struct ImageTile;
struct ImbFormatOptions;
+struct ListBase;
struct Main;
struct Object;
struct RenderResult;
@@ -284,6 +285,10 @@ void BKE_image_ensure_viewer_views(const struct RenderData *rd,
void BKE_image_user_frame_calc(struct Image *ima, struct ImageUser *iuser, int cfra);
int BKE_image_user_frame_get(const struct ImageUser *iuser, int cfra, bool *r_is_in_range);
void BKE_image_user_file_path(struct ImageUser *iuser, struct Image *ima, char *path);
+void BKE_image_user_file_path_ex(struct ImageUser *iuser,
+ struct Image *ima,
+ char *path,
+ bool resolve_udim);
void BKE_image_editors_update_frame(const struct Main *bmain, int cfra);
/**
@@ -397,6 +402,18 @@ void BKE_image_get_tile_label(struct Image *ima,
char *label,
int len_label);
+/**
+ * Checks whether the given filepath refers to a UDIM tiled texture.
+ * If yes, the range from the lowest to the highest tile is returned.
+ *
+ * `filepath` may be modified to ensure a UDIM token is present.
+ * `tiles` may be filled even if the result ultimately is false!
+ */
+bool BKE_image_get_tile_info(char *filepath,
+ struct ListBase *tiles,
+ int *tile_start,
+ int *tile_range);
+
struct ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label);
bool BKE_image_remove_tile(struct Image *ima, struct ImageTile *tile);
void BKE_image_reassign_tile(struct Image *ima, struct ImageTile *tile, int new_tile_number);
@@ -411,6 +428,40 @@ bool BKE_image_fill_tile(struct Image *ima,
int planes,
bool is_float);
+typedef enum {
+ UDIM_TILE_FORMAT_NONE = 0,
+ UDIM_TILE_FORMAT_UDIM = 1,
+ UDIM_TILE_FORMAT_UVTILE = 2
+} eUDIM_TILE_FORMAT;
+
+/**
+ * Ensures that `filename` contains a UDIM token if we find a supported format pattern.
+ */
+void BKE_image_ensure_tile_token(char *filename);
+
+/**
+ * When provided with an absolute virtual filepath, check to see if at least
+ * one concrete file exists.
+ * Note: This function requires directory traversal and may be inefficient in time-critical,
+ * or iterative, code paths.
+ */
+bool BKE_image_tile_filepath_exists(const char *filepath);
+
+/**
+ * Retrieves the UDIM token format and returns the pattern from the provided `filepath`.
+ * The returned pattern is typically passed to either `BKE_image_get_tile_number_from_filepath` or
+ * `BKE_image_set_filepath_from_tile_number`.
+ */
+char *BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format);
+bool BKE_image_get_tile_number_from_filepath(const char *filepath,
+ const char *pattern,
+ eUDIM_TILE_FORMAT tile_format,
+ int *r_tile_number);
+void BKE_image_set_filepath_from_tile_number(char *filepath,
+ const char *pattern,
+ eUDIM_TILE_FORMAT tile_format,
+ int tile_number);
+
struct ImageTile *BKE_image_get_tile(struct Image *ima, int tile_number);
struct ImageTile *BKE_image_get_tile_from_iuser(struct Image *ima, const struct ImageUser *iuser);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index c39583d234a..2ccd317e3e4 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -867,15 +867,12 @@ void BKE_mesh_calc_relative_deform(const struct MPoly *mpoly,
bool BKE_mesh_validate(struct Mesh *me, const bool do_verbose, const bool cddata_check_mask);
/**
* Checks if a Mesh is valid without any modification. This is always verbose.
- *
- * \see #DM_is_valid to call on derived meshes
- *
- * \returns is_valid.
+ * \returns True if the mesh is valid.
*/
bool BKE_mesh_is_valid(struct Mesh *me);
/**
* Check all material indices of polygons are valid, invalid ones are set to 0.
- * \returns is_valid.
+ * \returns True if the material indices are valid.
*/
bool BKE_mesh_validate_material_indices(struct Mesh *me);
diff --git a/source/blender/blenkernel/BKE_mesh_wrapper.h b/source/blender/blenkernel/BKE_mesh_wrapper.h
index 2fe264fd0f7..12e8fd71503 100644
--- a/source/blender/blenkernel/BKE_mesh_wrapper.h
+++ b/source/blender/blenkernel/BKE_mesh_wrapper.h
@@ -22,6 +22,7 @@
struct BMEditMesh;
struct CustomData_MeshMasks;
struct Mesh;
+struct Object;
#ifdef __cplusplus
extern "C" {
@@ -51,6 +52,8 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const struct Mesh *me,
int vert_coords_len,
const float mat[4][4]);
+struct Mesh *BKE_mesh_wrapper_ensure_subdivision(const struct Object *ob, struct Mesh *me);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index a2959556810..56b44994985 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -34,6 +34,7 @@
#include "RNA_types.h"
#ifdef __cplusplus
+# include "BLI_map.hh"
# include "BLI_string_ref.hh"
#endif
@@ -413,7 +414,6 @@ typedef struct bNodeTreeType {
/* calls allowing threaded composite */
void (*localize)(struct bNodeTree *localtree, struct bNodeTree *ntree);
- void (*local_sync)(struct bNodeTree *localtree, struct bNodeTree *ntree);
void (*local_merge)(struct Main *bmain, struct bNodeTree *localtree, struct bNodeTree *ntree);
/* Tree update. Overrides `nodetype->updatetreefunc` ! */
@@ -501,16 +501,13 @@ void ntreeFreeLocalTree(struct bNodeTree *ntree);
struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type);
bool ntreeHasType(const struct bNodeTree *ntree, int type);
bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup);
-void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree);
void ntreeUpdateAllNew(struct Main *main);
-/**
- * \param tree_update_flag: #eNodeTreeUpdate enum.
- */
-void ntreeUpdateAllUsers(struct Main *main, struct ID *id, int tree_update_flag);
+void ntreeUpdateAllUsers(struct Main *main, struct ID *id);
void ntreeGetDependencyList(struct bNodeTree *ntree,
struct bNode ***r_deplist,
int *r_deplist_len);
+void ntreeUpdateNodeLevels(struct bNodeTree *ntree);
/**
* XXX: old trees handle output flags automatically based on special output
@@ -521,21 +518,12 @@ void ntreeSetOutput(struct bNodeTree *ntree);
void ntreeFreeCache(struct bNodeTree *ntree);
-bool ntreeNodeExists(const struct bNodeTree *ntree, const struct bNode *testnode);
-bool ntreeOutputExists(const struct bNode *node, const struct bNodeSocket *testsock);
void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable);
/**
* Returns localized tree for execution in threads.
*/
struct bNodeTree *ntreeLocalize(struct bNodeTree *ntree);
/**
- * Sync local composite with real tree.
- * The local tree is supposed to be running, be careful moving previews!
- *
- * Is called by jobs manager, outside threads, so it doesn't happen during draw.
- */
-void ntreeLocalSync(struct bNodeTree *localtree, struct bNodeTree *ntree);
-/**
* Merge local tree results back, and free local tree.
*
* We have to assume the editor already changed completely.
@@ -700,31 +688,28 @@ void nodeRemoveNode(struct Main *bmain,
struct bNode *node,
bool do_id_user);
-/**
- * \param ntree: is the target tree.
- *
- * \note keep socket list order identical, for copying links.
- * \note `unique_name` needs to be true. It's only disabled for speed when doing GPUnodetrees.
- */
-struct bNode *BKE_node_copy_ex(struct bNodeTree *ntree,
- const struct bNode *node_src,
- const int flag,
- const bool unique_name);
+#ifdef __cplusplus
+
+namespace blender::bke {
/**
- * Same as #BKE_node_copy_ex but stores pointers to a new node and its sockets in the source node.
- *
- * NOTE: DANGER ZONE!
- *
- * TODO(sergey): Maybe it's better to make BKE_node_copy_ex() return a mapping from old node and
- * sockets to new one.
+ * \note keeps socket list order identical, for copying links.
+ * \note `unique_name` should usually be true, unless the \a dst_tree is temporary,
+ * or the names can already be assumed valid.
*/
-struct bNode *BKE_node_copy_store_new_pointers(struct bNodeTree *ntree,
- struct bNode *node_src,
- const int flag);
-struct bNodeTree *ntreeCopyTree_ex_new_pointers(const struct bNodeTree *ntree,
- struct Main *bmain,
- const bool do_id_user);
+bNode *node_copy_with_mapping(bNodeTree *dst_tree,
+ const bNode &node_src,
+ int flag,
+ bool unique_name,
+ Map<const bNodeSocket *, bNodeSocket *> &new_socket_map);
+
+bNode *node_copy(bNodeTree *dst_tree, const bNode &src_node, int flag, bool unique_name);
+
+} // namespace blender::bke
+
+#endif
+
+bNode *BKE_node_copy(bNodeTree *dst_tree, const bNode *src_node, int flag, bool unique_name);
/**
* Also used via RNA API, so we check for proper input output direction.
@@ -833,12 +818,7 @@ void nodeClearActive(struct bNodeTree *ntree);
void nodeClearActiveID(struct bNodeTree *ntree, short idtype);
struct bNode *nodeGetActiveTexture(struct bNodeTree *ntree);
-void nodeUpdate(struct bNodeTree *ntree, struct bNode *node);
-bool nodeUpdateID(struct bNodeTree *ntree, struct ID *id);
-void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node);
-
int nodeSocketIsHidden(const struct bNodeSocket *sock);
-void ntreeTagUsedSockets(struct bNodeTree *ntree);
void nodeSetSocketAvailability(struct bNodeTree *ntree,
struct bNodeSocket *sock,
bool is_available);
@@ -960,28 +940,16 @@ bNodePreview *BKE_node_preview_verify(
struct bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create);
bNodePreview *BKE_node_preview_copy(struct bNodePreview *preview);
void BKE_node_preview_free(struct bNodePreview *preview);
-void BKE_node_preview_init_tree(struct bNodeTree *ntree,
- int xsize,
- int ysize,
- bool create_previews);
+void BKE_node_preview_init_tree(struct bNodeTree *ntree, int xsize, int ysize);
void BKE_node_preview_free_tree(struct bNodeTree *ntree);
void BKE_node_preview_remove_unused(struct bNodeTree *ntree);
void BKE_node_preview_clear(struct bNodePreview *preview);
void BKE_node_preview_clear_tree(struct bNodeTree *ntree);
-void BKE_node_preview_sync_tree(struct bNodeTree *to_ntree, struct bNodeTree *from_ntree);
void BKE_node_preview_merge_tree(struct bNodeTree *to_ntree,
struct bNodeTree *from_ntree,
bool remove_old);
-/**
- * Hack warning! this function is only used for shader previews,
- * and since it gets called multiple times per pixel for Z-transparency we only add the color once.
- * Preview gets cleared before it starts render though.
- */
-void BKE_node_preview_set_pixel(
- struct bNodePreview *preview, const float col[4], int x, int y, bool do_manage);
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1001,9 +969,11 @@ bool nodeGroupPoll(struct bNodeTree *nodetree,
/**
* Initialize a new node type struct with default values and callbacks.
*/
-void node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
-void node_type_base_custom(
- struct bNodeType *ntype, const char *idname, const char *name, short nclass, short flag);
+void node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
+void node_type_base_custom(struct bNodeType *ntype,
+ const char *idname,
+ const char *name,
+ short nclass);
void node_type_socket_templates(struct bNodeType *ntype,
struct bNodeSocketTemplate *inputs,
struct bNodeSocketTemplate *outputs);
@@ -1170,7 +1140,6 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
#define SH_NODE_SEPRGB 120
#define SH_NODE_COMBRGB 121
#define SH_NODE_HUE_SAT 122
-#define NODE_DYNAMIC 123
#define SH_NODE_OUTPUT_MATERIAL 124
#define SH_NODE_OUTPUT_WORLD 125
@@ -1739,6 +1708,8 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS 1143
#define GEO_NODE_INPUT_MESH_ISLAND 1144
#define GEO_NODE_INPUT_SCENE_TIME 1145
+#define GEO_NODE_ACCUMULATE_FIELD 1146
+#define GEO_NODE_INPUT_MESH_EDGE_ANGLE 1147
/** \} */
diff --git a/source/blender/blenkernel/BKE_node_tree_update.h b/source/blender/blenkernel/BKE_node_tree_update.h
new file mode 100644
index 00000000000..d549eec2247
--- /dev/null
+++ b/source/blender/blenkernel/BKE_node_tree_update.h
@@ -0,0 +1,110 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+struct bNode;
+struct bNodeSocket;
+struct bNodeTree;
+struct bNodeLink;
+struct Main;
+struct ID;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Tag tree as changed without providing any more information about what has changed exactly.
+ * The update process has to assume that everything may have changed.
+ *
+ * Using one of the methods below to tag the tree after changes is preffered when possible.
+ */
+void BKE_ntree_update_tag_all(struct bNodeTree *ntree);
+
+/**
+ * More specialized tag functions that may result in a more efficient update.
+ */
+
+void BKE_ntree_update_tag_node_property(struct bNodeTree *ntree, struct bNode *node);
+void BKE_ntree_update_tag_node_new(struct bNodeTree *ntree, struct bNode *node);
+void BKE_ntree_update_tag_node_removed(struct bNodeTree *ntree);
+void BKE_ntree_update_tag_node_mute(struct bNodeTree *ntree, struct bNode *node);
+void BKE_ntree_update_tag_node_internal_link(struct bNodeTree *ntree, struct bNode *node);
+
+void BKE_ntree_update_tag_socket_property(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_new(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_type(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_availability(struct bNodeTree *ntree, struct bNodeSocket *socket);
+void BKE_ntree_update_tag_socket_removed(struct bNodeTree *ntree);
+
+void BKE_ntree_update_tag_link_changed(struct bNodeTree *ntree);
+void BKE_ntree_update_tag_link_removed(struct bNodeTree *ntree);
+void BKE_ntree_update_tag_link_added(struct bNodeTree *ntree, struct bNodeLink *link);
+void BKE_ntree_update_tag_link_mute(struct bNodeTree *ntree, struct bNodeLink *link);
+
+/** Used after file loading when run-time data on the tree has not been initialized yet. */
+void BKE_ntree_update_tag_missing_runtime_data(struct bNodeTree *ntree);
+/** Used when the interface sockets/values have changed. */
+void BKE_ntree_update_tag_interface(struct bNodeTree *ntree);
+/** Used when an id data block changed that might be used by nodes that need to be updated. */
+void BKE_ntree_update_tag_id_changed(struct Main *bmain, struct ID *id);
+
+typedef struct NodeTreeUpdateExtraParams {
+ /**
+ * Data passed into the callbacks.
+ */
+ void *user_data;
+
+ /**
+ * Called for every tree that has been changed during the update. This can be used to send
+ * notifiers to trigger redraws or depsgraph updates.
+ */
+ void (*tree_changed_fn)(struct ID *, struct bNodeTree *, void *user_data);
+
+ /**
+ * Called for every tree whose output value may have changed based on the provided update tags.
+ * This can be used to tag the depsgraph if necessary.
+ */
+ void (*tree_output_changed_fn)(struct ID *, struct bNodeTree *, void *user_data);
+} NodeTreeUpdateExtraParams;
+
+/**
+ * Updates #bmain based on changes to node trees.
+ */
+void BKE_ntree_update_main(struct Main *bmain, struct NodeTreeUpdateExtraParams *params);
+
+/**
+ * Same as #BKE_ntree_update_main, but will first only look at the provided tree and only looks
+ * at #bmain when something relevant for other data-blocks changed. This avoids scanning #bmain in
+ * many cases.
+ *
+ * If #bmain is null, only the provided tree is updated. This should only be used in very rare
+ * cases because it may result it incorrectly synced data in DNA.
+ *
+ * If #tree is null, this is the same as calling #BKE_ntree_update_main.
+ */
+void BKE_ntree_update_main_tree(struct Main *bmain,
+ struct bNodeTree *ntree,
+ struct NodeTreeUpdateExtraParams *params);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 03565bd3bda..a7d39598e54 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -48,6 +48,7 @@ struct RegionView3D;
struct RigidBodyWorld;
struct Scene;
struct ShaderFxData;
+struct SubsurfModifierData;
struct View3D;
struct ViewLayer;
@@ -512,6 +513,7 @@ bool BKE_object_obdata_texspace_get(struct Object *ob,
float **r_loc,
float **r_size);
+struct Mesh *BKE_object_get_evaluated_mesh_no_subsurf(const struct Object *object);
/** Get evaluated mesh for given object. */
struct Mesh *BKE_object_get_evaluated_mesh(const struct Object *object);
/**
@@ -712,6 +714,15 @@ void BKE_object_modifiers_lib_link_common(void *userData,
struct ID **idpoin,
int cb_flag);
+/**
+ * Return the last subsurf modifier of an object, this does not check whether modifiers on top of
+ * it are disabled. Return NULL if no such modifier is found.
+ *
+ * This does not check if the modifier is enabled as it is assumed that the caller verified that it
+ * is enabled for its evaluation mode.
+ */
+struct SubsurfModifierData *BKE_object_get_last_subsurf_modifier(const struct Object *ob);
+
void BKE_object_replace_data_on_shallow_copy(struct Object *ob, struct ID *new_data);
struct PartEff;
diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h
index af8a6ed293d..57b0127088c 100644
--- a/source/blender/blenkernel/BKE_pointcloud.h
+++ b/source/blender/blenkernel/BKE_pointcloud.h
@@ -41,7 +41,7 @@ void *BKE_pointcloud_add_default(struct Main *bmain, const char *name);
struct PointCloud *BKE_pointcloud_new_nomain(const int totpoint);
struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob);
-void BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]);
+bool BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]);
void BKE_pointcloud_update_customdata_pointers(struct PointCloud *pointcloud);
bool BKE_pointcloud_customdata_required(struct PointCloud *pointcloud,
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index 77cf250471f..4792921fec7 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -22,6 +22,8 @@
* \ingroup bke
*/
+#include "BLI_sys_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index fd0682ee8f0..3d8b48e5192 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -465,20 +465,20 @@ void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizm
*/
struct ARegion *BKE_area_find_region_type(const struct ScrArea *area, int type);
struct ARegion *BKE_area_find_region_active_win(struct ScrArea *area);
-struct ARegion *BKE_area_find_region_xy(struct ScrArea *area, const int regiontype, int x, int y);
+struct ARegion *BKE_area_find_region_xy(struct ScrArea *area,
+ const int regiontype,
+ const int xy[2]) ATTR_NONNULL(3);
/**
* \note This is only for screen level regions (typically menus/popups).
*/
struct ARegion *BKE_screen_find_region_xy(struct bScreen *screen,
const int regiontype,
- int x,
- int y) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+ const int xy[2]) ATTR_WARN_UNUSED_RESULT
+ ATTR_NONNULL(1, 3);
struct ARegion *BKE_screen_find_main_region_at_xy(struct bScreen *screen,
const int space_type,
- const int x,
- const int y);
-
+ const int xy[2]) ATTR_NONNULL(1, 3);
/**
* \note Ideally we can get the area from the context,
* there are a few places however where this isn't practical.
@@ -495,9 +495,10 @@ struct ScrArea *BKE_screen_find_big_area(struct bScreen *screen,
const short min);
struct ScrArea *BKE_screen_area_map_find_area_xy(const struct ScrAreaMap *areamap,
const int spacetype,
- int x,
- int y);
-struct ScrArea *BKE_screen_find_area_xy(struct bScreen *screen, const int spacetype, int x, int y);
+ const int xy[2]) ATTR_NONNULL(1, 3);
+struct ScrArea *BKE_screen_find_area_xy(struct bScreen *screen,
+ const int spacetype,
+ const int xy[2]) ATTR_NONNULL(1, 3);
void BKE_screen_gizmo_tag_refresh(struct bScreen *screen);
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
index ebdc4a0ca0b..3413bdbfa69 100644
--- a/source/blender/blenkernel/BKE_spline.hh
+++ b/source/blender/blenkernel/BKE_spline.hh
@@ -330,17 +330,6 @@ class BezierSpline final : public Spline {
int resolution() const;
void set_resolution(const int value);
- /**
- * \warning Call #reallocate on the spline's attributes after adding all points.
- */
- void add_point(const blender::float3 position,
- const HandleType handle_type_left,
- const blender::float3 handle_position_left,
- const HandleType handle_type_right,
- const blender::float3 handle_position_right,
- const float radius,
- const float tilt);
-
void resize(const int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
@@ -567,14 +556,6 @@ class NURBSpline final : public Spline {
uint8_t order() const;
void set_order(const uint8_t value);
- /**
- * \warning Call #reallocate on the spline's attributes after adding all points.
- */
- void add_point(const blender::float3 position,
- const float radius,
- const float tilt,
- const float weight);
-
bool check_valid_size_and_order() const;
int knots_size() const;
@@ -634,11 +615,6 @@ class PolySpline final : public Spline {
int size() const final;
- /**
- * \warning Call #reallocate on the spline's attributes after adding all points.
- */
- void add_point(const blender::float3 position, const float radius, const float tilt);
-
void resize(const int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
@@ -710,7 +686,7 @@ struct CurveEval {
void translate(const blender::float3 &translation);
void transform(const blender::float4x4 &matrix);
- void bounds_min_max(blender::float3 &min, blender::float3 &max, const bool use_evaluated) const;
+ bool bounds_min_max(blender::float3 &min, blender::float3 &max, const bool use_evaluated) const;
/**
* Return the start indices for each of the curve spline's control points, if they were part
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
index 2fb27fad30d..169a4337f6a 100644
--- a/source/blender/blenkernel/BKE_subdiv.h
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -188,7 +188,16 @@ typedef struct Subdiv {
/* Cached values, are not supposed to be accessed directly. */
struct {
/* Indexed by base face index, element indicates total number of ptex
- * faces created for preceding base faces. */
+ * faces created for preceding base faces. This also stores the final
+ * ptex offset (the total number of PTex faces) at the end of the array
+ * so that algorithms can compute the number of ptex faces for a given
+ * face by computing the delta with the offset for the next face without
+ * using a separate data structure, e.g.:
+ *
+ * const int num_face_ptex_faces = face_ptex_offset[i + 1] - face_ptex_offset[i];
+ *
+ * In total this array has a size of `num base faces + 1`.
+ */
int *face_ptex_offset;
} cache_;
} Subdiv;
@@ -257,6 +266,9 @@ void BKE_subdiv_displacement_detach(Subdiv *subdiv);
/* ============================ TOPOLOGY HELPERS ============================ */
+/* For each element in the array, this stores the total number of ptex faces up to that element,
+ * with the total number of ptex faces being the last element in the array. The array is of length
+ * `base face count + 1`. */
int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv);
/* =========================== PTEX FACES AND GRIDS ========================= */
diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h
index 0b61e62c89c..177d5f386a8 100644
--- a/source/blender/blenkernel/BKE_subdiv_eval.h
+++ b/source/blender/blenkernel/BKE_subdiv_eval.h
@@ -31,15 +31,25 @@ extern "C" {
struct Mesh;
struct Subdiv;
+struct OpenSubdiv_EvaluatorCache;
+
+typedef enum eSubdivEvaluatorType {
+ SUBDIV_EVALUATOR_TYPE_CPU,
+ SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE,
+} eSubdivEvaluatorType;
/* Returns true if evaluator is ready for use. */
-bool BKE_subdiv_eval_begin(struct Subdiv *subdiv);
+bool BKE_subdiv_eval_begin(struct Subdiv *subdiv,
+ eSubdivEvaluatorType evaluator_type,
+ struct OpenSubdiv_EvaluatorCache *evaluator_cache);
/* coarse_vertex_cos is an optional argument which allows to override coordinates of the coarse
* mesh. */
bool BKE_subdiv_eval_begin_from_mesh(struct Subdiv *subdiv,
const struct Mesh *mesh,
- const float (*coarse_vertex_cos)[3]);
+ const float (*coarse_vertex_cos)[3],
+ eSubdivEvaluatorType evaluator_type,
+ struct OpenSubdiv_EvaluatorCache *evaluator_cache);
bool BKE_subdiv_eval_refine_from_mesh(struct Subdiv *subdiv,
const struct Mesh *mesh,
const float (*coarse_vertex_cos)[3]);
diff --git a/source/blender/blenkernel/BKE_subdiv_foreach.h b/source/blender/blenkernel/BKE_subdiv_foreach.h
index 3f74299455d..f63e23917ef 100644
--- a/source/blender/blenkernel/BKE_subdiv_foreach.h
+++ b/source/blender/blenkernel/BKE_subdiv_foreach.h
@@ -38,7 +38,8 @@ typedef bool (*SubdivForeachTopologyInformationCb)(const struct SubdivForeachCon
const int num_vertices,
const int num_edges,
const int num_loops,
- const int num_polygons);
+ const int num_polygons,
+ const int *subdiv_polygon_offset);
typedef void (*SubdivForeachVertexFromCornerCb)(const struct SubdivForeachContext *context,
void *tls,
diff --git a/source/blender/blenkernel/BKE_subdiv_modifier.h b/source/blender/blenkernel/BKE_subdiv_modifier.h
new file mode 100644
index 00000000000..94068613101
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subdiv_modifier.h
@@ -0,0 +1,71 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2021 by Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#pragma once
+
+#include "BLI_sys_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Mesh;
+struct Object;
+struct Scene;
+struct Subdiv;
+struct SubdivSettings;
+struct SubsurfModifierData;
+
+void BKE_subsurf_modifier_subdiv_settings_init(struct SubdivSettings *settings,
+ const struct SubsurfModifierData *smd,
+ const bool use_render_params);
+
+/* If skip_check_is_last is true, we assume that the modifier passed is the last enabled modifier
+ * in the stack. */
+bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const struct Scene *scene,
+ const struct Object *ob,
+ const struct SubsurfModifierData *smd,
+ int required_mode,
+ bool skip_check_is_last);
+
+bool BKE_subsurf_modifier_can_do_gpu_subdiv(const struct Scene *scene,
+ const struct Object *ob,
+ const int required_mode);
+
+extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(struct Subdiv *subdiv);
+
+struct Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(
+ const struct SubsurfModifierData *smd,
+ const struct SubdivSettings *subdiv_settings,
+ const struct Mesh *mesh,
+ const bool for_draw_code);
+
+struct SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(struct SubsurfModifierData *smd);
+
+/* Return the #ModifierMode required for the evaluation of the subsurf modifier, which should be
+ * used to check if the modifier is enabled. */
+int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h
index 6e1f9468ce4..44893a6f030 100644
--- a/source/blender/blenkernel/BKE_undo_system.h
+++ b/source/blender/blenkernel/BKE_undo_system.h
@@ -91,7 +91,7 @@ typedef struct UndoStep {
/** When this is true, undo/memfile read code is allowed to re-use old data-blocks for unchanged
* IDs, and existing depsgraphes. This has to be forbidden in some cases (like renamed IDs). */
bool use_old_bmain_data;
- /** For use by undo systems that accumulate changes (text editor, painting). */
+ /** For use by undo systems that accumulate changes (mesh-sculpt & image-painting). */
bool is_applied;
/* Over alloc 'type->struct_size'. */
} UndoStep;
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index f6e7f1c2473..3c780a933d3 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -126,7 +126,7 @@ set(SRC
intern/curve_eval.cc
intern/curve_to_mesh_convert.cc
intern/curveprofile.cc
- intern/customdata.c
+ intern/customdata.cc
intern/customdata_file.c
intern/data_transfer.c
intern/deform.c
@@ -156,7 +156,7 @@ set(SRC
intern/gpencil_curve.c
intern/gpencil_geom.cc
intern/gpencil_modifier.c
- intern/hair.c
+ intern/hair.cc
intern/icons.cc
intern/icons_rasterize.c
intern/idprop.c
@@ -226,6 +226,7 @@ set(SRC
intern/multires_versioning.c
intern/nla.c
intern/node.cc
+ intern/node_tree_update.cc
intern/type_conversions.cc
intern/object.cc
intern/object_deform.c
@@ -274,6 +275,7 @@ set(SRC
intern/subdiv_eval.c
intern/subdiv_foreach.c
intern/subdiv_mesh.c
+ intern/subdiv_modifier.c
intern/subdiv_stats.c
intern/subdiv_topology.c
intern/subsurf_ccg.c
@@ -420,6 +422,7 @@ set(SRC
BKE_multires.h
BKE_nla.h
BKE_node.h
+ BKE_node_tree_update.h
BKE_object.h
BKE_object_deform.h
BKE_object_facemap.h
@@ -451,6 +454,7 @@ set(SRC
BKE_subdiv_eval.h
BKE_subdiv_foreach.h
BKE_subdiv_mesh.h
+ BKE_subdiv_modifier.h
BKE_subdiv_topology.h
BKE_subsurf.h
BKE_text.h
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 6c9c5490ca0..4bfd71ba932 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -2311,145 +2311,3 @@ static void mesh_init_origspace(Mesh *mesh)
BKE_mesh_tessface_clear(mesh);
}
-
-/* derivedmesh info printing function,
- * to help track down differences DM output */
-
-#ifndef NDEBUG
-# include "BLI_dynstr.h"
-
-static void dm_debug_info_layers(DynStr *dynstr,
- DerivedMesh *dm,
- CustomData *cd,
- void *(*getElemDataArray)(DerivedMesh *, int))
-{
- int type;
-
- for (type = 0; type < CD_NUMTYPES; type++) {
- if (CustomData_has_layer(cd, type)) {
- /* NOTE: doesn't account for multiple layers. */
- const char *name = CustomData_layertype_name(type);
- const int size = CustomData_sizeof(type);
- const void *pt = getElemDataArray(dm, type);
- const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0;
- const char *structname;
- int structnum;
- CustomData_file_write_info(type, &structname, &structnum);
- BLI_dynstr_appendf(
- dynstr,
- " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
- name,
- structname,
- type,
- (const void *)pt,
- size,
- pt_size);
- }
- }
-}
-
-char *DM_debug_info(DerivedMesh *dm)
-{
- DynStr *dynstr = BLI_dynstr_new();
- char *ret;
- const char *tstr;
-
- BLI_dynstr_append(dynstr, "{\n");
- BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)dm);
- switch (dm->type) {
- case DM_TYPE_CDDM:
- tstr = "DM_TYPE_CDDM";
- break;
- case DM_TYPE_CCGDM:
- tstr = "DM_TYPE_CCGDM";
- break;
- default:
- tstr = "UNKNOWN";
- break;
- }
- BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr);
- BLI_dynstr_appendf(dynstr, " 'numVertData': %d,\n", dm->numVertData);
- BLI_dynstr_appendf(dynstr, " 'numEdgeData': %d,\n", dm->numEdgeData);
- BLI_dynstr_appendf(dynstr, " 'numTessFaceData': %d,\n", dm->numTessFaceData);
- BLI_dynstr_appendf(dynstr, " 'numPolyData': %d,\n", dm->numPolyData);
- BLI_dynstr_appendf(dynstr, " 'deformedOnly': %d,\n", dm->deformedOnly);
-
- BLI_dynstr_append(dynstr, " 'vertexLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->vertData, dm->getVertDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'edgeLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->edgeData, dm->getEdgeDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'loopLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->loopData, dm->getLoopDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'polyLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->polyData, dm->getPolyDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, " 'tessFaceLayers': (\n");
- dm_debug_info_layers(dynstr, dm, &dm->faceData, dm->getTessFaceDataArray);
- BLI_dynstr_append(dynstr, " ),\n");
-
- BLI_dynstr_append(dynstr, "}\n");
-
- ret = BLI_dynstr_get_cstring(dynstr);
- BLI_dynstr_free(dynstr);
- return ret;
-}
-
-void DM_debug_print(DerivedMesh *dm)
-{
- char *str = DM_debug_info(dm);
- puts(str);
- fflush(stdout);
- MEM_freeN(str);
-}
-
-bool DM_is_valid(DerivedMesh *dm)
-{
- const bool do_verbose = true;
- const bool do_fixes = false;
-
- bool is_valid = true;
- bool changed = true;
-
- is_valid &= BKE_mesh_validate_all_customdata(
- dm->getVertDataLayout(dm),
- dm->getNumVerts(dm),
- dm->getEdgeDataLayout(dm),
- dm->getNumEdges(dm),
- dm->getLoopDataLayout(dm),
- dm->getNumLoops(dm),
- dm->getPolyDataLayout(dm),
- dm->getNumPolys(dm),
- false, /* setting mask here isn't useful, gives false positives */
- do_verbose,
- do_fixes,
- &changed);
-
- is_valid &= BKE_mesh_validate_arrays(nullptr,
- dm->getVertArray(dm),
- dm->getNumVerts(dm),
- dm->getEdgeArray(dm),
- dm->getNumEdges(dm),
- dm->getTessFaceArray(dm),
- dm->getNumTessFaces(dm),
- dm->getLoopArray(dm),
- dm->getNumLoops(dm),
- dm->getPolyArray(dm),
- dm->getNumPolys(dm),
- (MDeformVert *)dm->getVertDataArray(dm, CD_MDEFORMVERT),
- do_verbose,
- do_fixes,
- &changed);
-
- BLI_assert(changed == false);
-
- return is_valid;
-}
-
-#endif /* NDEBUG */
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index ddba726ba83..764c043f5ed 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -705,7 +705,12 @@ bool BKE_pose_channels_is_valid(const bPose *pose)
#endif
-bPoseChannel *BKE_pose_channel_active(Object *ob)
+bool BKE_pose_is_layer_visible(const bArmature *arm, const bPoseChannel *pchan)
+{
+ return (pchan->bone->layer & arm->layer);
+}
+
+bPoseChannel *BKE_pose_channel_active(Object *ob, const bool check_arm_layer)
{
bArmature *arm = (ob) ? ob->data : NULL;
bPoseChannel *pchan;
@@ -716,14 +721,21 @@ bPoseChannel *BKE_pose_channel_active(Object *ob)
/* find active */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone) && (pchan->bone == arm->act_bone) && (pchan->bone->layer & arm->layer)) {
- return pchan;
+ if ((pchan->bone) && (pchan->bone == arm->act_bone)) {
+ if (!check_arm_layer || BKE_pose_is_layer_visible(arm, pchan)) {
+ return pchan;
+ }
}
}
return NULL;
}
+bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob)
+{
+ return BKE_pose_channel_active(ob, true);
+}
+
bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob)
{
bArmature *arm = (ob) ? ob->data : NULL;
@@ -732,7 +744,7 @@ bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob)
return NULL;
}
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && (pchan->bone->flag & BONE_SELECTED) && PBONE_VISIBLE(arm, pchan->bone)) {
return pchan;
}
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index d93d5c456d8..42b72a7cd66 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -676,41 +676,6 @@ void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBa
}
}
-char *BKE_animdata_driver_path_hack(bContext *C,
- PointerRNA *ptr,
- PropertyRNA *prop,
- char *base_path)
-{
- ID *id = ptr->owner_id;
- ScrArea *area = CTX_wm_area(C);
-
- /* get standard path which may be extended */
- char *basepath = base_path ? base_path : RNA_path_from_ID_to_property(ptr, prop);
- char *path = basepath; /* in case no remapping is needed */
-
- /* Remapping will only be performed in the Properties Editor, as only this
- * restricts the subspace of options to the 'active' data (a manageable state)
- */
- /* TODO: watch out for pinned context? */
- if ((area) && (area->spacetype == SPACE_PROPERTIES)) {
- Object *ob = CTX_data_active_object(C);
-
- if (ob && id) {
- /* TODO: after material textures were removed, this function serves
- * no purpose anymore, but could be used again so was not removed. */
-
- /* fix RNA pointer, as we've now changed the ID root by changing the paths */
- if (basepath != path) {
- /* rebase provided pointer so that it starts from object... */
- RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr);
- }
- }
- }
-
- /* the path should now have been corrected for use */
- return path;
-}
-
/* Path Validation -------------------------------------------- */
/* Check if a given RNA Path is valid, by tracing it from the given ID,
diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc
index aec622bb71f..eee1f6287c3 100644
--- a/source/blender/blenkernel/intern/asset_catalog.cc
+++ b/source/blender/blenkernel/intern/asset_catalog.cc
@@ -24,7 +24,7 @@
#include "BKE_asset_catalog.hh"
#include "BKE_asset_library.h"
-#include "BLI_fileops.h"
+#include "BLI_fileops.hh"
#include "BLI_path_util.h"
/* For S_ISREG() and S_ISDIR() on Windows. */
@@ -32,6 +32,10 @@
# include "BLI_winstuff.h"
#endif
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"bke.asset_service"};
+
namespace blender::bke {
const CatalogFilePath AssetCatalogService::DEFAULT_CATALOG_FILENAME = "blender_assets.cats.txt";
@@ -311,6 +315,7 @@ void AssetCatalogService::load_from_disk(const CatalogFilePath &file_or_director
BLI_stat_t status;
if (BLI_stat(file_or_directory_path.data(), &status) == -1) {
/* TODO(@sybren): throw an appropriate exception. */
+ CLOG_WARN(&LOG, "path not found: %s", file_or_directory_path.data());
return;
}
@@ -337,6 +342,7 @@ void AssetCatalogService::load_directory_recursive(const CatalogFilePath &direct
if (!BLI_exists(file_path.data())) {
/* No file to be loaded is perfectly fine. */
+ CLOG_INFO(&LOG, 2, "path not found: %s", file_path.data());
return;
}
@@ -824,8 +830,12 @@ void AssetCatalogDefinitionFile::parse_catalog_file(
const CatalogFilePath &catalog_definition_file_path,
AssetCatalogParsedFn catalog_loaded_callback)
{
- std::fstream infile(catalog_definition_file_path);
+ fstream infile(catalog_definition_file_path, std::ios::in);
+ if (!infile.is_open()) {
+ CLOG_ERROR(&LOG, "%s: unable to open file", catalog_definition_file_path.c_str());
+ return;
+ }
bool seen_version_number = false;
std::string line;
while (std::getline(infile, line)) {
@@ -956,7 +966,7 @@ bool AssetCatalogDefinitionFile::write_to_disk_unsafe(const CatalogFilePath &des
return false;
}
- std::ofstream output(dest_file_path);
+ fstream output(dest_file_path, std::ios::out);
/* TODO(@sybren): remember the line ending style that was originally read, then use that to write
* the file again. */
diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc
index ba8f8716823..3ff7831b19a 100644
--- a/source/blender/blenkernel/intern/asset_catalog_test.cc
+++ b/source/blender/blenkernel/intern/asset_catalog_test.cc
@@ -27,6 +27,8 @@
#include "DNA_asset_types.h"
#include "DNA_userdef_types.h"
+#include "CLG_log.h"
+
#include "testing/testing.h"
namespace blender::bke::tests {
@@ -93,6 +95,18 @@ class AssetCatalogTest : public testing::Test {
CatalogFilePath asset_library_root_;
CatalogFilePath temp_library_path_;
+ static void SetUpTestSuite()
+ {
+ testing::Test::SetUpTestSuite();
+ CLG_init();
+ }
+
+ static void TearDownTestSuite()
+ {
+ CLG_exit();
+ testing::Test::TearDownTestSuite();
+ }
+
void SetUp() override
{
const std::string test_files_dir = blender::tests::flags_test_asset_dir();
@@ -549,6 +563,30 @@ TEST_F(AssetCatalogTest, write_single_file)
/* TODO(@sybren): test ordering of catalogs in the file. */
}
+TEST_F(AssetCatalogTest, read_write_unicode_filepath)
+{
+ TestableAssetCatalogService service(asset_library_root_);
+ const CatalogFilePath load_from_path = asset_library_root_ + "/новый/" +
+ AssetCatalogService::DEFAULT_CATALOG_FILENAME;
+ service.load_from_disk(load_from_path);
+
+ const CatalogFilePath save_to_path = use_temp_path() + "новый.cats.txt";
+ AssetCatalogDefinitionFile *cdf = service.get_catalog_definition_file();
+ ASSERT_NE(nullptr, cdf) << "unable to load " << load_from_path;
+ EXPECT_TRUE(cdf->write_to_disk(save_to_path));
+
+ AssetCatalogService loaded_service(save_to_path);
+ loaded_service.load_from_disk();
+
+ /* Test that the file was loaded correctly. */
+ const bUUID materials_uuid("a2151dff-dead-4f29-b6bc-b2c7d6cccdb4");
+ const AssetCatalog *cat = loaded_service.find_catalog(materials_uuid);
+ ASSERT_NE(nullptr, cat);
+ EXPECT_EQ(materials_uuid, cat->catalog_id);
+ EXPECT_EQ(AssetCatalogPath("Материалы"), cat->path);
+ EXPECT_EQ("Russian Materials", cat->simple_name);
+}
+
TEST_F(AssetCatalogTest, no_writing_empty_files)
{
const CatalogFilePath temp_lib_root = create_temp_path();
diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c
index c265a6e2b7d..23e9e6bfbbb 100644
--- a/source/blender/blenkernel/intern/blendfile_link_append.c
+++ b/source/blender/blenkernel/intern/blendfile_link_append.c
@@ -440,6 +440,16 @@ static bool object_in_any_collection(Main *bmain, Object *ob)
return false;
}
+static bool collection_instantiated_by_any_object(Main *bmain, Collection *collection)
+{
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->type == OB_EMPTY && ob->instance_collection == collection) {
+ return true;
+ }
+ }
+ return false;
+}
+
static ID *loose_data_instantiate_process_check(LooseDataInstantiateContext *instantiate_context,
BlendfileLinkAppendContextItem *item)
{
@@ -633,12 +643,19 @@ static void loose_data_instantiate_collection_process(
* children.
*/
Collection *collection = (Collection *)id;
+ /* The collection could be linked/appended together with an Empty object instantiating it,
+ * better not instantiate the collection in the viewlayer in that case.
+ *
+ * Can easily happen when copy/pasting such instantiating empty, see T93839. */
+ const bool collection_is_instantiated = collection_instantiated_by_any_object(bmain,
+ collection);
/* Always consider adding collections directly selected by the user. */
- bool do_add_collection = (item->tag & LINK_APPEND_TAG_INDIRECT) == 0;
+ bool do_add_collection = (item->tag & LINK_APPEND_TAG_INDIRECT) == 0 &&
+ !collection_is_instantiated;
/* In linking case, do not enforce instantiating non-directly linked collections/objects.
* This avoids cluttering the ViewLayers, user can instantiate themselves specific collections
* or objects easily from the Outliner if needed. */
- if (!do_add_collection && do_append) {
+ if (!do_add_collection && do_append && !collection_is_instantiated) {
LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) {
Object *ob = coll_ob->ob;
if (!object_in_any_scene(bmain, ob)) {
@@ -726,6 +743,8 @@ static void loose_data_instantiate_object_process(LooseDataInstantiateContext *i
* if you want it do it at the editor level. */
const bool object_set_active = false;
+ const bool is_linking = (lapp_context->params->flag & FILE_LINK) != 0;
+
/* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used
* anywhere. */
LinkNode *itemlink;
@@ -736,6 +755,17 @@ static void loose_data_instantiate_object_process(LooseDataInstantiateContext *i
continue;
}
+ /* In linking case, never instantiate stray objects that are not directly linked.
+ *
+ * While this is not ideal (in theory no object should remain un-owned), in case of indirectly
+ * linked objects, the other solution would be to add them to a local collection, which would
+ * make them directly linked. Think for now keeping them indirectly linked is more important.
+ * Ref. T93757.
+ */
+ if (is_linking && (item->tag & LINK_APPEND_TAG_INDIRECT) != 0) {
+ continue;
+ }
+
Object *ob = (Object *)id;
if (object_in_any_collection(bmain, ob)) {
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 85e49774dfd..44ef3ec96ff 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -236,7 +236,8 @@ void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports)
BKE_bpath_foreach_path_main(&(BPathForeachPathData){
.bmain = bmain,
.callback_function = check_missing_files_foreach_path_cb,
- .flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_SKIP_PACKED,
+ .flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_SKIP_PACKED |
+ BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN,
.user_data = reports});
}
@@ -384,7 +385,8 @@ void BKE_bpath_missing_files_find(Main *bmain,
const bool find_all)
{
struct BPathFind_Data data = {NULL};
- const int flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_RELOAD_EDITED;
+ const int flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_RELOAD_EDITED |
+ BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN;
data.basedir = BKE_main_blendfile_path(bmain);
data.reports = reports;
diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc
index a68119fbc1d..09a01d209df 100644
--- a/source/blender/blenkernel/intern/bvhutils.cc
+++ b/source/blender/blenkernel/intern/bvhutils.cc
@@ -127,7 +127,7 @@ bool bvhcache_has_tree(const BVHCache *bvh_cache, const BVHTree *tree)
BVHCache *bvhcache_init()
{
- BVHCache *cache = (BVHCache *)MEM_callocN(sizeof(BVHCache), __func__);
+ BVHCache *cache = MEM_cnew<BVHCache>(__func__);
BLI_mutex_init(&cache->mutex);
return cache;
}
diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c
index 21a9159004f..e6ce4eb9440 100644
--- a/source/blender/blenkernel/intern/collection.c
+++ b/source/blender/blenkernel/intern/collection.c
@@ -186,7 +186,7 @@ static ID *collection_owner_get(Main *bmain, ID *id)
Collection *master_collection = (Collection *)id;
BLI_assert((master_collection->flag & COLLECTION_IS_MASTER) != 0);
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
if (scene->master_collection == master_collection) {
return &scene->id;
}
@@ -1205,9 +1205,7 @@ static void collection_object_remove_nulls(Collection *collection)
{
bool changed = false;
- for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) {
- cob_next = cob->next;
-
+ LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) {
if (cob->ob == NULL) {
BLI_freelinkN(&collection->gobject, cob);
changed = true;
@@ -1221,22 +1219,61 @@ static void collection_object_remove_nulls(Collection *collection)
void BKE_collections_object_remove_nulls(Main *bmain)
{
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
collection_object_remove_nulls(scene->master_collection);
}
- for (Collection *collection = bmain->collections.first; collection;
- collection = collection->id.next) {
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
collection_object_remove_nulls(collection);
}
}
-static void collection_null_children_remove(Collection *collection)
+/*
+ * Remove all duplicate objects from collections.
+ * This is used for library remapping, happens when remapping an object to another one already
+ * present in the collection. Otherwise this should never happen.
+ */
+static void collection_object_remove_duplicates(Collection *collection)
{
- for (CollectionChild *child = collection->children.first, *child_next = NULL; child;
- child = child_next) {
- child_next = child->next;
+ bool changed = false;
+
+ LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) {
+ if (cob->ob->runtime.collection_management) {
+ BLI_freelinkN(&collection->gobject, cob);
+ changed = true;
+ continue;
+ }
+ cob->ob->runtime.collection_management = true;
+ }
+ /* Cleanup. */
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
+ cob->ob->runtime.collection_management = false;
+ }
+
+ if (changed) {
+ BKE_collection_object_cache_free(collection);
+ }
+}
+
+void BKE_collections_object_remove_duplicates(struct Main *bmain)
+{
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ ob->runtime.collection_management = false;
+ }
+
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ collection_object_remove_duplicates(scene->master_collection);
+ }
+
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ collection_object_remove_duplicates(collection);
+ }
+}
+
+static void collection_null_children_remove(Collection *collection)
+{
+ LISTBASE_FOREACH_MUTABLE (CollectionChild *, child, &collection->children) {
if (child->collection == NULL) {
BLI_freelinkN(&collection->children, child);
}
@@ -1245,9 +1282,7 @@ static void collection_null_children_remove(Collection *collection)
static void collection_missing_parents_remove(Collection *collection)
{
- for (CollectionParent *parent = collection->parents.first, *parent_next; parent != NULL;
- parent = parent_next) {
- parent_next = parent->next;
+ LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &collection->parents) {
if ((parent->collection == NULL) || !collection_find_child(parent->collection, collection)) {
BLI_freelinkN(&collection->parents, parent);
}
@@ -1267,28 +1302,23 @@ void BKE_collections_child_remove_nulls(Main *bmain,
* otherwise we can miss some cases...
* Also, master collections are not in bmain, so we also need to loop over scenes.
*/
- for (child_collection = bmain->collections.first; child_collection != NULL;
- child_collection = child_collection->id.next) {
- collection_null_children_remove(child_collection);
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ collection_null_children_remove(collection);
}
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
collection_null_children_remove(scene->master_collection);
}
}
- for (child_collection = bmain->collections.first; child_collection != NULL;
- child_collection = child_collection->id.next) {
- collection_missing_parents_remove(child_collection);
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ collection_missing_parents_remove(collection);
}
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
collection_missing_parents_remove(scene->master_collection);
}
}
else {
- for (CollectionParent *parent = child_collection->parents.first, *parent_next; parent;
- parent = parent_next) {
- parent_next = parent->next;
-
+ LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &child_collection->parents) {
collection_null_children_remove(parent->collection);
if (!collection_find_child(parent->collection, child_collection)) {
@@ -1586,9 +1616,9 @@ static void collection_parents_rebuild_recursive(Collection *collection)
BKE_collection_parent_relations_rebuild(collection);
collection->tag &= ~COLLECTION_TAG_RELATION_REBUILD;
- for (CollectionChild *child = collection->children.first; child != NULL; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
/* See comment above in `BKE_collection_parent_relations_rebuild`. */
- if ((collection->id.tag & (LIB_TAG_NO_MAIN | LIB_TAG_COPIED_ON_WRITE)) != 0) {
+ if ((child->collection->id.tag & (LIB_TAG_NO_MAIN | LIB_TAG_COPIED_ON_WRITE)) != 0) {
continue;
}
collection_parents_rebuild_recursive(child->collection);
@@ -1598,8 +1628,7 @@ static void collection_parents_rebuild_recursive(Collection *collection)
void BKE_main_collections_parent_relations_rebuild(Main *bmain)
{
/* Only collections not in bmain (master ones in scenes) have no parent... */
- for (Collection *collection = bmain->collections.first; collection != NULL;
- collection = collection->id.next) {
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
BLI_freelistN(&collection->parents);
collection->tag |= COLLECTION_TAG_RELATION_REBUILD;
@@ -1607,7 +1636,7 @@ void BKE_main_collections_parent_relations_rebuild(Main *bmain)
/* Scene's master collections will be 'root' parent of most of our collections, so start with
* them. */
- for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) {
+ LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
/* This function can be called from readfile.c, when this pointer is not guaranteed to be NULL.
*/
if (scene->master_collection != NULL) {
@@ -1619,8 +1648,7 @@ void BKE_main_collections_parent_relations_rebuild(Main *bmain)
/* We may have parent chains outside of scene's master_collection context? At least, readfile's
* lib_link_collection_data() seems to assume that, so do the same here. */
- for (Collection *collection = bmain->collections.first; collection != NULL;
- collection = collection->id.next) {
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
if (collection->tag & COLLECTION_TAG_RELATION_REBUILD) {
/* NOTE: we do not have easy access to 'which collections is root' info in that case, which
* means test for cycles in collection relationships may fail here. I don't think that is an
diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc
index d532ed9e4b2..7481d4df351 100644
--- a/source/blender/blenkernel/intern/cryptomatte.cc
+++ b/source/blender/blenkernel/intern/cryptomatte.cc
@@ -278,13 +278,13 @@ void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const ch
token = token.substr(first, (last - first + 1));
if (*token.begin() == '<' && *(--token.end()) == '>') {
float encoded_hash = atof(token.substr(1, token.length() - 2).c_str());
- entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__);
+ entry = MEM_cnew<CryptomatteEntry>(__func__);
entry->encoded_hash = encoded_hash;
}
else {
const char *name = token.c_str();
int name_len = token.length();
- entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__);
+ entry = MEM_cnew<CryptomatteEntry>(__func__);
STRNCPY(entry->name, name);
uint32_t hash = BKE_cryptomatte_hash(name, name_len);
entry->encoded_hash = BKE_cryptomatte_hash_to_float(hash);
diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc
index 50b7c15774d..291927ee398 100644
--- a/source/blender/blenkernel/intern/curve.cc
+++ b/source/blender/blenkernel/intern/curve.cc
@@ -43,7 +43,7 @@
#include "DNA_defaults.h"
#include "DNA_material_types.h"
-/* for dereferencing pointers */
+/* For dereferencing pointers. */
#include "DNA_key_types.h"
#include "DNA_object_types.h"
#include "DNA_vfont_types.h"
@@ -1438,7 +1438,7 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r
jstart = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces4");
jend = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces5");
- /* precalculation of basisv and jstart, jend */
+ /* Pre-calculation of `basisv` and `jstart`, `jend`. */
if (nu->flagv & CU_NURB_CYCLIC) {
cycl = nu->orderv - 1;
}
@@ -2104,10 +2104,10 @@ static void tilt_bezpart(const BezTriple *prevbezt,
}
}
-/* make_bevel_list_3D_* funcs, at a minimum these must
- * fill in the bezp->quat and bezp->dir values */
+/* `make_bevel_list_3D_*` functions, at a minimum these must
+ * fill in the #BevPoint.quat and #BevPoint.dir values. */
-/* utility for make_bevel_list_3D_* funcs */
+/** Utility for `make_bevel_list_3D_*` functions. */
static void bevel_list_calc_bisect(BevList *bl)
{
BevPoint *bevp2, *bevp1, *bevp0;
@@ -2329,14 +2329,14 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl)
/* Need to correct for the start/end points not matching
* do this by calculating the tilt angle difference, then apply
- * the rotation gradually over the entire curve
+ * the rotation gradually over the entire curve.
*
- * note that the split is between last and second last, rather than first/last as youd expect.
+ * Note that the split is between last and second last, rather than first/last as you'd expect.
*
* real order is like this
* 0,1,2,3,4 --> 1,2,3,4,0
*
- * this is why we compare last with second last
+ * This is why we compare last with second last.
*/
float vec_1[3] = {0, 1, 0}, vec_2[3] = {0, 1, 0}, angle, ang_fac, cross_tmp[3];
@@ -2614,14 +2614,13 @@ void BKE_curve_bevelList_free(ListBase *bev)
void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_render)
{
- /*
- * - convert all curves to polys, with indication of resol and flags for double-vertices
- * - possibly; do a smart vertice removal (in case Nurb)
- * - separate in individual blocks with BoundBox
- * - AutoHole detection
+ /* - Convert all curves to polys, with indication of resolution and flags for double-vertices.
+ * - Possibly; do a smart vertex removal (in case #Nurb).
+ * - Separate in individual blocks with #BoundBox.
+ * - Auto-hole detection.
*/
- /* this function needs an object, because of tflag and upflag */
+ /* This function needs an object, because of `tflag` and `upflag`. */
Curve *cu = (Curve *)ob->data;
BezTriple *bezt, *prevbezt;
BPoint *bp;
@@ -2637,7 +2636,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
bool is_editmode = false;
ListBase *bev;
- /* segbevcount alsp requires seglen. */
+ /* segbevcount also requires seglen. */
const bool need_seglen = ELEM(
cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) ||
ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE);
@@ -2695,7 +2694,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
if (nu->type == CU_POLY) {
len = nu->pntsu;
- BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), __func__);
+ BevList *bl = MEM_cnew<BevList>(__func__);
bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
@@ -2745,7 +2744,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
/* in case last point is not cyclic */
len = segcount * resolu + 1;
- BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), __func__);
+ BevList *bl = MEM_cnew<BevList>(__func__);
bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
@@ -2805,10 +2804,10 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
}
}
else {
- /* always do all three, to prevent data hanging around */
+ /* Always do all three, to prevent data hanging around. */
int j;
- /* BevPoint must stay aligned to 4 so sizeof(BevPoint)/sizeof(float) works */
+ /* #BevPoint must stay aligned to 4 so `sizeof(BevPoint) / sizeof(float)` works. */
for (j = 0; j < 3; j++) {
BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
prevbezt->vec[2][j],
@@ -2819,7 +2818,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
sizeof(BevPoint));
}
- /* if both arrays are nullptr do nothiong */
+ /* If both arrays are `nullptr` do nothing. */
tilt_bezpart(prevbezt,
bezt,
nu,
@@ -2839,7 +2838,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
sizeof(BevPoint));
}
- /* seglen */
+ /* `seglen`. */
if (seglen != nullptr) {
*seglen = 0;
*segbevcount = 0;
@@ -2847,7 +2846,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
bevp0 = bevp;
bevp++;
bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
- /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
+ /* Match `seglen` and `segbevcount` to the cleaned up bevel lists (see STEP 2). */
if (bevp->offset > threshold) {
*seglen += bevp->offset;
*segbevcount += 1;
@@ -2881,7 +2880,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
if (nu->pntsv == 1) {
len = (resolu * segcount);
- BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), __func__);
+ BevList *bl = MEM_cnew<BevList>(__func__);
bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__);
if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__);
@@ -2980,7 +2979,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
continue;
}
- nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */
+ nr = bl->nr - bl->dupe_nr + 1; /* +1 because vector-bezier sets flag too. */
blnew = (BevList *)MEM_mallocN(sizeof(BevList), "makeBevelList4");
memcpy(blnew, bl, sizeof(BevList));
blnew->bevpoints = (BevPoint *)MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4");
@@ -2992,7 +2991,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
blnew->seglen = bl->seglen;
blnew->nr = 0;
BLI_remlink(bev, bl);
- BLI_insertlinkbefore(bev, bl->next, blnew); /* to make sure bevlist is tuned with nurblist */
+ BLI_insertlinkbefore(bev, bl->next, blnew); /* Ensure `bevlist` is tuned with `nurblist`. */
bevp0 = bl->bevpoints;
bevp1 = blnew->bevpoints;
nr = bl->nr;
@@ -3114,7 +3113,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BevPoint *bevp = bl->bevpoints;
unit_qt(bevp->quat);
}
- else if (bl->nr == 2) { /* 2 pnt, treat separate */
+ else if (bl->nr == 2) { /* 2 points, treat separately. */
make_bevel_list_segment_2D(bl);
}
else {
@@ -3129,7 +3128,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_
BevPoint *bevp = bl->bevpoints;
unit_qt(bevp->quat);
}
- else if (bl->nr == 2) { /* 2 pnt, treat separate */
+ else if (bl->nr == 2) { /* 2 points, treat separately. */
make_bevel_list_segment_3D(bl);
}
else {
@@ -3321,13 +3320,13 @@ static void calchandleNurb_intern(BezTriple *bezt,
}
if (skip_align ||
- /* when one handle is free, alignming makes no sense, see: T35952 */
+ /* When one handle is free, aligning makes no sense, see: T35952 */
ELEM(HD_FREE, bezt->h1, bezt->h2) ||
- /* also when no handles are aligned, skip this step */
+ /* Also when no handles are aligned, skip this step. */
(!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) {
- /* handles need to be updated during animation and applying stuff like hooks,
+ /* Handles need to be updated during animation and applying stuff like hooks,
* but in such situations it's quite difficult to distinguish in which order
- * align handles should be aligned so skip them for now */
+ * align handles should be aligned so skip them for now. */
return;
}
@@ -3996,8 +3995,8 @@ void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic)
}
}
- /* Find continuous subsequences of free auto handles and smooth them, starting at
- * search_base. In cyclic mode these subsequences can span the cycle boundary. */
+ /* Find continuous sub-sequences of free auto handles and smooth them, starting at search_base.
+ * In cyclic mode these sub-sequences can span the cycle boundary. */
int start = search_base, count = 1;
for (int i = 1, j = start + 1; i < total; i++, j++) {
@@ -4189,13 +4188,13 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
/* left handle: */
if (flag == 0 || (bezt1->f1 & flag)) {
bezt1->h1 = HD_FREE;
- /* distance too short: vectorhandle */
+ /* Distance too short: vector-handle. */
if (len_squared_v3v3(bezt1->vec[1], bezt0->vec[1]) < eps_sq) {
bezt1->h1 = HD_VECT;
leftsmall = true;
}
else {
- /* aligned handle? */
+ /* Aligned handle? */
if (dist_squared_to_line_v3(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < eps_sq) {
align = true;
bezt1->h1 = HD_ALIGN;
@@ -4209,13 +4208,13 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag)
/* right handle: */
if (flag == 0 || (bezt1->f3 & flag)) {
bezt1->h2 = HD_FREE;
- /* distance too short: vectorhandle */
+ /* Distance too short: vector-handle. */
if (len_squared_v3v3(bezt1->vec[1], bezt2->vec[1]) < eps_sq) {
bezt1->h2 = HD_VECT;
rightsmall = true;
}
else {
- /* aligned handle? */
+ /* Aligned handle? */
if (align) {
bezt1->h2 = HD_ALIGN;
}
@@ -4860,7 +4859,7 @@ bool BKE_nurb_type_convert(Nurb *nu,
int a, c, nr;
if (nu->type == CU_POLY) {
- if (type == CU_BEZIER) { /* To Bezier with vecthandles. */
+ if (type == CU_BEZIER) { /* To Bezier with vector-handles. */
nr = nu->pntsu;
bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2");
nu->bezt = bezt;
diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index 38f736e6907..e2461adaaca 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -100,11 +100,17 @@ void CurveEval::transform(const float4x4 &matrix)
}
}
-void CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const
+bool CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const
{
+ bool have_minmax = false;
for (const SplinePtr &spline : this->splines()) {
- spline->bounds_min_max(min, max, use_evaluated);
+ if (spline->size()) {
+ spline->bounds_min_max(min, max, use_evaluated);
+ have_minmax = true;
+ }
}
+
+ return have_minmax;
}
float CurveEval::total_length() const
diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
index 5522a84d094..073d9d18a04 100644
--- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
+++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc
@@ -401,10 +401,8 @@ struct ResultAttributes {
};
static ResultAttributes create_result_attributes(const CurveEval &curve,
const CurveEval &profile,
- Mesh &mesh)
+ MeshComponent &mesh_component)
{
- MeshComponent mesh_component;
- mesh_component.replace(&mesh, GeometryOwnershipType::Editable);
Set<AttributeIDRef> curve_attributes;
/* In order to prefer attributes on the main curve input when there are name collisions, first
@@ -708,7 +706,11 @@ Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile, cons
mesh->smoothresh = DEG2RADF(180.0f);
BKE_mesh_normals_tag_dirty(mesh);
- ResultAttributes attributes = create_result_attributes(curve, profile, *mesh);
+ /* Create the mesh component for retrieving attributes at this scope, since output attributes
+ * can keep a reference to the component for updating after retrieving write access. */
+ MeshComponent mesh_component;
+ mesh_component.replace(mesh, GeometryOwnershipType::Editable);
+ ResultAttributes attributes = create_result_attributes(curve, profile, mesh_component);
threading::parallel_for(curves.index_range(), 128, [&](IndexRange curves_range) {
for (const int i_spline : curves_range) {
@@ -760,7 +762,10 @@ static CurveEval get_curve_single_vert()
{
CurveEval curve;
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- spline->add_point(float3(0), 0, 0.0f);
+ spline->resize(1.0f);
+ spline->positions().fill(float3(0));
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
curve.add_spline(std::move(spline));
return curve;
diff --git a/source/blender/blenkernel/intern/curveprofile.cc b/source/blender/blenkernel/intern/curveprofile.cc
index 387709fca29..8f387be41d3 100644
--- a/source/blender/blenkernel/intern/curveprofile.cc
+++ b/source/blender/blenkernel/intern/curveprofile.cc
@@ -46,7 +46,7 @@
struct CurveProfile *BKE_curveprofile_add(eCurveProfilePresets preset)
{
- CurveProfile *profile = (CurveProfile *)MEM_callocN(sizeof(CurveProfile), __func__);
+ CurveProfile *profile = MEM_cnew<CurveProfile>(__func__);
BKE_curveprofile_set_defaults(profile);
profile->preset = preset;
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.cc
index 1170f59bee3..f5c5fdcf34a 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -69,7 +69,7 @@
#define CUSTOMDATA_GROW 5
/* ensure typemap size is ok */
-BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "size mismatch");
+BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)nullptr)->typemap) == CD_NUMTYPES, "size mismatch");
static CLG_LogRef LOG = {"bke.customdata"};
@@ -94,7 +94,7 @@ bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref,
}
/********************* Layer type information **********************/
-typedef struct LayerTypeInfo {
+struct LayerTypeInfo {
int size; /* the memory size of one element of this layer's data */
/** name of the struct used, for file writing */
@@ -105,7 +105,7 @@ typedef struct LayerTypeInfo {
/**
* default layer name.
*
- * \note when NULL this is a way to ensure there is only ever one item
+ * \note when null this is a way to ensure there is only ever one item
* see: CustomData_layertype_is_singleton().
*/
const char *defaultname;
@@ -113,7 +113,7 @@ typedef struct LayerTypeInfo {
/**
* a function to copy count elements of this layer's data
* (deep copy if appropriate)
- * if NULL, memcpy is used
+ * if null, memcpy is used
*/
cd_copy copy;
@@ -128,7 +128,7 @@ typedef struct LayerTypeInfo {
/**
* a function to interpolate between count source elements of this
* layer's data and store the result in dest
- * if weights == NULL or sub_weights == NULL, they should default to 1
+ * if weights == null or sub_weights == null, they should default to 1
*
* weights gives the weight for each element in sources
* sub_weights gives the sub-element weights for each element in sources
@@ -146,7 +146,7 @@ typedef struct LayerTypeInfo {
void (*swap)(void *data, const int *corner_indices);
/**
- * a function to set a layer's data to default values. if NULL, the
+ * a function to set a layer's data to default values. if null, the
* default is assumed to be all zeros */
void (*set_default)(void *data, int count);
@@ -171,9 +171,9 @@ typedef struct LayerTypeInfo {
size_t (*filesize)(CDataFile *cdf, const void *data, int count);
/** a function to determine max allowed number of layers,
- * should be NULL or return -1 if no limit */
- int (*layers_max)(void);
-} LayerTypeInfo;
+ * should be null or return -1 if no limit */
+ int (*layers_max)();
+};
static void layerCopy_mdeformvert(const void *source, void *dest, int count)
{
@@ -182,17 +182,17 @@ static void layerCopy_mdeformvert(const void *source, void *dest, int count)
memcpy(dest, source, count * size);
for (i = 0; i < count; i++) {
- MDeformVert *dvert = POINTER_OFFSET(dest, i * size);
+ MDeformVert *dvert = static_cast<MDeformVert *>(POINTER_OFFSET(dest, i * size));
if (dvert->totweight) {
- MDeformWeight *dw = MEM_malloc_arrayN(
- dvert->totweight, sizeof(*dw), "layerCopy_mdeformvert dw");
+ MDeformWeight *dw = static_cast<MDeformWeight *>(
+ MEM_malloc_arrayN(dvert->totweight, sizeof(*dw), __func__));
memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw));
dvert->dw = dw;
}
else {
- dvert->dw = NULL;
+ dvert->dw = nullptr;
}
}
}
@@ -200,11 +200,11 @@ static void layerCopy_mdeformvert(const void *source, void *dest, int count)
static void layerFree_mdeformvert(void *data, int count, int size)
{
for (int i = 0; i < count; i++) {
- MDeformVert *dvert = POINTER_OFFSET(data, i * size);
+ MDeformVert *dvert = static_cast<MDeformVert *>(POINTER_OFFSET(data, i * size));
if (dvert->dw) {
MEM_freeN(dvert->dw);
- dvert->dw = NULL;
+ dvert->dw = nullptr;
dvert->totweight = 0;
}
}
@@ -216,8 +216,8 @@ static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest,
const int size = sizeof(void *);
for (int i = 0; i < count; i++) {
- void **ptr = POINTER_OFFSET(dest, i * size);
- *ptr = NULL;
+ void **ptr = (void **)POINTER_OFFSET(dest, i * size);
+ *ptr = nullptr;
}
}
@@ -231,9 +231,9 @@ void bpy_bm_generic_invalidate(struct BPy_BMGeneric *UNUSED(self))
static void layerFree_bmesh_elem_py_ptr(void *data, int count, int size)
{
for (int i = 0; i < count; i++) {
- void **ptr = POINTER_OFFSET(data, i * size);
+ void **ptr = (void **)POINTER_OFFSET(data, i * size);
if (*ptr) {
- bpy_bm_generic_invalidate(*ptr);
+ bpy_bm_generic_invalidate(static_cast<BPy_BMGeneric *>(*ptr));
}
}
}
@@ -251,14 +251,14 @@ static void layerInterp_mdeformvert(const void **sources,
MDeformWeight dw;
};
- MDeformVert *dvert = dest;
- struct MDeformWeight_Link *dest_dwlink = NULL;
+ MDeformVert *dvert = static_cast<MDeformVert *>(dest);
+ struct MDeformWeight_Link *dest_dwlink = nullptr;
struct MDeformWeight_Link *node;
/* build a list of unique def_nrs for dest */
int totweight = 0;
for (int i = 0; i < count; i++) {
- const MDeformVert *source = sources[i];
+ const MDeformVert *source = static_cast<const MDeformVert *>(sources[i]);
float interp_weight = weights[i];
for (int j = 0; j < source->totweight; j++) {
@@ -280,7 +280,8 @@ static void layerInterp_mdeformvert(const void **sources,
/* if this def_nr is not in the list, add it */
if (!node) {
- struct MDeformWeight_Link *tmp_dwlink = alloca(sizeof(*tmp_dwlink));
+ struct MDeformWeight_Link *tmp_dwlink = static_cast<MDeformWeight_Link *>(
+ alloca(sizeof(*tmp_dwlink)));
tmp_dwlink->dw.def_nr = dw->def_nr;
tmp_dwlink->dw.weight = weight;
@@ -305,7 +306,8 @@ static void layerInterp_mdeformvert(const void **sources,
}
if (totweight) {
- dvert->dw = MEM_malloc_arrayN(totweight, sizeof(*dvert->dw), __func__);
+ dvert->dw = static_cast<MDeformWeight *>(
+ MEM_malloc_arrayN(totweight, sizeof(*dvert->dw), __func__));
}
}
@@ -346,7 +348,7 @@ static void layerInterp_normal(const void **sources,
static bool layerValidate_normal(void *data, const uint totitems, const bool do_fixes)
{
static const float no_default[3] = {0.0f, 0.0f, 1.0f}; /* Z-up default normal... */
- float(*no)[3] = data;
+ float(*no)[3] = (float(*)[3])data;
bool has_errors = false;
for (int i = 0; i < totitems; i++, no++) {
@@ -372,8 +374,8 @@ static void layerCopyValue_normal(const void *source,
const int mixmode,
const float mixfactor)
{
- const float *no_src = source;
- float *no_dst = dest;
+ const float *no_src = (const float *)source;
+ float *no_dst = (float *)dest;
float no_tmp[3];
if (ELEM(mixmode,
@@ -416,13 +418,13 @@ static void layerCopy_tface(const void *source, void *dest, int count)
static void layerInterp_tface(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
{
- MTFace *tf = dest;
+ MTFace *tf = static_cast<MTFace *>(dest);
float uv[4][2] = {{0.0f}};
const float *sub_weight = sub_weights;
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MTFace *src = sources[i];
+ const MTFace *src = static_cast<const MTFace *>(sources[i]);
for (int j = 0; j < 4; j++) {
if (sub_weights) {
@@ -443,7 +445,7 @@ static void layerInterp_tface(
static void layerSwap_tface(void *data, const int *corner_indices)
{
- MTFace *tf = data;
+ MTFace *tf = static_cast<MTFace *>(data);
float uv[4][2];
for (int j = 0; j < 4; j++) {
@@ -464,7 +466,7 @@ static void layerDefault_tface(void *data, int count)
}
}
-static int layerMaxNum_tface(void)
+static int layerMaxNum_tface()
{
return MAX_MTFACE;
}
@@ -491,7 +493,7 @@ static void layerInterp_propFloat(const void **sources,
static bool layerValidate_propFloat(void *data, const uint totitems, const bool do_fixes)
{
- MFloatProperty *fp = data;
+ MFloatProperty *fp = static_cast<MFloatProperty *>(data);
bool has_errors = false;
for (int i = 0; i < totitems; i++, fp++) {
@@ -529,13 +531,13 @@ static void layerCopy_origspace_face(const void *source, void *dest, int count)
static void layerInterp_origspace_face(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
{
- OrigSpaceFace *osf = dest;
+ OrigSpaceFace *osf = static_cast<OrigSpaceFace *>(dest);
float uv[4][2] = {{0.0f}};
const float *sub_weight = sub_weights;
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const OrigSpaceFace *src = sources[i];
+ const OrigSpaceFace *src = static_cast<const OrigSpaceFace *>(sources[i]);
for (int j = 0; j < 4; j++) {
if (sub_weights) {
@@ -555,7 +557,7 @@ static void layerInterp_origspace_face(
static void layerSwap_origspace_face(void *data, const int *corner_indices)
{
- OrigSpaceFace *osf = data;
+ OrigSpaceFace *osf = static_cast<OrigSpaceFace *>(data);
float uv[4][2];
for (int j = 0; j < 4; j++) {
@@ -576,7 +578,7 @@ static void layerDefault_origspace_face(void *data, int count)
static void layerSwap_mdisps(void *data, const int *ci)
{
- MDisps *s = data;
+ MDisps *s = static_cast<MDisps *>(data);
if (s->disps) {
int nverts = (ci[1] == 3) ? 4 : 3; /* silly way to know vertex count of face */
@@ -589,11 +591,11 @@ static void layerSwap_mdisps(void *data, const int *ci)
MEM_freeN(s->disps);
s->totdisp = (s->totdisp / corners) * nverts;
- s->disps = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisp swap");
+ s->disps = (float(*)[3])MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisp swap");
return;
}
- float(*d)[3] = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap");
+ float(*d)[3] = (float(*)[3])MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap");
for (int S = 0; S < corners; S++) {
memcpy(d + cornersize * S, s->disps + cornersize * ci[S], sizeof(float[3]) * cornersize);
@@ -606,17 +608,17 @@ static void layerSwap_mdisps(void *data, const int *ci)
static void layerCopy_mdisps(const void *source, void *dest, int count)
{
- const MDisps *s = source;
- MDisps *d = dest;
+ const MDisps *s = static_cast<const MDisps *>(source);
+ MDisps *d = static_cast<MDisps *>(dest);
for (int i = 0; i < count; i++) {
if (s[i].disps) {
- d[i].disps = MEM_dupallocN(s[i].disps);
- d[i].hidden = MEM_dupallocN(s[i].hidden);
+ d[i].disps = static_cast<float(*)[3]>(MEM_dupallocN(s[i].disps));
+ d[i].hidden = static_cast<unsigned int *>(MEM_dupallocN(s[i].hidden));
}
else {
- d[i].disps = NULL;
- d[i].hidden = NULL;
+ d[i].disps = nullptr;
+ d[i].hidden = nullptr;
}
/* still copy even if not in memory, displacement can be external */
@@ -627,7 +629,7 @@ static void layerCopy_mdisps(const void *source, void *dest, int count)
static void layerFree_mdisps(void *data, int count, int UNUSED(size))
{
- MDisps *d = data;
+ MDisps *d = static_cast<MDisps *>(data);
for (int i = 0; i < count; i++) {
if (d[i].disps) {
@@ -636,8 +638,8 @@ static void layerFree_mdisps(void *data, int count, int UNUSED(size))
if (d[i].hidden) {
MEM_freeN(d[i].hidden);
}
- d[i].disps = NULL;
- d[i].hidden = NULL;
+ d[i].disps = nullptr;
+ d[i].hidden = nullptr;
d[i].totdisp = 0;
d[i].level = 0;
}
@@ -645,16 +647,16 @@ static void layerFree_mdisps(void *data, int count, int UNUSED(size))
static bool layerRead_mdisps(CDataFile *cdf, void *data, int count)
{
- MDisps *d = data;
+ MDisps *d = static_cast<MDisps *>(data);
for (int i = 0; i < count; i++) {
if (!d[i].disps) {
- d[i].disps = MEM_calloc_arrayN(d[i].totdisp, sizeof(float[3]), "mdisps read");
+ d[i].disps = (float(*)[3])MEM_calloc_arrayN(d[i].totdisp, sizeof(float[3]), "mdisps read");
}
if (!cdf_read_data(cdf, sizeof(float[3]) * d[i].totdisp, d[i].disps)) {
CLOG_ERROR(&LOG, "failed to read multires displacement %d/%d %d", i, count, d[i].totdisp);
- return 0;
+ return false;
}
}
@@ -663,12 +665,12 @@ static bool layerRead_mdisps(CDataFile *cdf, void *data, int count)
static bool layerWrite_mdisps(CDataFile *cdf, const void *data, int count)
{
- const MDisps *d = data;
+ const MDisps *d = static_cast<const MDisps *>(data);
for (int i = 0; i < count; i++) {
if (!cdf_write_data(cdf, sizeof(float[3]) * d[i].totdisp, d[i].disps)) {
CLOG_ERROR(&LOG, "failed to write multires displacement %d/%d %d", i, count, d[i].totdisp);
- return 0;
+ return false;
}
}
@@ -677,7 +679,7 @@ static bool layerWrite_mdisps(CDataFile *cdf, const void *data, int count)
static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int count)
{
- const MDisps *d = data;
+ const MDisps *d = static_cast<const MDisps *>(data);
size_t size = 0;
for (int i = 0; i < count; i++) {
@@ -695,7 +697,7 @@ static void layerInterp_paint_mask(const void **sources,
float mask = 0.0f;
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const float *src = sources[i];
+ const float *src = static_cast<const float *>(sources[i]);
mask += (*src) * interp_weight;
}
*(float *)dest = mask;
@@ -703,16 +705,16 @@ static void layerInterp_paint_mask(const void **sources,
static void layerCopy_grid_paint_mask(const void *source, void *dest, int count)
{
- const GridPaintMask *s = source;
- GridPaintMask *d = dest;
+ const GridPaintMask *s = static_cast<const GridPaintMask *>(source);
+ GridPaintMask *d = static_cast<GridPaintMask *>(dest);
for (int i = 0; i < count; i++) {
if (s[i].data) {
- d[i].data = MEM_dupallocN(s[i].data);
+ d[i].data = static_cast<float *>(MEM_dupallocN(s[i].data));
d[i].level = s[i].level;
}
else {
- d[i].data = NULL;
+ d[i].data = nullptr;
d[i].level = 0;
}
}
@@ -720,7 +722,7 @@ static void layerCopy_grid_paint_mask(const void *source, void *dest, int count)
static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size))
{
- GridPaintMask *gpm = data;
+ GridPaintMask *gpm = static_cast<GridPaintMask *>(data);
for (int i = 0; i < count; i++) {
MEM_SAFE_FREE(gpm[i].data);
@@ -734,8 +736,8 @@ static void layerCopyValue_mloopcol(const void *source,
const int mixmode,
const float mixfactor)
{
- const MLoopCol *m1 = source;
- MLoopCol *m2 = dest;
+ const MLoopCol *m1 = static_cast<const MLoopCol *>(source);
+ MLoopCol *m2 = static_cast<MLoopCol *>(dest);
unsigned char tmp_col[4];
if (ELEM(mixmode,
@@ -789,7 +791,8 @@ static void layerCopyValue_mloopcol(const void *source,
static bool layerEqual_mloopcol(const void *data1, const void *data2)
{
- const MLoopCol *m1 = data1, *m2 = data2;
+ const MLoopCol *m1 = static_cast<const MLoopCol *>(data1);
+ const MLoopCol *m2 = static_cast<const MLoopCol *>(data2);
float r, g, b, a;
r = m1->r - m2->r;
@@ -802,7 +805,7 @@ static bool layerEqual_mloopcol(const void *data1, const void *data2)
static void layerMultiply_mloopcol(void *data, float fac)
{
- MLoopCol *m = data;
+ MLoopCol *m = static_cast<MLoopCol *>(data);
m->r = (float)m->r * fac;
m->g = (float)m->g * fac;
@@ -812,8 +815,8 @@ static void layerMultiply_mloopcol(void *data, float fac)
static void layerAdd_mloopcol(void *data1, const void *data2)
{
- MLoopCol *m = data1;
- const MLoopCol *m2 = data2;
+ MLoopCol *m = static_cast<MLoopCol *>(data1);
+ const MLoopCol *m2 = static_cast<const MLoopCol *>(data2);
m->r += m2->r;
m->g += m2->g;
@@ -823,8 +826,9 @@ static void layerAdd_mloopcol(void *data1, const void *data2)
static void layerDoMinMax_mloopcol(const void *data, void *vmin, void *vmax)
{
- const MLoopCol *m = data;
- MLoopCol *min = vmin, *max = vmax;
+ const MLoopCol *m = static_cast<const MLoopCol *>(data);
+ MLoopCol *min = static_cast<MLoopCol *>(vmin);
+ MLoopCol *max = static_cast<MLoopCol *>(vmax);
if (m->r < min->r) {
min->r = m->r;
@@ -854,7 +858,8 @@ static void layerDoMinMax_mloopcol(const void *data, void *vmin, void *vmax)
static void layerInitMinMax_mloopcol(void *vmin, void *vmax)
{
- MLoopCol *min = vmin, *max = vmax;
+ MLoopCol *min = static_cast<MLoopCol *>(vmin);
+ MLoopCol *max = static_cast<MLoopCol *>(vmax);
min->r = 255;
min->g = 255;
@@ -882,7 +887,7 @@ static void layerInterp_mloopcol(const void **sources,
int count,
void *dest)
{
- MLoopCol *mc = dest;
+ MLoopCol *mc = static_cast<MLoopCol *>(dest);
struct {
float a;
float r;
@@ -892,7 +897,7 @@ static void layerInterp_mloopcol(const void **sources,
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MLoopCol *src = sources[i];
+ const MLoopCol *src = static_cast<const MLoopCol *>(sources[i]);
col.r += src->r * interp_weight;
col.g += src->g * interp_weight;
col.b += src->b * interp_weight;
@@ -909,7 +914,7 @@ static void layerInterp_mloopcol(const void **sources,
mc->a = round_fl_to_uchar_clamp(col.a);
}
-static int layerMaxNum_mloopcol(void)
+static int layerMaxNum_mloopcol()
{
return MAX_MCOL;
}
@@ -919,8 +924,8 @@ static void layerCopyValue_mloopuv(const void *source,
const int mixmode,
const float mixfactor)
{
- const MLoopUV *luv1 = source;
- MLoopUV *luv2 = dest;
+ const MLoopUV *luv1 = static_cast<const MLoopUV *>(source);
+ MLoopUV *luv2 = static_cast<MLoopUV *>(dest);
/* We only support a limited subset of advanced mixing here -
* namely the mixfactor interpolation. */
@@ -935,37 +940,40 @@ static void layerCopyValue_mloopuv(const void *source,
static bool layerEqual_mloopuv(const void *data1, const void *data2)
{
- const MLoopUV *luv1 = data1, *luv2 = data2;
+ const MLoopUV *luv1 = static_cast<const MLoopUV *>(data1);
+ const MLoopUV *luv2 = static_cast<const MLoopUV *>(data2);
return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
}
static void layerMultiply_mloopuv(void *data, float fac)
{
- MLoopUV *luv = data;
+ MLoopUV *luv = static_cast<MLoopUV *>(data);
mul_v2_fl(luv->uv, fac);
}
static void layerInitMinMax_mloopuv(void *vmin, void *vmax)
{
- MLoopUV *min = vmin, *max = vmax;
+ MLoopUV *min = static_cast<MLoopUV *>(vmin);
+ MLoopUV *max = static_cast<MLoopUV *>(vmax);
INIT_MINMAX2(min->uv, max->uv);
}
static void layerDoMinMax_mloopuv(const void *data, void *vmin, void *vmax)
{
- const MLoopUV *luv = data;
- MLoopUV *min = vmin, *max = vmax;
+ const MLoopUV *luv = static_cast<const MLoopUV *>(data);
+ MLoopUV *min = static_cast<MLoopUV *>(vmin);
+ MLoopUV *max = static_cast<MLoopUV *>(vmax);
minmax_v2v2_v2(min->uv, max->uv, luv->uv);
}
static void layerAdd_mloopuv(void *data1, const void *data2)
{
- MLoopUV *l1 = data1;
- const MLoopUV *l2 = data2;
+ MLoopUV *l1 = static_cast<MLoopUV *>(data1);
+ const MLoopUV *l2 = static_cast<const MLoopUV *>(data2);
add_v2_v2(l1->uv, l2->uv);
}
@@ -983,7 +991,7 @@ static void layerInterp_mloopuv(const void **sources,
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MLoopUV *src = sources[i];
+ const MLoopUV *src = static_cast<const MLoopUV *>(sources[i]);
madd_v2_v2fl(uv, src->uv, interp_weight);
if (interp_weight > 0.0f) {
flag |= src->flag;
@@ -997,7 +1005,7 @@ static void layerInterp_mloopuv(const void **sources,
static bool layerValidate_mloopuv(void *data, const uint totitems, const bool do_fixes)
{
- MLoopUV *uv = data;
+ MLoopUV *uv = static_cast<MLoopUV *>(data);
bool has_errors = false;
for (int i = 0; i < totitems; i++, uv++) {
@@ -1018,45 +1026,48 @@ static void layerCopyValue_mloop_origspace(const void *source,
const int UNUSED(mixmode),
const float UNUSED(mixfactor))
{
- const OrigSpaceLoop *luv1 = source;
- OrigSpaceLoop *luv2 = dest;
+ const OrigSpaceLoop *luv1 = static_cast<const OrigSpaceLoop *>(source);
+ OrigSpaceLoop *luv2 = static_cast<OrigSpaceLoop *>(dest);
copy_v2_v2(luv2->uv, luv1->uv);
}
static bool layerEqual_mloop_origspace(const void *data1, const void *data2)
{
- const OrigSpaceLoop *luv1 = data1, *luv2 = data2;
+ const OrigSpaceLoop *luv1 = static_cast<const OrigSpaceLoop *>(data1);
+ const OrigSpaceLoop *luv2 = static_cast<const OrigSpaceLoop *>(data2);
return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
}
static void layerMultiply_mloop_origspace(void *data, float fac)
{
- OrigSpaceLoop *luv = data;
+ OrigSpaceLoop *luv = static_cast<OrigSpaceLoop *>(data);
mul_v2_fl(luv->uv, fac);
}
static void layerInitMinMax_mloop_origspace(void *vmin, void *vmax)
{
- OrigSpaceLoop *min = vmin, *max = vmax;
+ OrigSpaceLoop *min = static_cast<OrigSpaceLoop *>(vmin);
+ OrigSpaceLoop *max = static_cast<OrigSpaceLoop *>(vmax);
INIT_MINMAX2(min->uv, max->uv);
}
static void layerDoMinMax_mloop_origspace(const void *data, void *vmin, void *vmax)
{
- const OrigSpaceLoop *luv = data;
- OrigSpaceLoop *min = vmin, *max = vmax;
+ const OrigSpaceLoop *luv = static_cast<const OrigSpaceLoop *>(data);
+ OrigSpaceLoop *min = static_cast<OrigSpaceLoop *>(vmin);
+ OrigSpaceLoop *max = static_cast<OrigSpaceLoop *>(vmax);
minmax_v2v2_v2(min->uv, max->uv, luv->uv);
}
static void layerAdd_mloop_origspace(void *data1, const void *data2)
{
- OrigSpaceLoop *l1 = data1;
- const OrigSpaceLoop *l2 = data2;
+ OrigSpaceLoop *l1 = static_cast<OrigSpaceLoop *>(data1);
+ const OrigSpaceLoop *l2 = static_cast<const OrigSpaceLoop *>(data2);
add_v2_v2(l1->uv, l2->uv);
}
@@ -1072,7 +1083,7 @@ static void layerInterp_mloop_origspace(const void **sources,
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const OrigSpaceLoop *src = sources[i];
+ const OrigSpaceLoop *src = static_cast<const OrigSpaceLoop *>(sources[i]);
madd_v2_v2fl(uv, src->uv, interp_weight);
}
@@ -1084,7 +1095,7 @@ static void layerInterp_mloop_origspace(const void **sources,
static void layerInterp_mcol(
const void **sources, const float *weights, const float *sub_weights, int count, void *dest)
{
- MCol *mc = dest;
+ MCol *mc = static_cast<MCol *>(dest);
struct {
float a;
float r;
@@ -1098,7 +1109,7 @@ static void layerInterp_mcol(
for (int j = 0; j < 4; j++) {
if (sub_weights) {
- const MCol *src = sources[i];
+ const MCol *src = static_cast<const MCol *>(sources[i]);
for (int k = 0; k < 4; k++, sub_weight++, src++) {
const float w = (*sub_weight) * interp_weight;
col[j].a += src->a * w;
@@ -1108,7 +1119,7 @@ static void layerInterp_mcol(
}
}
else {
- const MCol *src = sources[i];
+ const MCol *src = static_cast<const MCol *>(sources[i]);
col[j].a += src[j].a * interp_weight;
col[j].r += src[j].r * interp_weight;
col[j].g += src[j].g * interp_weight;
@@ -1131,7 +1142,7 @@ static void layerInterp_mcol(
static void layerSwap_mcol(void *data, const int *corner_indices)
{
- MCol *mcol = data;
+ MCol *mcol = static_cast<MCol *>(data);
MCol col[4];
for (int j = 0; j < 4; j++) {
@@ -1205,7 +1216,7 @@ static void layerInterp_shapekey(const void **sources,
static void layerDefault_mvert_skin(void *data, int count)
{
- MVertSkin *vs = data;
+ MVertSkin *vs = static_cast<MVertSkin *>(data);
for (int i = 0; i < count; i++) {
copy_v3_fl(vs[i].radius, 0.25f);
@@ -1229,20 +1240,20 @@ static void layerInterp_mvert_skin(const void **sources,
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MVertSkin *vs_src = sources[i];
+ const MVertSkin *vs_src = static_cast<const MVertSkin *>(sources[i]);
madd_v3_v3fl(radius, vs_src->radius, interp_weight);
}
/* Delay writing to the destination in case dest is in sources. */
- MVertSkin *vs_dst = dest;
+ MVertSkin *vs_dst = static_cast<MVertSkin *>(dest);
copy_v3_v3(vs_dst->radius, radius);
vs_dst->flag &= ~MVERT_SKIN_ROOT;
}
static void layerSwap_flnor(void *data, const int *corner_indices)
{
- short(*flnors)[4][3] = data;
+ short(*flnors)[4][3] = static_cast<short(*)[4][3]>(data);
short nors[4][3];
int i = 4;
@@ -1266,8 +1277,8 @@ static void layerCopyValue_propcol(const void *source,
const int mixmode,
const float mixfactor)
{
- const MPropCol *m1 = source;
- MPropCol *m2 = dest;
+ const MPropCol *m1 = static_cast<const MPropCol *>(source);
+ MPropCol *m2 = static_cast<MPropCol *>(dest);
float tmp_col[4];
if (ELEM(mixmode,
@@ -1311,7 +1322,8 @@ static void layerCopyValue_propcol(const void *source,
static bool layerEqual_propcol(const void *data1, const void *data2)
{
- const MPropCol *m1 = data1, *m2 = data2;
+ const MPropCol *m1 = static_cast<const MPropCol *>(data1);
+ const MPropCol *m2 = static_cast<const MPropCol *>(data2);
float tot = 0;
for (int i = 0; i < 4; i++) {
@@ -1324,27 +1336,29 @@ static bool layerEqual_propcol(const void *data1, const void *data2)
static void layerMultiply_propcol(void *data, float fac)
{
- MPropCol *m = data;
+ MPropCol *m = static_cast<MPropCol *>(data);
mul_v4_fl(m->color, fac);
}
static void layerAdd_propcol(void *data1, const void *data2)
{
- MPropCol *m = data1;
- const MPropCol *m2 = data2;
+ MPropCol *m = static_cast<MPropCol *>(data1);
+ const MPropCol *m2 = static_cast<const MPropCol *>(data2);
add_v4_v4(m->color, m2->color);
}
static void layerDoMinMax_propcol(const void *data, void *vmin, void *vmax)
{
- const MPropCol *m = data;
- MPropCol *min = vmin, *max = vmax;
+ const MPropCol *m = static_cast<const MPropCol *>(data);
+ MPropCol *min = static_cast<MPropCol *>(vmin);
+ MPropCol *max = static_cast<MPropCol *>(vmax);
minmax_v4v4_v4(min->color, max->color, m->color);
}
static void layerInitMinMax_propcol(void *vmin, void *vmax)
{
- MPropCol *min = vmin, *max = vmax;
+ MPropCol *min = static_cast<MPropCol *>(vmin);
+ MPropCol *max = static_cast<MPropCol *>(vmax);
copy_v4_fl(min->color, FLT_MAX);
copy_v4_fl(max->color, FLT_MIN);
@@ -1366,17 +1380,17 @@ static void layerInterp_propcol(const void **sources,
int count,
void *dest)
{
- MPropCol *mc = dest;
+ MPropCol *mc = static_cast<MPropCol *>(dest);
float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const MPropCol *src = sources[i];
+ const MPropCol *src = static_cast<const MPropCol *>(sources[i]);
madd_v4_v4fl(col, src->color, interp_weight);
}
copy_v4_v4(mc->color, col);
}
-static int layerMaxNum_propcol(void)
+static int layerMaxNum_propcol()
{
return MAX_MCOL;
}
@@ -1390,7 +1404,7 @@ static void layerInterp_propfloat3(const void **sources,
vec3f result = {0.0f, 0.0f, 0.0f};
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const vec3f *src = sources[i];
+ const vec3f *src = static_cast<const vec3f *>(sources[i]);
madd_v3_v3fl(&result.x, &src->x, interp_weight);
}
copy_v3_v3((float *)dest, &result.x);
@@ -1398,7 +1412,7 @@ static void layerInterp_propfloat3(const void **sources,
static void layerMultiply_propfloat3(void *data, float fac)
{
- vec3f *vec = data;
+ vec3f *vec = static_cast<vec3f *>(data);
vec->x *= fac;
vec->y *= fac;
vec->z *= fac;
@@ -1406,8 +1420,8 @@ static void layerMultiply_propfloat3(void *data, float fac)
static void layerAdd_propfloat3(void *data1, const void *data2)
{
- vec3f *vec1 = data1;
- const vec3f *vec2 = data2;
+ vec3f *vec1 = static_cast<vec3f *>(data1);
+ const vec3f *vec2 = static_cast<const vec3f *>(data2);
vec1->x += vec2->x;
vec1->y += vec2->y;
vec1->z += vec2->z;
@@ -1415,7 +1429,7 @@ static void layerAdd_propfloat3(void *data1, const void *data2)
static bool layerValidate_propfloat3(void *data, const uint totitems, const bool do_fixes)
{
- float *values = data;
+ float *values = static_cast<float *>(data);
bool has_errors = false;
for (int i = 0; i < totitems * 3; i++) {
if (!isfinite(values[i])) {
@@ -1437,7 +1451,7 @@ static void layerInterp_propfloat2(const void **sources,
vec2f result = {0.0f, 0.0f};
for (int i = 0; i < count; i++) {
const float interp_weight = weights[i];
- const vec2f *src = sources[i];
+ const vec2f *src = static_cast<const vec2f *>(sources[i]);
madd_v2_v2fl(&result.x, &src->x, interp_weight);
}
copy_v2_v2((float *)dest, &result.x);
@@ -1445,22 +1459,22 @@ static void layerInterp_propfloat2(const void **sources,
static void layerMultiply_propfloat2(void *data, float fac)
{
- vec2f *vec = data;
+ vec2f *vec = static_cast<vec2f *>(data);
vec->x *= fac;
vec->y *= fac;
}
static void layerAdd_propfloat2(void *data1, const void *data2)
{
- vec2f *vec1 = data1;
- const vec2f *vec2 = data2;
+ vec2f *vec1 = static_cast<vec2f *>(data1);
+ const vec2f *vec2 = static_cast<const vec2f *>(data2);
vec1->x += vec2->x;
vec1->y += vec2->y;
}
static bool layerValidate_propfloat2(void *data, const uint totitems, const bool do_fixes)
{
- float *values = data;
+ float *values = static_cast<float *>(data);
bool has_errors = false;
for (int i = 0; i < totitems * 2; i++) {
if (!isfinite(values[i])) {
@@ -1475,136 +1489,130 @@ static bool layerValidate_propfloat2(void *data, const uint totitems, const bool
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 0: CD_MVERT */
- {sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MVert), "MVert", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 1: CD_MSTICKY */ /* DEPRECATED */
- {sizeof(float[2]), "", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[2]), "", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 2: CD_MDEFORMVERT */
{sizeof(MDeformVert),
"MDeformVert",
1,
- NULL,
+ nullptr,
layerCopy_mdeformvert,
layerFree_mdeformvert,
layerInterp_mdeformvert,
- NULL,
- NULL},
+ nullptr,
+ nullptr},
/* 3: CD_MEDGE */
- {sizeof(MEdge), "MEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MEdge), "MEdge", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 4: CD_MFACE */
- {sizeof(MFace), "MFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MFace), "MFace", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 5: CD_MTFACE */
- {sizeof(MTFace),
- "MTFace",
- 1,
- N_("UVMap"),
- layerCopy_tface,
- NULL,
- layerInterp_tface,
- layerSwap_tface,
- layerDefault_tface,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- layerMaxNum_tface},
+ {sizeof(MTFace), "MTFace", 1,
+ N_("UVMap"), layerCopy_tface, nullptr,
+ layerInterp_tface, layerSwap_tface, layerDefault_tface,
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr,
+ nullptr, layerMaxNum_tface},
/* 6: CD_MCOL */
/* 4 MCol structs per face */
{sizeof(MCol[4]),
"MCol",
4,
N_("Col"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mcol,
layerSwap_mcol,
layerDefault_mcol,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
layerMaxNum_mloopcol},
/* 7: CD_ORIGINDEX */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_origindex},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_origindex},
/* 8: CD_NORMAL */
/* 3 floats per normal vector */
{sizeof(float[3]),
"vec3f",
1,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerInterp_normal,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerValidate_normal,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
layerCopyValue_normal},
/* 9: CD_FACEMAP */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_fmap, NULL},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_fmap, nullptr},
/* 10: CD_PROP_FLOAT */
{sizeof(MFloatProperty),
"MFloatProperty",
1,
N_("Float"),
layerCopy_propFloat,
- NULL,
+ nullptr,
layerInterp_propFloat,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerValidate_propFloat},
/* 11: CD_PROP_INT32 */
- {sizeof(MIntProperty), "MIntProperty", 1, N_("Int"), layerCopy_propInt, NULL, NULL, NULL},
+ {sizeof(MIntProperty),
+ "MIntProperty",
+ 1,
+ N_("Int"),
+ layerCopy_propInt,
+ nullptr,
+ nullptr,
+ nullptr},
/* 12: CD_PROP_STRING */
{sizeof(MStringProperty),
"MStringProperty",
1,
N_("String"),
layerCopy_propString,
- NULL,
- NULL,
- NULL},
+ nullptr,
+ nullptr,
+ nullptr},
/* 13: CD_ORIGSPACE */
{sizeof(OrigSpaceFace),
"OrigSpaceFace",
1,
N_("UVMap"),
layerCopy_origspace_face,
- NULL,
+ nullptr,
layerInterp_origspace_face,
layerSwap_origspace_face,
layerDefault_origspace_face},
/* 14: CD_ORCO */
- {sizeof(float[3]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[3]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 15: CD_MTEXPOLY */ /* DEPRECATED */
/* NOTE: when we expose the UV Map / TexFace split to the user,
* change this back to face Texture. */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 16: CD_MLOOPUV */
{sizeof(MLoopUV),
"MLoopUV",
1,
N_("UVMap"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mloopuv,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerValidate_mloopuv,
layerEqual_mloopuv,
layerMultiply_mloopuv,
@@ -1612,50 +1620,50 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerAdd_mloopuv,
layerDoMinMax_mloopuv,
layerCopyValue_mloopuv,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerMaxNum_tface},
/* 17: CD_MLOOPCOL */
{sizeof(MLoopCol),
"MLoopCol",
1,
N_("Col"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mloopcol,
- NULL,
+ nullptr,
layerDefault_mloopcol,
- NULL,
+ nullptr,
layerEqual_mloopcol,
layerMultiply_mloopcol,
layerInitMinMax_mloopcol,
layerAdd_mloopcol,
layerDoMinMax_mloopcol,
layerCopyValue_mloopcol,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerMaxNum_mloopcol},
/* 18: CD_TANGENT */
- {sizeof(float[4][4]), "", 0, N_("Tangent"), NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[4][4]), "", 0, N_("Tangent"), nullptr, nullptr, nullptr, nullptr, nullptr},
/* 19: CD_MDISPS */
{sizeof(MDisps),
"MDisps",
1,
- NULL,
+ nullptr,
layerCopy_mdisps,
layerFree_mdisps,
- NULL,
+ nullptr,
layerSwap_mdisps,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
layerRead_mdisps,
layerWrite_mdisps,
layerFilesize_mdisps},
@@ -1664,52 +1672,58 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
"MCol",
4,
N_("PreviewCol"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mcol,
layerSwap_mcol,
layerDefault_mcol},
/* 21: CD_ID_MCOL */ /* DEPRECATED */
- {sizeof(MCol[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MCol[4]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 22: CD_TEXTURE_MCOL */
{sizeof(MCol[4]),
"MCol",
4,
N_("TexturedCol"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mcol,
layerSwap_mcol,
layerDefault_mcol},
/* 23: CD_CLOTH_ORCO */
- {sizeof(float[3]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[3]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 24: CD_RECAST */
- {sizeof(MRecast), "MRecast", 1, N_("Recast"), NULL, NULL, NULL, NULL},
-
- /* BMESH ONLY */
+ {sizeof(MRecast), "MRecast", 1, N_("Recast"), nullptr, nullptr, nullptr, nullptr},
/* 25: CD_MPOLY */
- {sizeof(MPoly), "MPoly", 1, N_("NGon Face"), NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MPoly), "MPoly", 1, N_("NGon Face"), nullptr, nullptr, nullptr, nullptr, nullptr},
/* 26: CD_MLOOP */
- {sizeof(MLoop), "MLoop", 1, N_("NGon Face-Vertex"), NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MLoop),
+ "MLoop",
+ 1,
+ N_("NGon Face-Vertex"),
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr},
/* 27: CD_SHAPE_KEYINDEX */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 28: CD_SHAPEKEY */
- {sizeof(float[3]), "", 0, N_("ShapeKey"), NULL, NULL, layerInterp_shapekey},
+ {sizeof(float[3]), "", 0, N_("ShapeKey"), nullptr, nullptr, layerInterp_shapekey},
/* 29: CD_BWEIGHT */
- {sizeof(float), "", 0, N_("BevelWeight"), NULL, NULL, layerInterp_bweight},
+ {sizeof(float), "", 0, N_("BevelWeight"), nullptr, nullptr, layerInterp_bweight},
/* 30: CD_CREASE */
- {sizeof(float), "", 0, N_("SubSurfCrease"), NULL, NULL, layerInterp_bweight},
+ {sizeof(float), "", 0, N_("SubSurfCrease"), nullptr, nullptr, layerInterp_bweight},
/* 31: CD_ORIGSPACE_MLOOP */
{sizeof(OrigSpaceLoop),
"OrigSpaceLoop",
1,
N_("OS Loop"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mloop_origspace,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerEqual_mloop_origspace,
layerMultiply_mloop_origspace,
layerInitMinMax_mloop_origspace,
@@ -1721,12 +1735,12 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
"MLoopCol",
1,
N_("PreviewLoopCol"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_mloopcol,
- NULL,
+ nullptr,
layerDefault_mloopcol,
- NULL,
+ nullptr,
layerEqual_mloopcol,
layerMultiply_mloopcol,
layerInitMinMax_mloopcol,
@@ -1737,125 +1751,138 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(void *),
"",
1,
- NULL,
+ nullptr,
layerCopy_bmesh_elem_py_ptr,
layerFree_bmesh_elem_py_ptr,
- NULL,
- NULL,
- NULL},
-
- /* END BMESH ONLY */
-
+ nullptr,
+ nullptr,
+ nullptr},
/* 34: CD_PAINT_MASK */
- {sizeof(float), "", 0, NULL, NULL, NULL, layerInterp_paint_mask, NULL, NULL},
+ {sizeof(float), "", 0, nullptr, nullptr, nullptr, layerInterp_paint_mask, nullptr, nullptr},
/* 35: CD_GRID_PAINT_MASK */
{sizeof(GridPaintMask),
"GridPaintMask",
1,
- NULL,
+ nullptr,
layerCopy_grid_paint_mask,
layerFree_grid_paint_mask,
- NULL,
- NULL,
- NULL},
+ nullptr,
+ nullptr,
+ nullptr},
/* 36: CD_MVERT_SKIN */
{sizeof(MVertSkin),
"MVertSkin",
1,
- NULL,
+ nullptr,
layerCopy_mvert_skin,
- NULL,
+ nullptr,
layerInterp_mvert_skin,
- NULL,
+ nullptr,
layerDefault_mvert_skin},
/* 37: CD_FREESTYLE_EDGE */
- {sizeof(FreestyleEdge), "FreestyleEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(FreestyleEdge),
+ "FreestyleEdge",
+ 1,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr},
/* 38: CD_FREESTYLE_FACE */
- {sizeof(FreestyleFace), "FreestyleFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(FreestyleFace),
+ "FreestyleFace",
+ 1,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr},
/* 39: CD_MLOOPTANGENT */
- {sizeof(float[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[4]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 40: CD_TESSLOOPNORMAL */
- {sizeof(short[4][3]), "", 0, NULL, NULL, NULL, NULL, layerSwap_flnor, NULL},
+ {sizeof(short[4][3]), "", 0, nullptr, nullptr, nullptr, nullptr, layerSwap_flnor, nullptr},
/* 41: CD_CUSTOMLOOPNORMAL */
- {sizeof(short[2]), "vec2s", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(short[2]), "vec2s", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 42: CD_SCULPT_FACE_SETS */
- {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 43: CD_LOCATION */
- {sizeof(float[3]), "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float[3]), "vec3f", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 44: CD_RADIUS */
- {sizeof(float), "MFloatProperty", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float), "MFloatProperty", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 45: CD_HAIRCURVE */
- {sizeof(HairCurve), "HairCurve", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(HairCurve), "HairCurve", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 46: CD_HAIRMAPPING */
- {sizeof(HairMapping), "HairMapping", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(HairMapping), "HairMapping", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 47: CD_PROP_COLOR */
{sizeof(MPropCol),
"MPropCol",
1,
N_("Color"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_propcol,
- NULL,
+ nullptr,
layerDefault_propcol,
- NULL,
+ nullptr,
layerEqual_propcol,
layerMultiply_propcol,
layerInitMinMax_propcol,
layerAdd_propcol,
layerDoMinMax_propcol,
layerCopyValue_propcol,
- NULL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
+ nullptr,
layerMaxNum_propcol},
/* 48: CD_PROP_FLOAT3 */
{sizeof(float[3]),
"vec3f",
1,
N_("Float3"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_propfloat3,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerValidate_propfloat3,
- NULL,
+ nullptr,
layerMultiply_propfloat3,
- NULL,
+ nullptr,
layerAdd_propfloat3},
/* 49: CD_PROP_FLOAT2 */
{sizeof(float[2]),
"vec2f",
1,
N_("Float2"),
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerInterp_propfloat2,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
layerValidate_propfloat2,
- NULL,
+ nullptr,
layerMultiply_propfloat2,
- NULL,
+ nullptr,
layerAdd_propfloat2},
/* 50: CD_PROP_BOOL */
{sizeof(bool),
"bool",
1,
N_("Boolean"),
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr},
/* 51: CD_HAIRLENGTH */
- {sizeof(float), "float", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float), "float", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
};
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
@@ -1916,95 +1943,106 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
};
const CustomData_MeshMasks CD_MASK_BAREMESH = {
- .vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT,
- .emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT,
- .fmask = 0,
- .lmask = CD_MASK_MLOOP,
- .pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP,
+ /* vmask */ CD_MASK_MVERT | CD_MASK_BWEIGHT,
+ /* emask */ CD_MASK_MEDGE | CD_MASK_BWEIGHT,
+ /* fmask */ 0,
+ /* pmask */ CD_MASK_MPOLY | CD_MASK_FACEMAP,
+ /* lmask */ CD_MASK_MLOOP,
};
const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
- .vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
- .emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
- .fmask = 0,
- .lmask = CD_MASK_MLOOP,
- .pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_ORIGINDEX,
+ /* vmask */ CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
+ /* emask */ CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX,
+ /* fmask */ 0,
+ /* pmask */ CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_ORIGINDEX,
+ /* lmask */ CD_MASK_MLOOP,
};
const CustomData_MeshMasks CD_MASK_MESH = {
- .vmask = (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
- CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
- .fmask = 0,
- .lmask = (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL |
- CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
- .pmask = (CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL |
- CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
+ CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
+ /* emask */ (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
+ /* fmask */ 0,
+ /* pmask */
+ (CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL |
+ CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL |
+ CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
};
const CustomData_MeshMasks CD_MASK_EDITMESH = {
- .vmask = (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
- CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_PROP_ALL),
- .fmask = 0,
- .lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
- .pmask = (CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
+ CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
+ /* emask */ (CD_MASK_PROP_ALL),
+ /* fmask */ 0,
+ /* pmask */ (CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
};
const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
- .vmask = (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
- CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL |
- CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
- .fmask = (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
- .lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
- CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
- CD_MASK_PROP_ALL), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */
- .pmask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
- CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
+ CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL |
+ CD_MASK_PROP_COLOR),
+ /* emask */ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
+ /* fmask */ (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
+ /* pmask */
+ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
+ CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_PREVIEW_MLOOPCOL |
+ CD_MASK_ORIGSPACE_MLOOP | CD_MASK_PROP_ALL), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */
};
const CustomData_MeshMasks CD_MASK_BMESH = {
- .vmask = (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
- CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
- .fmask = 0,
- .lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
- .pmask = (CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
- CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY |
+ CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL |
+ CD_MASK_PROP_COLOR),
+ /* emask */ (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
+ /* fmask */ 0,
+ /* pmask */
+ (CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
};
/**
* cover values copied by #mesh_loops_to_tessdata
*/
const CustomData_MeshMasks CD_MASK_FACECORNERS = {
- .vmask = 0,
- .emask = 0,
- .fmask = (CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_PREVIEW_MCOL | CD_MASK_ORIGSPACE |
- CD_MASK_TESSLOOPNORMAL | CD_MASK_TANGENT),
- .lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL |
- CD_MASK_ORIGSPACE_MLOOP | CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT),
- .pmask = 0,
+ /* vmask */ 0,
+ /* emask */ 0,
+ /* fmask */
+ (CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_PREVIEW_MCOL | CD_MASK_ORIGSPACE |
+ CD_MASK_TESSLOOPNORMAL | CD_MASK_TANGENT),
+ /* pmask */ 0,
+ /* lmask */
+ (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
+ CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT),
};
const CustomData_MeshMasks CD_MASK_EVERYTHING = {
- .vmask = (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL |
- CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO |
- CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK |
- CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
- .emask = (CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT |
- CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
- .fmask = (CD_MASK_MFACE | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MTFACE | CD_MASK_MCOL |
- CD_MASK_ORIGSPACE | CD_MASK_TANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_PREVIEW_MCOL |
- CD_MASK_PROP_ALL),
- .lmask = (CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL |
- CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL |
- CD_MASK_MLOOPTANGENT | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
- .pmask = (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL |
- CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL |
- CD_MASK_SCULPT_FACE_SETS),
+ /* vmask */ (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL |
+ CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO |
+ CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX |
+ CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR),
+ /* emask */
+ (CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT | CD_MASK_CREASE |
+ CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
+ /* fmask */
+ (CD_MASK_MFACE | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MTFACE | CD_MASK_MCOL |
+ CD_MASK_ORIGSPACE | CD_MASK_TANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_PREVIEW_MCOL |
+ CD_MASK_PROP_ALL),
+ /* pmask */
+ (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_FACEMAP |
+ CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
+ /* lmask */
+ (CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL | CD_MASK_MLOOPUV |
+ CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_MLOOPTANGENT |
+ CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_GRID_PAINT_MASK |
+ CD_MASK_PROP_ALL),
};
static const LayerTypeInfo *layerType_getInfo(int type)
{
if (type < 0 || type >= CD_NUMTYPES) {
- return NULL;
+ return nullptr;
}
return &LAYERTYPEINFO[type];
@@ -2013,7 +2051,7 @@ static const LayerTypeInfo *layerType_getInfo(int type)
static const char *layerType_getName(int type)
{
if (type < 0 || type >= CD_NUMTYPES) {
- return NULL;
+ return nullptr;
}
return LAYERTYPENAMES[type];
@@ -2147,7 +2185,7 @@ bool CustomData_merge(const struct CustomData *source,
data = layer->data;
break;
default:
- data = NULL;
+ data = nullptr;
break;
}
@@ -2169,7 +2207,7 @@ bool CustomData_merge(const struct CustomData *source,
newlayer->flag |= flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY);
changed = true;
- if (layer->anonymous_id != NULL) {
+ if (layer->anonymous_id != nullptr) {
BKE_anonymous_attribute_id_increment_weak(layer->anonymous_id);
newlayer->anonymous_id = layer->anonymous_id;
}
@@ -2202,7 +2240,7 @@ void CustomData_copy(const struct CustomData *source,
CustomData_reset(dest);
if (source->external) {
- dest->external = MEM_dupallocN(source->external);
+ dest->external = static_cast<CustomDataExternal *>(MEM_dupallocN(source->external));
}
CustomData_merge(source, dest, mask, alloctype, totelem);
@@ -2212,9 +2250,9 @@ static void customData_free_layer__internal(CustomDataLayer *layer, int totelem)
{
const LayerTypeInfo *typeInfo;
- if (layer->anonymous_id != NULL) {
+ if (layer->anonymous_id != nullptr) {
BKE_anonymous_attribute_id_decrement_weak(layer->anonymous_id);
- layer->anonymous_id = NULL;
+ layer->anonymous_id = nullptr;
}
if (!(layer->flag & CD_FLAG_NOFREE) && layer->data) {
typeInfo = layerType_getInfo(layer->type);
@@ -2233,7 +2271,7 @@ static void CustomData_external_free(CustomData *data)
{
if (data->external) {
MEM_freeN(data->external);
- data->external = NULL;
+ data->external = nullptr;
}
}
@@ -2506,8 +2544,8 @@ void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag)
static bool customData_resize(CustomData *data, int amount)
{
- CustomDataLayer *tmp = MEM_calloc_arrayN(
- (data->maxlayer + amount), sizeof(*tmp), "CustomData->layers");
+ CustomDataLayer *tmp = static_cast<CustomDataLayer *>(
+ MEM_calloc_arrayN((data->maxlayer + amount), sizeof(*tmp), __func__));
if (!tmp) {
return false;
}
@@ -2531,7 +2569,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
int flag = 0, index = data->totlayer;
- void *newlayerdata = NULL;
+ void *newlayerdata = nullptr;
/* Passing a layer-data to copy from with an alloctype that won't copy is
* most likely a bug */
@@ -2553,7 +2591,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
}
if (!newlayerdata) {
- return NULL;
+ return nullptr;
}
}
@@ -2581,7 +2619,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
if (newlayerdata != layerdata) {
MEM_freeN(newlayerdata);
}
- return NULL;
+ return nullptr;
}
}
@@ -2647,7 +2685,7 @@ void *CustomData_add_layer(
return layer->data;
}
- return NULL;
+ return nullptr;
}
void *CustomData_add_layer_named(CustomData *data,
@@ -2665,7 +2703,7 @@ void *CustomData_add_layer_named(CustomData *data,
return layer->data;
}
- return NULL;
+ return nullptr;
}
void *CustomData_add_layer_anonymous(struct CustomData *data,
@@ -2680,8 +2718,8 @@ void *CustomData_add_layer_anonymous(struct CustomData *data,
data, type, alloctype, layerdata, totelem, name);
CustomData_update_typemap(data);
- if (layer == NULL) {
- return NULL;
+ if (layer == nullptr) {
+ return nullptr;
}
BKE_anonymous_attribute_id_increment_weak(anonymous_id);
@@ -2794,7 +2832,7 @@ static void *customData_duplicate_referenced_layer_index(CustomData *data,
const int totelem)
{
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
CustomDataLayer *layer = &data->layers[layer_index];
@@ -2863,7 +2901,7 @@ void *CustomData_duplicate_referenced_layer_anonymous(CustomData *data,
}
}
BLI_assert_unreachable();
- return NULL;
+ return nullptr;
}
void CustomData_duplicate_referenced_layers(CustomData *data, int totelem)
@@ -2959,7 +2997,7 @@ void CustomData_copy_data_layer(const CustomData *source,
const size_t dst_offset = (size_t)dst_index * typeInfo->size;
if (!count || !src_data || !dst_data) {
- if (count && !(src_data == NULL && dst_data == NULL)) {
+ if (count && !(src_data == nullptr && dst_data == nullptr)) {
CLOG_WARN(&LOG,
"null data for %s type (%p --> %p), skipping",
layerType_getName(source->layers[src_layer_index].type),
@@ -3086,15 +3124,16 @@ void CustomData_interp(const CustomData *source,
/* Slow fallback in case we're interpolating a ridiculous number of elements. */
if (count > SOURCE_BUF_SIZE) {
- sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__);
+ sources = static_cast<const void **>(MEM_malloc_arrayN(count, sizeof(*sources), __func__));
}
/* If no weights are given, generate default ones to produce an average result. */
float default_weights_buf[SOURCE_BUF_SIZE];
- float *default_weights = NULL;
- if (weights == NULL) {
+ float *default_weights = nullptr;
+ if (weights == nullptr) {
default_weights = (count > SOURCE_BUF_SIZE) ?
- MEM_mallocN(sizeof(*weights) * (size_t)count, __func__) :
+ static_cast<float *>(
+ MEM_mallocN(sizeof(*weights) * (size_t)count, __func__)) :
default_weights_buf;
copy_vn_fl(default_weights, count, 1.0f / count);
weights = default_weights;
@@ -3146,7 +3185,7 @@ void CustomData_interp(const CustomData *source,
if (count > SOURCE_BUF_SIZE) {
MEM_freeN((void *)sources);
}
- if (!ELEM(default_weights, NULL, default_weights_buf)) {
+ if (!ELEM(default_weights, nullptr, default_weights_buf)) {
MEM_freeN(default_weights);
}
}
@@ -3198,7 +3237,7 @@ void *CustomData_get(const CustomData *data, int index, int type)
/* get the layer index of the active layer of type */
int layer_index = CustomData_get_active_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
/* get the offset of the desired element */
@@ -3214,7 +3253,7 @@ void *CustomData_get_n(const CustomData *data, int type, int index, int n)
/* get the layer index of the first layer of type */
int layer_index = data->typemap[type];
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
const size_t offset = (size_t)index * layerType_getInfo(type)->size;
@@ -3226,7 +3265,7 @@ void *CustomData_get_layer(const CustomData *data, int type)
/* get the layer index of the active layer of type */
int layer_index = CustomData_get_active_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return data->layers[layer_index].data;
@@ -3237,7 +3276,7 @@ void *CustomData_get_layer_n(const CustomData *data, int type, int n)
/* get the layer index of the active layer of type */
int layer_index = CustomData_get_layer_index_n(data, type, n);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return data->layers[layer_index].data;
@@ -3247,7 +3286,7 @@ void *CustomData_get_layer_named(const struct CustomData *data, int type, const
{
int layer_index = CustomData_get_named_layer_index(data, type, name);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return data->layers[layer_index].data;
@@ -3293,7 +3332,7 @@ const char *CustomData_get_layer_name(const CustomData *data, int type, int n)
{
const int layer_index = CustomData_get_layer_index_n(data, type, n);
- return (layer_index == -1) ? NULL : data->layers[layer_index].name;
+ return (layer_index == -1) ? nullptr : data->layers[layer_index].name;
}
void *CustomData_set_layer(const CustomData *data, int type, void *ptr)
@@ -3302,7 +3341,7 @@ void *CustomData_set_layer(const CustomData *data, int type, void *ptr)
int layer_index = CustomData_get_active_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
data->layers[layer_index].data = ptr;
@@ -3315,7 +3354,7 @@ void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, voi
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_layer_index_n(data, type, n);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
data->layers[layer_index].data = ptr;
@@ -3347,19 +3386,19 @@ void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop)
for (int i = 0; i < fdata->totlayer; i++) {
if (fdata->layers[i].type == CD_MTFACE) {
CustomData_add_layer_named(
- ldata, CD_MLOOPUV, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ ldata, CD_MLOOPUV, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
}
else if (fdata->layers[i].type == CD_MCOL) {
CustomData_add_layer_named(
- ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ ldata, CD_MLOOPCOL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
}
else if (fdata->layers[i].type == CD_MDISPS) {
CustomData_add_layer_named(
- ldata, CD_MDISPS, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ ldata, CD_MDISPS, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
}
else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) {
CustomData_add_layer_named(
- ldata, CD_NORMAL, CD_CALLOC, NULL, totloop, fdata->layers[i].name);
+ ldata, CD_NORMAL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name);
}
}
}
@@ -3371,25 +3410,27 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *ldata, int total)
for (int i = 0; i < ldata->totlayer; i++) {
if (ldata->layers[i].type == CD_MLOOPUV) {
- CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ CustomData_add_layer_named(
+ fdata, CD_MTFACE, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
if (ldata->layers[i].type == CD_MLOOPCOL) {
- CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_PREVIEW_MLOOPCOL) {
CustomData_add_layer_named(
- fdata, CD_PREVIEW_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ fdata, CD_PREVIEW_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) {
CustomData_add_layer_named(
- fdata, CD_ORIGSPACE, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ fdata, CD_ORIGSPACE, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_NORMAL) {
CustomData_add_layer_named(
- fdata, CD_TESSLOOPNORMAL, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ fdata, CD_TESSLOOPNORMAL, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
else if (ldata->layers[i].type == CD_TANGENT) {
- CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, total, ldata->layers[i].name);
+ CustomData_add_layer_named(
+ fdata, CD_TANGENT, CD_CALLOC, nullptr, total, ldata->layers[i].name);
}
}
@@ -3502,7 +3543,7 @@ void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
int chunksize;
/* Dispose old pools before calling here to avoid leaks */
- BLI_assert(data->pool == NULL);
+ BLI_assert(data->pool == nullptr);
switch (htype) {
case BM_VERT:
@@ -3545,7 +3586,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
* the new allocation */
CustomData destold = *dest;
if (destold.layers) {
- destold.layers = MEM_dupallocN(destold.layers);
+ destold.layers = static_cast<CustomDataLayer *>(MEM_dupallocN(destold.layers));
}
if (CustomData_merge(source, dest, mask, alloctype, 0) == false) {
@@ -3581,7 +3622,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
break;
}
- dest->pool = NULL;
+ dest->pool = nullptr;
CustomData_bmesh_init_pool(dest, totelem, htype);
if (iter_type != BM_LOOPS_OF_FACE) {
@@ -3589,7 +3630,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
BMIter iter;
/* Ensure all current elements follow new customdata layout. */
BM_ITER_MESH (h, &iter, bm, iter_type) {
- void *tmp = NULL;
+ void *tmp = nullptr;
CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp);
CustomData_bmesh_free_block(&destold, &h->data);
h->data = tmp;
@@ -3604,7 +3645,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
/* Ensure all current elements follow new customdata layout. */
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- void *tmp = NULL;
+ void *tmp = nullptr;
CustomData_bmesh_copy_data(&destold, dest, l->head.data, &tmp);
CustomData_bmesh_free_block(&destold, &l->head.data);
l->head.data = tmp;
@@ -3623,7 +3664,7 @@ bool CustomData_bmesh_merge(const CustomData *source,
void CustomData_bmesh_free_block(CustomData *data, void **block)
{
- if (*block == NULL) {
+ if (*block == nullptr) {
return;
}
@@ -3642,12 +3683,12 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
BLI_mempool_free(data->pool, *block);
}
- *block = NULL;
+ *block = nullptr;
}
void CustomData_bmesh_free_block_data(CustomData *data, void *block)
{
- if (block == NULL) {
+ if (block == nullptr) {
return;
}
for (int i = 0; i < data->totlayer; i++) {
@@ -3674,7 +3715,7 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
*block = BLI_mempool_alloc(data->pool);
}
else {
- *block = NULL;
+ *block = nullptr;
}
}
@@ -3682,7 +3723,7 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
void *block,
const CustomDataMask mask_exclude)
{
- if (block == NULL) {
+ if (block == nullptr) {
return;
}
for (int i = 0; i < data->totlayer; i++) {
@@ -3714,7 +3755,7 @@ static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n
void CustomData_bmesh_set_default(CustomData *data, void **block)
{
- if (*block == NULL) {
+ if (*block == nullptr) {
CustomData_bmesh_alloc_block(data, block);
}
@@ -3733,7 +3774,7 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source,
* would cause too much duplicate code, so add a check instead. */
const bool no_mask = (mask_exclude == 0);
- if (*dest_block == NULL) {
+ if (*dest_block == nullptr) {
CustomData_bmesh_alloc_block(dest, dest_block);
if (*dest_block) {
memset(*dest_block, 0, dest->totsize);
@@ -3799,7 +3840,7 @@ void *CustomData_bmesh_get(const CustomData *data, void *block, int type)
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_active_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return POINTER_OFFSET(block, data->layers[layer_index].offset);
@@ -3810,7 +3851,7 @@ void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int
/* get the layer index of the first layer of type */
int layer_index = CustomData_get_layer_index(data, type);
if (layer_index == -1) {
- return NULL;
+ return nullptr;
}
return POINTER_OFFSET(block, data->layers[layer_index + n].offset);
@@ -3819,7 +3860,7 @@ void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int
void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
{
if (n < 0 || n >= data->totlayer) {
- return NULL;
+ return nullptr;
}
return POINTER_OFFSET(block, data->layers[n].offset);
@@ -4035,7 +4076,7 @@ void CustomData_bmesh_interp_n(CustomData *data,
void *dst_block_ofs,
int n)
{
- BLI_assert(weights != NULL);
+ BLI_assert(weights != nullptr);
BLI_assert(count > 0);
CustomDataLayer *layer = &data->layers[n];
@@ -4060,15 +4101,15 @@ void CustomData_bmesh_interp(CustomData *data,
/* Slow fallback in case we're interpolating a ridiculous number of elements. */
if (count > SOURCE_BUF_SIZE) {
- sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__);
+ sources = (const void **)MEM_malloc_arrayN(count, sizeof(*sources), __func__);
}
/* If no weights are given, generate default ones to produce an average result. */
float default_weights_buf[SOURCE_BUF_SIZE];
- float *default_weights = NULL;
- if (weights == NULL) {
+ float *default_weights = nullptr;
+ if (weights == nullptr) {
default_weights = (count > SOURCE_BUF_SIZE) ?
- MEM_mallocN(sizeof(*weights) * (size_t)count, __func__) :
+ (float *)MEM_mallocN(sizeof(*weights) * (size_t)count, __func__) :
default_weights_buf;
copy_vn_fl(default_weights, count, 1.0f / count);
weights = default_weights;
@@ -4090,7 +4131,7 @@ void CustomData_bmesh_interp(CustomData *data,
if (count > SOURCE_BUF_SIZE) {
MEM_freeN((void *)sources);
}
- if (!ELEM(default_weights, NULL, default_weights_buf)) {
+ if (!ELEM(default_weights, nullptr, default_weights_buf)) {
MEM_freeN(default_weights);
}
}
@@ -4101,7 +4142,7 @@ void CustomData_to_bmesh_block(const CustomData *source,
void **dest_block,
bool use_default_init)
{
- if (*dest_block == NULL) {
+ if (*dest_block == nullptr) {
CustomData_bmesh_alloc_block(dest, dest_block);
}
@@ -4223,22 +4264,22 @@ void CustomData_blend_write_prepare(CustomData *data,
for (i = 0, j = 0; i < totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
/* Layers with this flag set are not written to file. */
- if ((layer->flag & CD_FLAG_NOCOPY) || layer->anonymous_id != NULL) {
+ if ((layer->flag & CD_FLAG_NOCOPY) || layer->anonymous_id != nullptr) {
data->totlayer--;
// CLOG_WARN(&LOG, "skipping layer %p (%s)", layer, layer->name);
}
else {
if (UNLIKELY((size_t)j >= write_layers_size)) {
if (write_layers == write_layers_buff) {
- write_layers = MEM_malloc_arrayN(
+ write_layers = (CustomDataLayer *)MEM_malloc_arrayN(
(write_layers_size + chunk_size), sizeof(*write_layers), __func__);
if (write_layers_buff) {
memcpy(write_layers, write_layers_buff, sizeof(*write_layers) * write_layers_size);
}
}
else {
- write_layers = MEM_reallocN(write_layers,
- sizeof(*write_layers) * (write_layers_size + chunk_size));
+ write_layers = (CustomDataLayer *)MEM_reallocN(
+ write_layers, sizeof(*write_layers) * (write_layers_size + chunk_size));
}
write_layers_size += chunk_size;
}
@@ -4265,14 +4306,14 @@ const char *CustomData_layertype_name(int type)
bool CustomData_layertype_is_singleton(int type)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- return typeInfo->defaultname == NULL;
+ return typeInfo->defaultname == nullptr;
}
bool CustomData_layertype_is_dynamic(int type)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
- return (typeInfo->free != NULL);
+ return (typeInfo->free != nullptr);
}
int CustomData_layertype_layers_max(const int type)
@@ -4280,10 +4321,10 @@ int CustomData_layertype_layers_max(const int type)
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
/* Same test as for singleton above. */
- if (typeInfo->defaultname == NULL) {
+ if (typeInfo->defaultname == nullptr) {
return 1;
}
- if (typeInfo->layers_max == NULL) {
+ if (typeInfo->layers_max == nullptr) {
return -1;
}
@@ -4313,13 +4354,15 @@ static bool cd_layer_find_dupe(CustomData *data, const char *name, int type, int
return false;
}
+struct CustomDataUniqueCheckData {
+ CustomData *data;
+ int type;
+ int index;
+};
+
static bool customdata_unique_check(void *arg, const char *name)
{
- struct {
- CustomData *data;
- int type;
- int index;
- } *data_arg = arg;
+ CustomDataUniqueCheckData *data_arg = static_cast<CustomDataUniqueCheckData *>(arg);
return cd_layer_find_dupe(data_arg->data, name, data_arg->type, data_arg->index);
}
@@ -4328,14 +4371,7 @@ void CustomData_set_layer_unique_name(CustomData *data, int index)
CustomDataLayer *nlayer = &data->layers[index];
const LayerTypeInfo *typeInfo = layerType_getInfo(nlayer->type);
- struct {
- CustomData *data;
- int type;
- int index;
- } data_arg;
- data_arg.data = data;
- data_arg.type = nlayer->type;
- data_arg.index = index;
+ CustomDataUniqueCheckData data_arg{data, nlayer->type, index};
if (!typeInfo->defaultname) {
return;
@@ -4348,7 +4384,7 @@ void CustomData_set_layer_unique_name(CustomData *data, int index)
}
BLI_uniquename_cb(
- customdata_unique_check, &data_arg, NULL, '.', nlayer->name, sizeof(nlayer->name));
+ customdata_unique_check, &data_arg, nullptr, '.', nlayer->name, sizeof(nlayer->name));
}
void CustomData_validate_layer_name(const CustomData *data,
@@ -4420,7 +4456,7 @@ bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, cons
{
const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
- if (typeInfo->validate != NULL) {
+ if (typeInfo->validate != nullptr) {
return typeInfo->validate(layer->data, totitems, do_fixes);
}
@@ -4672,7 +4708,7 @@ void CustomData_external_add(
}
if (!external) {
- external = MEM_callocN(sizeof(CustomDataExternal), "CustomDataExternal");
+ external = MEM_cnew<CustomDataExternal>(__func__);
data->external = external;
}
BLI_strncpy(external->filename, filename, sizeof(external->filename));
@@ -4771,7 +4807,7 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
const int count,
const float mix_factor)
{
- BLI_assert(weights != NULL);
+ BLI_assert(weights != nullptr);
BLI_assert(count > 0);
/* Fake interpolation, we actually copy highest weighted source to dest.
@@ -4786,8 +4822,8 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
size_t data_size;
const uint64_t data_flag = laymap->data_flag;
- cd_interp interp_cd = NULL;
- cd_copy copy_cd = NULL;
+ cd_interp interp_cd = nullptr;
+ cd_copy copy_cd = nullptr;
if (!sources) {
/* Not supported here, abort. */
@@ -4841,7 +4877,7 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye
BLI_assert(best_src_idx >= 0);
if (interp_cd) {
- interp_cd(sources, weights, NULL, count, tmp_dst);
+ interp_cd(sources, weights, nullptr, count, tmp_dst);
}
else if (data_flag) {
copy_bit_flag(tmp_dst, sources[best_src_idx], data_size, data_flag);
@@ -4886,13 +4922,13 @@ void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLaye
const int count,
const float mix_factor)
{
- BLI_assert(weights != NULL);
+ BLI_assert(weights != nullptr);
BLI_assert(count > 0);
const int data_type = laymap->data_type;
const int mix_mode = laymap->mix_mode;
- SpaceTransform *space_transform = laymap->interp_data;
+ SpaceTransform *space_transform = static_cast<SpaceTransform *>(laymap->interp_data);
const LayerTypeInfo *type_info = layerType_getInfo(data_type);
cd_interp interp_cd = type_info->interp;
@@ -4906,7 +4942,7 @@ void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLaye
return;
}
- interp_cd(sources, weights, NULL, count, tmp_dst);
+ interp_cd(sources, weights, nullptr, count, tmp_dst);
if (space_transform) {
/* tmp_dst is in source space so far, bring it back in destination space. */
BLI_space_transform_invert_normal(space_transform, tmp_dst);
@@ -4929,18 +4965,19 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap,
size_t data_size;
size_t data_offset;
- cd_datatransfer_interp interp = NULL;
+ cd_datatransfer_interp interp = nullptr;
size_t tmp_buff_size = 32;
- const void **tmp_data_src = NULL;
+ const void **tmp_data_src = nullptr;
- /* NOTE: NULL data_src may happen and be valid (see vgroups...). */
+ /* NOTE: null data_src may happen and be valid (see vgroups...). */
if (!data_dst) {
return;
}
if (data_src) {
- tmp_data_src = MEM_malloc_arrayN(tmp_buff_size, sizeof(*tmp_data_src), __func__);
+ tmp_data_src = (const void **)MEM_malloc_arrayN(
+ tmp_buff_size, sizeof(*tmp_data_src), __func__);
}
if (data_type & CD_FAKE) {
@@ -4972,7 +5009,8 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap,
if (tmp_data_src) {
if (UNLIKELY(sources_num > tmp_buff_size)) {
tmp_buff_size = (size_t)sources_num;
- tmp_data_src = MEM_reallocN((void *)tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size);
+ tmp_data_src = (const void **)MEM_reallocN((void *)tmp_data_src,
+ sizeof(*tmp_data_src) * tmp_buff_size);
}
for (int j = 0; j < sources_num; j++) {
@@ -5044,28 +5082,29 @@ void CustomData_blend_write(BlendWriter *writer,
if (layer->type == CD_MDEFORMVERT) {
/* layer types that allocate own memory need special handling */
- BKE_defvert_blend_write(writer, count, layer->data);
+ BKE_defvert_blend_write(writer, count, static_cast<struct MDeformVert *>(layer->data));
}
else if (layer->type == CD_MDISPS) {
- write_mdisps(writer, count, layer->data, layer->flag & CD_FLAG_EXTERNAL);
+ write_mdisps(
+ writer, count, static_cast<MDisps *>(layer->data), layer->flag & CD_FLAG_EXTERNAL);
}
else if (layer->type == CD_PAINT_MASK) {
- const float *layer_data = layer->data;
+ const float *layer_data = static_cast<const float *>(layer->data);
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else if (layer->type == CD_SCULPT_FACE_SETS) {
- const float *layer_data = layer->data;
+ const float *layer_data = static_cast<const float *>(layer->data);
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else if (layer->type == CD_GRID_PAINT_MASK) {
- write_grid_paint_mask(writer, count, layer->data);
+ write_grid_paint_mask(writer, count, static_cast<GridPaintMask *>(layer->data));
}
else if (layer->type == CD_FACEMAP) {
- const int *layer_data = layer->data;
+ const int *layer_data = static_cast<const int *>(layer->data);
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else if (layer->type == CD_PROP_BOOL) {
- const bool *layer_data = layer->data;
+ const bool *layer_data = static_cast<const bool *>(layer->data);
BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data);
}
else {
@@ -5138,7 +5177,7 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
/* Annoying workaround for bug T31079 loading legacy files with
* no polygons _but_ have stale custom-data. */
- if (UNLIKELY(count == 0 && data->layers == NULL && data->totlayer != 0)) {
+ if (UNLIKELY(count == 0 && data->layers == nullptr && data->totlayer != 0)) {
CustomData_reset(data);
return;
}
@@ -5157,7 +5196,7 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
if (CustomData_verify_versions(data, i)) {
BLO_read_data_address(reader, &layer->data);
- if (layer->data == NULL && count > 0 && layer->type == CD_PROP_BOOL) {
+ if (layer->data == nullptr && count > 0 && layer->type == CD_PROP_BOOL) {
/* Usually this should never happen, except when a custom data layer has not been written
* to a file correctly. */
CLOG_WARN(&LOG, "Reallocating custom data layer that was not saved correctly.");
@@ -5168,10 +5207,11 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
}
}
if (layer->type == CD_MDISPS) {
- blend_read_mdisps(reader, count, layer->data, layer->flag & CD_FLAG_EXTERNAL);
+ blend_read_mdisps(
+ reader, count, static_cast<MDisps *>(layer->data), layer->flag & CD_FLAG_EXTERNAL);
}
else if (layer->type == CD_GRID_PAINT_MASK) {
- blend_read_paint_mask(reader, count, layer->data);
+ blend_read_paint_mask(reader, count, static_cast<GridPaintMask *>(layer->data));
}
i++;
}
diff --git a/source/blender/blenkernel/intern/data_transfer_intern.h b/source/blender/blenkernel/intern/data_transfer_intern.h
index e40b4946f52..5510f699197 100644
--- a/source/blender/blenkernel/intern/data_transfer_intern.h
+++ b/source/blender/blenkernel/intern/data_transfer_intern.h
@@ -25,6 +25,10 @@
#include "BKE_customdata.h" /* For cd_datatransfer_interp */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct CustomData;
struct CustomDataTransferLayerMap;
struct ListBase;
@@ -78,3 +82,7 @@ void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLaye
const float *weights,
const int count,
const float mix_factor);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc
index edf043de63f..48bf24a0825 100644
--- a/source/blender/blenkernel/intern/displist.cc
+++ b/source/blender/blenkernel/intern/displist.cc
@@ -316,7 +316,7 @@ static void curve_to_displist(const Curve *cu,
* and resolution > 1. */
const bool use_cyclic_sample = is_cyclic && (samples_len != 2);
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
/* Add one to the length because of 'BKE_curve_forward_diff_bezier'. */
dl->verts = (float *)MEM_mallocN(sizeof(float[3]) * (samples_len + 1), __func__);
BLI_addtail(r_dispbase, dl);
@@ -371,7 +371,7 @@ static void curve_to_displist(const Curve *cu,
}
else if (nu->type == CU_NURBS) {
const int len = (resolution * SEGMENTSU(nu));
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__);
BLI_addtail(r_dispbase, dl);
dl->parts = 1;
@@ -384,7 +384,7 @@ static void curve_to_displist(const Curve *cu,
}
else if (nu->type == CU_POLY) {
const int len = nu->pntsu;
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__);
BLI_addtail(r_dispbase, dl);
dl->parts = 1;
@@ -475,7 +475,7 @@ void BKE_displist_fill(const ListBase *dispbase,
const int triangles_len = BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal_proj);
if (totvert != 0 && triangles_len != 0) {
- DispList *dlnew = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dlnew = MEM_cnew<DispList>(__func__);
dlnew->type = DL_INDEX3;
dlnew->flag = (dl_flag_accum & (DL_BACK_CURVE | DL_FRONT_CURVE));
dlnew->rt = (dl_rt_accum & CU_SMOOTH);
@@ -530,7 +530,7 @@ static void bevels_to_filledpoly(const Curve *cu, ListBase *dispbase)
if (dl->type == DL_SURF) {
if ((dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U) == 0) {
if ((cu->flag & CU_BACK) && (dl->flag & DL_BACK_CURVE)) {
- DispList *dlnew = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dlnew = MEM_cnew<DispList>(__func__);
BLI_addtail(&front, dlnew);
dlnew->verts = (float *)MEM_mallocN(sizeof(float[3]) * dl->parts, __func__);
dlnew->nr = dl->parts;
@@ -549,7 +549,7 @@ static void bevels_to_filledpoly(const Curve *cu, ListBase *dispbase)
}
}
if ((cu->flag & CU_FRONT) && (dl->flag & DL_FRONT_CURVE)) {
- DispList *dlnew = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dlnew = MEM_cnew<DispList>(__func__);
BLI_addtail(&back, dlnew);
dlnew->verts = (float *)MEM_mallocN(sizeof(float[3]) * dl->parts, __func__);
dlnew->nr = dl->parts;
@@ -665,7 +665,7 @@ void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob)
BKE_displist_free(&(ob->runtime.curve_cache->disp));
}
else {
- ob->runtime.curve_cache = (CurveCache *)MEM_callocN(sizeof(CurveCache), __func__);
+ ob->runtime.curve_cache = MEM_cnew<CurveCache>(__func__);
}
BKE_mball_polygonize(depsgraph, scene, ob, &ob->runtime.curve_cache->disp);
@@ -996,7 +996,7 @@ static void evaluate_surface_object(Depsgraph *depsgraph,
if (nu->pntsv == 1) {
const int len = SEGMENTSU(nu) * resolu;
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__);
BLI_addtail(r_dispbase, dl);
@@ -1019,7 +1019,7 @@ static void evaluate_surface_object(Depsgraph *depsgraph,
else {
const int len = (nu->pntsu * resolu) * (nu->pntsv * resolv);
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__);
BLI_addtail(r_dispbase, dl);
@@ -1122,7 +1122,7 @@ static void fillBevelCap(const Nurb *nu,
const float *prev_fp,
ListBase *dispbase)
{
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = (float *)MEM_mallocN(sizeof(float[3]) * dlb->nr, __func__);
memcpy(dl->verts, prev_fp, sizeof(float[3]) * dlb->nr);
@@ -1321,7 +1321,7 @@ static GeometrySet evaluate_curve_type_object(Depsgraph *depsgraph,
/* exception handling; curve without bevel or extrude, with width correction */
if (BLI_listbase_is_empty(&dlbev)) {
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), "makeDispListbev");
+ DispList *dl = MEM_cnew<DispList>("makeDispListbev");
dl->verts = (float *)MEM_mallocN(sizeof(float[3]) * bl->nr, "dlverts");
BLI_addtail(r_dispbase, dl);
@@ -1371,7 +1371,7 @@ static GeometrySet evaluate_curve_type_object(Depsgraph *depsgraph,
LISTBASE_FOREACH (DispList *, dlb, &dlbev) {
/* for each part of the bevel use a separate displblock */
- DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__);
+ DispList *dl = MEM_cnew<DispList>(__func__);
dl->verts = data = (float *)MEM_mallocN(sizeof(float[3]) * dlb->nr * steps, __func__);
BLI_addtail(r_dispbase, dl);
@@ -1495,7 +1495,7 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph,
BKE_object_free_derived_caches(ob);
cow_curve.curve_eval = nullptr;
- ob->runtime.curve_cache = (CurveCache *)MEM_callocN(sizeof(CurveCache), __func__);
+ ob->runtime.curve_cache = MEM_cnew<CurveCache>(__func__);
ListBase *dispbase = &ob->runtime.curve_cache->disp;
if (ob->type == OB_SURF) {
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 5bbfc0913a1..f7a547543af 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -412,7 +412,7 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
char *path = NULL;
if (!adt && C) {
- path = BKE_animdata_driver_path_hack(C, &tptr, prop, NULL);
+ path = RNA_path_from_ID_to_property(&tptr, prop);
adt = BKE_animdata_from_id(tptr.owner_id);
step--;
}
@@ -463,7 +463,7 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C,
}
if (step) {
- char *tpath = BKE_animdata_driver_path_hack(C, &tptr, prop, path);
+ char *tpath = path ? path : RNA_path_from_ID_to_property(&tptr, prop);
if (tpath && tpath != path) {
MEM_freeN(path);
path = tpath;
diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c
index 5496519e53b..ce30f80ba65 100644
--- a/source/blender/blenkernel/intern/fcurve_driver.c
+++ b/source/blender/blenkernel/intern/fcurve_driver.c
@@ -29,6 +29,7 @@
#include "BLI_alloca.h"
#include "BLI_expr_pylike_eval.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string_utils.h"
#include "BLI_threads.h"
@@ -864,6 +865,12 @@ void driver_variable_name_validate(DriverVar *dvar)
}
}
+void driver_variable_unique_name(DriverVar *dvar)
+{
+ ListBase variables = BLI_listbase_from_link((Link *)dvar);
+ BLI_uniquename(&variables, dvar, dvar->name, '_', offsetof(DriverVar, name), sizeof(dvar->name));
+}
+
DriverVar *driver_add_new_variable(ChannelDriver *driver)
{
DriverVar *dvar;
diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc
index 93a7646fed0..b411c793298 100644
--- a/source/blender/blenkernel/intern/geometry_component_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_component_instances.cc
@@ -17,6 +17,7 @@
#include <mutex>
#include "BLI_float4x4.hh"
+#include "BLI_index_mask.hh"
#include "BLI_map.hh"
#include "BLI_rand.hh"
#include "BLI_set.hh"
@@ -26,6 +27,8 @@
#include "DNA_collection_types.h"
+#include "BKE_attribute_access.hh"
+#include "BKE_attribute_math.hh"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
@@ -34,6 +37,7 @@
#include "FN_cpp_type_make.hh"
using blender::float4x4;
+using blender::IndexMask;
using blender::Map;
using blender::MutableSpan;
using blender::Set;
@@ -132,6 +136,62 @@ blender::Span<InstanceReference> InstancesComponent::references() const
return references_;
}
+template<typename T>
+static void copy_data_based_on_mask(Span<T> src, MutableSpan<T> dst, IndexMask mask)
+{
+ BLI_assert(src.data() != dst.data());
+ using namespace blender;
+ threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ dst[i] = src[mask[i]];
+ }
+ });
+}
+
+void InstancesComponent::remove_instances(const IndexMask mask)
+{
+ using namespace blender;
+ if (mask.is_range() && mask.as_range().start() == 0) {
+ /* Deleting from the end of the array can be much faster since no data has to be shifted. */
+ this->resize(mask.size());
+ this->remove_unused_references();
+ return;
+ }
+
+ Vector<int> new_handles(mask.size());
+ copy_data_based_on_mask<int>(this->instance_reference_handles(), new_handles, mask);
+ instance_reference_handles_ = std::move(new_handles);
+ Vector<float4x4> new_transforms(mask.size());
+ copy_data_based_on_mask<float4x4>(this->instance_transforms(), new_transforms, mask);
+ instance_transforms_ = std::move(new_transforms);
+
+ const bke::CustomDataAttributes &src_attributes = attributes_;
+
+ bke::CustomDataAttributes dst_attributes;
+ dst_attributes.reallocate(mask.size());
+
+ src_attributes.foreach_attribute(
+ [&](const bke::AttributeIDRef &id, const AttributeMetaData &meta_data) {
+ if (!id.should_be_kept()) {
+ return true;
+ }
+
+ 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);
+
+ attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_data_based_on_mask<T>(src.typed<T>(), dst.typed<T>(), mask);
+ });
+ return true;
+ },
+ ATTR_DOMAIN_INSTANCE);
+
+ attributes_ = std::move(dst_attributes);
+ this->remove_unused_references();
+}
+
void InstancesComponent::remove_unused_references()
{
using namespace blender;
diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc
index ef5609ec9a8..06e0e78745b 100644
--- a/source/blender/blenkernel/intern/geometry_set.cc
+++ b/source/blender/blenkernel/intern/geometry_set.cc
@@ -183,25 +183,27 @@ Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const
return components;
}
-void GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const
+bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const
{
+ bool have_minmax = false;
const PointCloud *pointcloud = this->get_pointcloud_for_read();
if (pointcloud != nullptr) {
- BKE_pointcloud_minmax(pointcloud, *r_min, *r_max);
+ have_minmax |= BKE_pointcloud_minmax(pointcloud, *r_min, *r_max);
}
const Mesh *mesh = this->get_mesh_for_read();
if (mesh != nullptr) {
- BKE_mesh_wrapper_minmax(mesh, *r_min, *r_max);
+ have_minmax |= BKE_mesh_wrapper_minmax(mesh, *r_min, *r_max);
}
const Volume *volume = this->get_volume_for_read();
if (volume != nullptr) {
- BKE_volume_min_max(volume, *r_min, *r_max);
+ have_minmax |= BKE_volume_min_max(volume, *r_min, *r_max);
}
const CurveEval *curve = this->get_curve_for_read();
if (curve != nullptr) {
/* Using the evaluated positions is somewhat arbitrary, but it is probably expected. */
- curve->bounds_min_max(*r_min, *r_max, true);
+ have_minmax |= curve->bounds_min_max(*r_min, *r_max, true);
}
+ return have_minmax;
}
std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index 4d84d5d899d..42d2211c360 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -69,9 +69,18 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object)
}
/* Otherwise, construct a new geometry set with the component based on the object type. */
- GeometrySet geometry_set;
if (object.type == OB_MESH) {
+ GeometrySet geometry_set;
add_final_mesh_as_geometry_component(object, geometry_set);
+ return geometry_set;
+ }
+ if (object.type == OB_EMPTY && object.instance_collection != nullptr) {
+ GeometrySet geometry_set;
+ Collection &collection = *object.instance_collection;
+ InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ const int handle = instances.add_reference(collection);
+ instances.add_instance(handle, float4x4::identity());
+ return geometry_set;
}
/* TODO: Cover the case of point clouds without modifiers-- they may not be covered by the
@@ -80,7 +89,7 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object)
/* TODO: Add volume support. */
/* Return by value since there is not always an existing geometry set owned elsewhere to use. */
- return geometry_set;
+ return {};
}
static void geometry_set_collect_recursive_collection_instance(
@@ -98,13 +107,6 @@ static void geometry_set_collect_recursive_object(const Object &object,
{
GeometrySet instance_geometry_set = object_get_evaluated_geometry_set(object);
geometry_set_collect_recursive(instance_geometry_set, transform, r_sets);
-
- if (object.type == OB_EMPTY) {
- const Collection *collection_instance = object.instance_collection;
- if (collection_instance != nullptr) {
- geometry_set_collect_recursive_collection_instance(*collection_instance, transform, r_sets);
- }
- }
}
static void geometry_set_collect_recursive_collection(const Collection &collection,
diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc
index b5190f598c6..f8681647a77 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.cc
+++ b/source/blender/blenkernel/intern/gpencil_geom.cc
@@ -145,7 +145,7 @@ void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps)
static void boundbox_gpencil(Object *ob)
{
if (ob->runtime.bb == nullptr) {
- ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
+ ob->runtime.bb = MEM_cnew<BoundBox>("GPencil boundbox");
}
BoundBox *bb = ob->runtime.bb;
@@ -182,7 +182,7 @@ BoundBox *BKE_gpencil_boundbox_get(Object *ob)
* to keep both values synchronized. */
if (!ELEM(ob_orig, nullptr, ob)) {
if (ob_orig->runtime.bb == nullptr) {
- ob_orig->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
+ ob_orig->runtime.bb = MEM_cnew<BoundBox>("GPencil boundbox");
}
for (int i = 0; i < 8; i++) {
copy_v3_v3(ob_orig->runtime.bb->vec[i], ob->runtime.bb->vec[i]);
@@ -364,7 +364,7 @@ static void stroke_defvert_create_nr_list(MDeformVert *dv_list,
}
}
if (!found) {
- ld = (LinkData *)MEM_callocN(sizeof(LinkData), "def_nr_item");
+ ld = MEM_cnew<LinkData>("def_nr_item");
ld->data = POINTER_FROM_INT(dw->def_nr);
BLI_addtail(result, ld);
tw++;
@@ -3482,7 +3482,7 @@ struct tSampleEdge {
/* Helper: creates a tSamplePoint from a bGPDspoint and (optionally) a MDeformVert. */
static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const MDeformVert *dvert)
{
- tSamplePoint *new_pt = (tSamplePoint *)MEM_callocN(sizeof(tSamplePoint), __func__);
+ tSamplePoint *new_pt = MEM_cnew<tSamplePoint>(__func__);
copy_v3_v3(&new_pt->x, &pt->x);
new_pt->pressure = pt->pressure;
new_pt->strength = pt->strength;
@@ -3505,7 +3505,7 @@ static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const
* the edge. */
static tSampleEdge *new_sample_edge_from_sample_points(tSamplePoint *from, tSamplePoint *to)
{
- tSampleEdge *new_edge = (tSampleEdge *)MEM_callocN(sizeof(tSampleEdge), __func__);
+ tSampleEdge *new_edge = MEM_cnew<tSampleEdge>(__func__);
new_edge->from = from;
new_edge->to = to;
new_edge->length_sq = len_squared_v3v3(&from->x, &to->x);
@@ -3561,7 +3561,7 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd,
tSamplePoint *sp_next = se->to;
/* Subdivide the edge. */
- tSamplePoint *new_sp = (tSamplePoint *)MEM_callocN(sizeof(tSamplePoint), __func__);
+ tSamplePoint *new_sp = MEM_cnew<tSamplePoint>(__func__);
interp_v3_v3v3(&new_sp->x, &sp->x, &sp_next->x, 0.5f);
new_sp->pressure = interpf(sp->pressure, sp_next->pressure, 0.5f);
new_sp->strength = interpf(sp->strength, sp_next->strength, 0.5f);
@@ -3687,7 +3687,7 @@ struct tPerimeterPoint {
static tPerimeterPoint *new_perimeter_point(const float pt[3])
{
- tPerimeterPoint *new_pt = (tPerimeterPoint *)MEM_callocN(sizeof(tPerimeterPoint), __func__);
+ tPerimeterPoint *new_pt = MEM_cnew<tPerimeterPoint>(__func__);
copy_v3_v3(&new_pt->x, pt);
return new_pt;
}
@@ -3856,8 +3856,8 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd,
float defaultpixsize = 1000.0f / gpd->pixfactor;
float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize) / 2.0f;
- ListBase *perimeter_right_side = (ListBase *)MEM_callocN(sizeof(ListBase), __func__);
- ListBase *perimeter_left_side = (ListBase *)MEM_callocN(sizeof(ListBase), __func__);
+ ListBase *perimeter_right_side = MEM_cnew<ListBase>(__func__);
+ ListBase *perimeter_left_side = MEM_cnew<ListBase>(__func__);
int num_perimeter_points = 0;
bGPDspoint *first = &gps->points[0];
diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.cc
index f2a5146422e..c5b154c9a4b 100644
--- a/source/blender/blenkernel/intern/hair.c
+++ b/source/blender/blenkernel/intern/hair.cc
@@ -18,6 +18,9 @@
* \ingroup bke
*/
+#include <cmath>
+#include <cstring>
+
#include "MEM_guardedalloc.h"
#include "DNA_defaults.h"
@@ -25,8 +28,9 @@
#include "DNA_material_types.h"
#include "DNA_object_types.h"
+#include "BLI_float3.hh"
#include "BLI_listbase.h"
-#include "BLI_math.h"
+#include "BLI_math_base.h"
#include "BLI_rand.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -49,6 +53,8 @@
#include "BLO_read_write.h"
+using blender::float3;
+
static const char *HAIR_ATTR_POSITION = "position";
static const char *HAIR_ATTR_RADIUS = "radius";
@@ -67,10 +73,10 @@ static void hair_init_data(ID *id)
CustomData_reset(&hair->cdata);
CustomData_add_layer_named(
- &hair->pdata, CD_PROP_FLOAT3, CD_CALLOC, NULL, hair->totpoint, HAIR_ATTR_POSITION);
+ &hair->pdata, CD_PROP_FLOAT3, CD_CALLOC, nullptr, hair->totpoint, HAIR_ATTR_POSITION);
CustomData_add_layer_named(
- &hair->pdata, CD_PROP_FLOAT, CD_CALLOC, NULL, hair->totpoint, HAIR_ATTR_RADIUS);
- CustomData_add_layer(&hair->cdata, CD_HAIRCURVE, CD_CALLOC, NULL, hair->totcurve);
+ &hair->pdata, CD_PROP_FLOAT, CD_CALLOC, nullptr, hair->totpoint, HAIR_ATTR_RADIUS);
+ CustomData_add_layer(&hair->cdata, CD_HAIRCURVE, CD_CALLOC, nullptr, hair->totcurve);
BKE_hair_update_customdata_pointers(hair);
hair_random(hair);
@@ -80,14 +86,14 @@ static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, co
{
Hair *hair_dst = (Hair *)id_dst;
const Hair *hair_src = (const Hair *)id_src;
- hair_dst->mat = MEM_dupallocN(hair_src->mat);
+ hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat));
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
CustomData_copy(&hair_src->pdata, &hair_dst->pdata, CD_MASK_ALL, alloc_type, hair_dst->totpoint);
CustomData_copy(&hair_src->cdata, &hair_dst->cdata, CD_MASK_ALL, alloc_type, hair_dst->totcurve);
BKE_hair_update_customdata_pointers(hair_dst);
- hair_dst->batch_cache = NULL;
+ hair_dst->batch_cache = nullptr;
}
static void hair_free_data(ID *id)
@@ -115,8 +121,8 @@ static void hair_blend_write(BlendWriter *writer, ID *id, const void *id_address
{
Hair *hair = (Hair *)id;
- CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE];
- CustomDataLayer *clayers = NULL, clayers_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE];
+ CustomDataLayer *clayers = nullptr, clayers_buff[CD_TEMP_CHUNK_SIZE];
CustomData_blend_write_prepare(&hair->pdata, &players, players_buff, ARRAY_SIZE(players_buff));
CustomData_blend_write_prepare(&hair->cdata, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff));
@@ -174,33 +180,33 @@ static void hair_blend_read_expand(BlendExpander *expander, ID *id)
}
IDTypeInfo IDType_ID_HA = {
- .id_code = ID_HA,
- .id_filter = FILTER_ID_HA,
- .main_listbase_index = INDEX_ID_HA,
- .struct_size = sizeof(Hair),
- .name = "Hair",
- .name_plural = "hairs",
- .translation_context = BLT_I18NCONTEXT_ID_HAIR,
- .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE,
- .asset_type_info = NULL,
-
- .init_data = hair_init_data,
- .copy_data = hair_copy_data,
- .free_data = hair_free_data,
- .make_local = NULL,
- .foreach_id = hair_foreach_id,
- .foreach_cache = NULL,
- .foreach_path = NULL,
- .owner_get = NULL,
-
- .blend_write = hair_blend_write,
- .blend_read_data = hair_blend_read_data,
- .blend_read_lib = hair_blend_read_lib,
- .blend_read_expand = hair_blend_read_expand,
-
- .blend_read_undo_preserve = NULL,
-
- .lib_override_apply_post = NULL,
+ /*id_code */ ID_HA,
+ /*id_filter */ FILTER_ID_HA,
+ /*main_listbase_index */ INDEX_ID_HA,
+ /*struct_size */ sizeof(Hair),
+ /*name */ "Hair",
+ /*name_plural */ "hairs",
+ /*translation_context */ BLT_I18NCONTEXT_ID_HAIR,
+ /*flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
+ /*asset_type_info */ nullptr,
+
+ /*init_data */ hair_init_data,
+ /*copy_data */ hair_copy_data,
+ /*free_data */ hair_free_data,
+ /*make_local */ nullptr,
+ /*foreach_id */ hair_foreach_id,
+ /*foreach_cache */ nullptr,
+ /*foreach_path */ nullptr,
+ /*owner_get */ nullptr,
+
+ /*blend_write */ hair_blend_write,
+ /*blend_read_data */ hair_blend_read_data,
+ /*blend_read_lib */ hair_blend_read_lib,
+ /*blend_read_expand */ hair_blend_read_expand,
+
+ /*blend_read_undo_preserve */ nullptr,
+
+ /*lib_override_apply_post */ nullptr,
};
static void hair_random(Hair *hair)
@@ -250,7 +256,7 @@ static void hair_random(Hair *hair)
void *BKE_hair_add(Main *bmain, const char *name)
{
- Hair *hair = BKE_id_new(bmain, ID_HA, name);
+ Hair *hair = static_cast<Hair *>(BKE_id_new(bmain, ID_HA, name));
return hair;
}
@@ -258,14 +264,14 @@ void *BKE_hair_add(Main *bmain, const char *name)
BoundBox *BKE_hair_boundbox_get(Object *ob)
{
BLI_assert(ob->type == OB_HAIR);
- Hair *hair = ob->data;
+ Hair *hair = static_cast<Hair *>(ob->data);
- if (ob->runtime.bb != NULL && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
+ if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
return ob->runtime.bb;
}
- if (ob->runtime.bb == NULL) {
- ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "hair boundbox");
+ if (ob->runtime.bb == nullptr) {
+ ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
float min[3], max[3];
INIT_MINMAX(min, max);
@@ -289,10 +295,12 @@ BoundBox *BKE_hair_boundbox_get(Object *ob)
void BKE_hair_update_customdata_pointers(Hair *hair)
{
- hair->co = CustomData_get_layer_named(&hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION);
- hair->radius = CustomData_get_layer_named(&hair->pdata, CD_PROP_FLOAT, HAIR_ATTR_RADIUS);
- hair->curves = CustomData_get_layer(&hair->cdata, CD_HAIRCURVE);
- hair->mapping = CustomData_get_layer(&hair->cdata, CD_HAIRMAPPING);
+ hair->co = (float(*)[3])CustomData_get_layer_named(
+ &hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION);
+ hair->radius = (float *)CustomData_get_layer_named(
+ &hair->pdata, CD_PROP_FLOAT, HAIR_ATTR_RADIUS);
+ hair->curves = (HairCurve *)CustomData_get_layer(&hair->cdata, CD_HAIRCURVE);
+ hair->mapping = (HairMaping *)CustomData_get_layer(&hair->cdata, CD_HAIRMAPPING);
}
bool BKE_hair_customdata_required(Hair *UNUSED(hair), CustomDataLayer *layer)
@@ -304,10 +312,10 @@ bool BKE_hair_customdata_required(Hair *UNUSED(hair), CustomDataLayer *layer)
Hair *BKE_hair_new_for_eval(const Hair *hair_src, int totpoint, int totcurve)
{
- Hair *hair_dst = BKE_id_new_nomain(ID_HA, NULL);
+ Hair *hair_dst = static_cast<Hair *>(BKE_id_new_nomain(ID_HA, nullptr));
STRNCPY(hair_dst->id.name, hair_src->id.name);
- hair_dst->mat = MEM_dupallocN(hair_src->mat);
+ hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat));
hair_dst->totcol = hair_src->totcol;
hair_dst->totpoint = totpoint;
@@ -327,7 +335,7 @@ Hair *BKE_hair_copy_for_eval(Hair *hair_src, bool reference)
flags |= LIB_ID_COPY_CD_REFERENCE;
}
- Hair *result = (Hair *)BKE_id_copy_ex(NULL, &hair_src->id, NULL, flags);
+ Hair *result = (Hair *)BKE_id_copy_ex(nullptr, &hair_src->id, nullptr, flags);
return result;
}
@@ -351,7 +359,7 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
/* Evaluate modifiers. */
for (; md; md = md->next) {
- const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(static_cast<ModifierType>(md->type));
if (!BKE_modifier_is_enabled(scene, md, required_mode)) {
continue;
@@ -370,7 +378,7 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
BKE_hair_update_customdata_pointers(hair);
/* Created deformed coordinates array on demand. */
- mti->deformVerts(md, &mectx, NULL, hair->co, hair->totpoint);
+ mti->deformVerts(md, &mectx, nullptr, hair->co, hair->totpoint);
}
else if (mti->modifyHair) {
/* Ensure we are not modifying the input. */
@@ -383,7 +391,7 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph,
if (hair_next && hair_next != hair) {
/* If the modifier returned a new hair, release the old one. */
if (hair != hair_input) {
- BKE_id_free(NULL, hair);
+ BKE_id_free(nullptr, hair);
}
hair = hair_next;
}
@@ -399,7 +407,7 @@ void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Obje
BKE_object_free_derived_caches(object);
/* Evaluate modifiers. */
- Hair *hair = object->data;
+ Hair *hair = static_cast<Hair *>(object->data);
Hair *hair_eval = hair_evaluate_modifiers(depsgraph, scene, object, hair);
/* Assign evaluated object. */
@@ -409,8 +417,8 @@ void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Obje
/* Draw Cache */
-void (*BKE_hair_batch_cache_dirty_tag_cb)(Hair *hair, int mode) = NULL;
-void (*BKE_hair_batch_cache_free_cb)(Hair *hair) = NULL;
+void (*BKE_hair_batch_cache_dirty_tag_cb)(Hair *hair, int mode) = nullptr;
+void (*BKE_hair_batch_cache_free_cb)(Hair *hair) = nullptr;
void BKE_hair_batch_cache_dirty_tag(Hair *hair, int mode)
{
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index f43cf00a310..2d4366846aa 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -21,6 +21,7 @@
* \ingroup bke
*/
+#include <ctype.h>
#include <fcntl.h>
#include <math.h>
#include <stdio.h>
@@ -84,6 +85,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -97,6 +99,7 @@
#include "SEQ_utils.h" /* SEQ_get_topmost_sequence() */
+#include "GPU_material.h"
#include "GPU_texture.h"
#include "BLI_sys_types.h" /* for intptr_t support */
@@ -270,7 +273,33 @@ static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data)
return;
}
- if (BKE_bpath_foreach_path_fixed_process(bpath_data, ima->filepath)) {
+ /* If this is a tiled image, and we're asked to resolve the tokens in the virtual
+ * filepath, use the first tile to generate a concrete path for use during processing. */
+ bool result = false;
+ if (ima->source == IMA_SRC_TILED && (flag & BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN) != 0) {
+ char temp_path[FILE_MAX], orig_file[FILE_MAXFILE];
+ BLI_strncpy(temp_path, ima->filepath, sizeof(temp_path));
+ BLI_split_file_part(temp_path, orig_file, sizeof(orig_file));
+
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = BKE_image_get_tile_strformat(temp_path, &tile_format);
+ BKE_image_set_filepath_from_tile_number(
+ temp_path, udim_pattern, tile_format, ((ImageTile *)ima->tiles.first)->tile_number);
+ MEM_SAFE_FREE(udim_pattern);
+
+ result = BKE_bpath_foreach_path_fixed_process(bpath_data, temp_path);
+ if (result) {
+ /* Put the filepath back together using the new directory and the original file name. */
+ char new_dir[FILE_MAXDIR];
+ BLI_split_dir_part(temp_path, new_dir, sizeof(new_dir));
+ BLI_join_dirfile(ima->filepath, sizeof(ima->filepath), new_dir, orig_file);
+ }
+ }
+ else {
+ result = BKE_bpath_foreach_path_fixed_process(bpath_data, ima->filepath);
+ }
+
+ if (result) {
if (flag & BKE_BPATH_FOREACH_PATH_RELOAD_EDITED) {
if (!BKE_image_has_packedfile(ima) &&
/* Image may have been painted onto (and not saved, T44543). */
@@ -886,9 +915,13 @@ Image *BKE_image_load(Main *bmain, const char *filepath)
/* exists? */
file = BLI_open(str, O_BINARY | O_RDONLY, 0);
if (file == -1) {
- return NULL;
+ if (!BKE_image_tile_filepath_exists(str)) {
+ return NULL;
+ }
+ }
+ else {
+ close(file);
}
- close(file);
ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE);
STRNCPY(ima->filepath, filepath);
@@ -3363,6 +3396,23 @@ static void image_walk_ntree_all_users(
}
}
+static void image_walk_gpu_materials(
+ ID *id,
+ ListBase *gpu_materials,
+ void *customdata,
+ void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata))
+{
+ LISTBASE_FOREACH (LinkData *, link, gpu_materials) {
+ GPUMaterial *gpu_material = (GPUMaterial *)link->data;
+ ListBase textures = GPU_material_textures(gpu_material);
+ LISTBASE_FOREACH (GPUMaterialTexture *, gpu_material_texture, &textures) {
+ if (gpu_material_texture->iuser_available) {
+ callback(gpu_material_texture->ima, id, &gpu_material_texture->iuser, customdata);
+ }
+ }
+ }
+}
+
static void image_walk_id_all_users(
ID *id,
bool skip_nested_nodes,
@@ -3382,6 +3432,7 @@ static void image_walk_id_all_users(
if (ma->nodetree && ma->use_nodes && !skip_nested_nodes) {
image_walk_ntree_all_users(ma->nodetree, &ma->id, customdata, callback);
}
+ image_walk_gpu_materials(id, &ma->gpumaterial, customdata, callback);
break;
}
case ID_LA: {
@@ -3396,6 +3447,7 @@ static void image_walk_id_all_users(
if (world->nodetree && world->use_nodes && !skip_nested_nodes) {
image_walk_ntree_all_users(world->nodetree, &world->id, customdata, callback);
}
+ image_walk_gpu_materials(id, &world->gpumaterial, customdata, callback);
break;
}
case ID_TE: {
@@ -3678,6 +3730,43 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
BKE_image_free_buffers(ima);
}
+ if (ima->source == IMA_SRC_TILED) {
+ ListBase new_tiles = {NULL, NULL};
+ int new_start, new_range;
+
+ char filepath[FILE_MAX];
+ BLI_strncpy(filepath, ima->filepath, sizeof(filepath));
+ BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
+ bool result = BKE_image_get_tile_info(filepath, &new_tiles, &new_start, &new_range);
+ if (result) {
+ /* Because the prior and new list of tiles are both sparse sequences, we need to be sure
+ * to account for how the two sets might or might not overlap. To be complete, we start
+ * the refresh process by clearing all existing tiles, stopping when there's only 1 tile
+ * left. */
+ while (BKE_image_remove_tile(ima, ima->tiles.last)) {
+ ;
+ }
+
+ int remaining_tile_number = ((ImageTile *)ima->tiles.first)->tile_number;
+ bool needs_final_cleanup = true;
+
+ /* Add in all the new tiles. */
+ LISTBASE_FOREACH (LinkData *, new_tile, &new_tiles) {
+ int new_tile_number = POINTER_AS_INT(new_tile->data);
+ BKE_image_add_tile(ima, new_tile_number, NULL);
+ if (new_tile_number == remaining_tile_number) {
+ needs_final_cleanup = false;
+ }
+ }
+
+ /* Final cleanup if the prior remaining tile was never encountered in the new list. */
+ if (needs_final_cleanup) {
+ BKE_image_remove_tile(ima, BKE_image_get_tile(ima, remaining_tile_number));
+ }
+ }
+ BLI_freelistN(&new_tiles);
+ }
+
if (iuser) {
image_tag_reload(ima, NULL, iuser, ima);
}
@@ -3699,16 +3788,8 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
BLI_mutex_unlock(ima->runtime.cache_mutex);
- /* don't use notifiers because they are not 100% sure to succeeded
- * this also makes sure all scenes are accounted for. */
- {
- Scene *scene;
- for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
- if (scene->nodetree) {
- nodeUpdateID(scene->nodetree, &ima->id);
- }
- }
- }
+ BKE_ntree_update_tag_id_changed(bmain, &ima->id);
+ BKE_ntree_update_main(bmain, NULL);
}
/* return renderpass for a given pass index and active view */
@@ -3769,6 +3850,57 @@ void BKE_image_get_tile_label(Image *ima, ImageTile *tile, char *label, int len_
}
}
+bool BKE_image_get_tile_info(char *filepath,
+ ListBase *udim_tiles,
+ int *udim_start,
+ int *udim_range)
+{
+ char filename[FILE_MAXFILE], dirname[FILE_MAXDIR];
+ BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
+
+ BKE_image_ensure_tile_token(filename);
+
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = BKE_image_get_tile_strformat(filename, &tile_format);
+
+ bool is_udim = true;
+ int min_udim = IMA_UDIM_MAX + 1;
+ 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)) {
+ continue;
+ }
+
+ if (!BKE_image_get_tile_number_from_filepath(dir[i].relname, udim_pattern, tile_format, &id)) {
+ continue;
+ }
+
+ if (id < 1001 || id > IMA_UDIM_MAX) {
+ is_udim = false;
+ break;
+ }
+
+ BLI_addtail(udim_tiles, BLI_genericNodeN(POINTER_FROM_INT(id)));
+ min_udim = min_ii(min_udim, id);
+ max_udim = max_ii(max_udim, id);
+ }
+ BLI_filelist_free(dir, totfile);
+ MEM_SAFE_FREE(udim_pattern);
+
+ if (is_udim && min_udim <= IMA_UDIM_MAX) {
+ BLI_join_dirfile(filepath, FILE_MAX, dirname, filename);
+
+ *udim_start = min_udim;
+ *udim_range = max_udim - min_udim + 1;
+ return true;
+ }
+ return false;
+}
+
ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label)
{
if (ima->source != IMA_SRC_TILED) {
@@ -3928,6 +4060,185 @@ bool BKE_image_fill_tile(struct Image *ima,
return false;
}
+void BKE_image_ensure_tile_token(char *filename)
+{
+ if (filename == NULL) {
+ return;
+ }
+
+ /* Is there a '<' character in the filename? Assume tokens already present. */
+ if (strstr(filename, "<") != NULL) {
+ 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;
+ }
+
+ /* 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++;
+ }
+
+ 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';
+ }
+}
+
+bool BKE_image_tile_filepath_exists(const char *filepath)
+{
+ BLI_assert(!BLI_path_is_rel(filepath));
+
+ char dirname[FILE_MAXDIR];
+ BLI_split_dir_part(filepath, dirname, sizeof(dirname));
+
+ eUDIM_TILE_FORMAT tile_format;
+ 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)) {
+ continue;
+ }
+
+ int id;
+ if (!BKE_image_get_tile_number_from_filepath(dir[i].path, udim_pattern, tile_format, &id)) {
+ continue;
+ }
+
+ if (id < 1001 || id > IMA_UDIM_MAX) {
+ continue;
+ }
+
+ found = true;
+ break;
+ }
+ BLI_filelist_free(dir, totfile);
+ MEM_SAFE_FREE(udim_pattern);
+
+ return found;
+}
+
+char *BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format)
+{
+ if (filepath == NULL || r_tile_format == NULL) {
+ return NULL;
+ }
+
+ if (strstr(filepath, "<UDIM>") != NULL) {
+ *r_tile_format = UDIM_TILE_FORMAT_UDIM;
+ return BLI_str_replaceN(filepath, "<UDIM>", "%d");
+ }
+ if (strstr(filepath, "<UVTILE>") != NULL) {
+ *r_tile_format = UDIM_TILE_FORMAT_UVTILE;
+ return BLI_str_replaceN(filepath, "<UVTILE>", "u%d_v%d");
+ }
+
+ *r_tile_format = UDIM_TILE_FORMAT_NONE;
+ return NULL;
+}
+
+bool BKE_image_get_tile_number_from_filepath(const char *filepath,
+ const char *pattern,
+ eUDIM_TILE_FORMAT tile_format,
+ int *r_tile_number)
+{
+ if (filepath == NULL || pattern == NULL || r_tile_number == NULL) {
+ return false;
+ }
+
+ int u, v;
+ bool result = false;
+
+ if (tile_format == UDIM_TILE_FORMAT_UDIM) {
+ if (sscanf(filepath, pattern, &u) == 1) {
+ *r_tile_number = u;
+ result = true;
+ }
+ }
+ else if (tile_format == UDIM_TILE_FORMAT_UVTILE) {
+ if (sscanf(filepath, pattern, &u, &v) == 2) {
+ *r_tile_number = 1001 + (u - 1) + ((v - 1) * 10);
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+void BKE_image_set_filepath_from_tile_number(char *filepath,
+ const char *pattern,
+ eUDIM_TILE_FORMAT tile_format,
+ int tile_number)
+{
+ if (filepath == NULL || pattern == NULL) {
+ return;
+ }
+
+ if (tile_format == UDIM_TILE_FORMAT_UDIM) {
+ sprintf(filepath, pattern, tile_number);
+ }
+ else if (tile_format == UDIM_TILE_FORMAT_UVTILE) {
+ int u = ((tile_number - 1001) % 10);
+ int v = ((tile_number - 1001) / 10);
+ sprintf(filepath, pattern, u + 1, v + 1);
+ }
+}
+
/* if layer or pass changes, we need an index for the imbufs list */
/* note it is called for rendered results, but it doesn't use the index! */
RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
@@ -5500,6 +5811,11 @@ void BKE_image_user_id_eval_animation(Depsgraph *depsgraph, ID *id)
void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
{
+ BKE_image_user_file_path_ex(iuser, ima, filepath, true);
+}
+
+void BKE_image_user_file_path_ex(ImageUser *iuser, Image *ima, char *filepath, bool resolve_udim)
+{
if (BKE_image_is_multiview(ima)) {
ImageView *iv = BLI_findlink(&ima->views, iuser->view);
if (iv->filepath[0]) {
@@ -5520,13 +5836,17 @@ void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath)
int index;
if (ima->source == IMA_SRC_SEQUENCE) {
index = iuser ? iuser->framenr : ima->lastframe;
+ BLI_path_sequence_decode(filepath, head, tail, &numlen);
+ BLI_path_sequence_encode(filepath, head, tail, numlen, index);
}
- else {
+ else if (resolve_udim) {
index = image_get_tile_number_from_iuser(ima, iuser);
- }
- BLI_path_sequence_decode(filepath, head, tail, &numlen);
- BLI_path_sequence_encode(filepath, head, tail, numlen, index);
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = BKE_image_get_tile_strformat(filepath, &tile_format);
+ BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, tile_format, index);
+ MEM_SAFE_FREE(udim_pattern);
+ }
}
BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc
index 4440e4b101a..c82de02e52a 100644
--- a/source/blender/blenkernel/intern/image_gpu.cc
+++ b/source/blender/blenkernel/intern/image_gpu.cc
@@ -172,7 +172,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima,
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
if (ibuf) {
- PackTile *packtile = (PackTile *)MEM_callocN(sizeof(PackTile), __func__);
+ PackTile *packtile = MEM_cnew<PackTile>(__func__);
packtile->tile = tile;
packtile->boxpack.w = ibuf->x;
packtile->boxpack.h = ibuf->y;
diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c
index f93ede517a9..329bc7b498b 100644
--- a/source/blender/blenkernel/intern/image_save.c
+++ b/source/blender/blenkernel/intern/image_save.c
@@ -30,6 +30,8 @@
#include "DNA_image_types.h"
+#include "MEM_guardedalloc.h"
+
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -402,15 +404,17 @@ bool BKE_image_save(
bool colorspace_changed = false;
+ eUDIM_TILE_FORMAT tile_format;
+ char *udim_pattern = NULL;
+
if (ima->source == IMA_SRC_TILED) {
- /* Verify filepath for tiles images. */
- ImageTile *first_tile = ima->tiles.first;
- if (BLI_path_sequence_decode(opts->filepath, NULL, NULL, NULL) != first_tile->tile_number) {
+ /* 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 the UDIM tile number %d",
- opts->filepath,
- first_tile->tile_number);
+ "When saving a tiled image, the path '%s' must contain a valid UDIM marker",
+ opts->filepath);
return false;
}
@@ -420,36 +424,29 @@ bool BKE_image_save(
}
}
- /* Save image - or, for tiled images, the first tile. */
- bool ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed);
-
- if (ok && ima->source == IMA_SRC_TILED) {
+ /* 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));
- char head[FILE_MAX], tail[FILE_MAX];
- unsigned short numlen;
- BLI_path_sequence_decode(filepath, head, tail, &numlen);
-
- /* Save all other tiles. */
- int index;
- LISTBASE_FOREACH_INDEX (ImageTile *, tile, &ima->tiles, index) {
- /* First tile was already saved before the loop. */
- if (index == 0) {
- continue;
- }
+ /* 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) {
- continue;
+ break;
}
-
- /* Build filepath of the tile. */
- BLI_path_sequence_encode(opts->filepath, head, tail, numlen, tile->tile_number);
-
- iuser->tile = tile->tile_number;
- ok = ok && image_save_single(reports, ima, iuser, opts, &colorspace_changed);
}
+ BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath));
BLI_strncpy(opts->filepath, filepath, sizeof(opts->filepath));
+ MEM_freeN(udim_pattern);
}
if (colorspace_changed) {
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index 1484d35f28a..c58820b239b 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -343,7 +343,7 @@ ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollecti
/* Base */
-static void view_layer_bases_hash_create(ViewLayer *view_layer)
+static void view_layer_bases_hash_create(ViewLayer *view_layer, const bool do_base_duplicates_fix)
{
static ThreadMutex hash_lock = BLI_MUTEX_INITIALIZER;
@@ -353,15 +353,29 @@ static void view_layer_bases_hash_create(ViewLayer *view_layer)
if (view_layer->object_bases_hash == NULL) {
GHash *hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
- LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
+ LISTBASE_FOREACH_MUTABLE (Base *, base, &view_layer->object_bases) {
if (base->object) {
- /* Some processes, like ID remapping, may lead to having several bases with the same
- * object. So just take the first one here, and ignore all others
- * (#BKE_layer_collection_sync will clean this up anyway). */
void **val_pp;
if (!BLI_ghash_ensure_p(hash, base->object, &val_pp)) {
*val_pp = base;
}
+ /* The same object has several bases.
+ *
+ * In normal cases this is a serious bug, but this is a common situation when remapping
+ * an object into another one already present in the same View Layer. While ideally we
+ * would process this case separately, for performances reasons it makes more sense to
+ * tackle it here. */
+ else if (do_base_duplicates_fix) {
+ if (view_layer->basact == base) {
+ view_layer->basact = NULL;
+ }
+ BLI_freelinkN(&view_layer->object_bases, base);
+ }
+ else {
+ CLOG_FATAL(&LOG,
+ "Object '%s' has more than one entry in view layer's object bases listbase",
+ base->object->id.name + 2);
+ }
}
}
@@ -376,7 +390,7 @@ static void view_layer_bases_hash_create(ViewLayer *view_layer)
Base *BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
{
if (!view_layer->object_bases_hash) {
- view_layer_bases_hash_create(view_layer);
+ view_layer_bases_hash_create(view_layer, false);
}
return BLI_ghash_lookup(view_layer->object_bases_hash, ob);
@@ -1204,7 +1218,7 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer)
/* Create object to base hash if it does not exist yet. */
if (!view_layer->object_bases_hash) {
- view_layer_bases_hash_create(view_layer);
+ view_layer_bases_hash_create(view_layer, false);
}
/* Clear visible and selectable flags to be reset. */
@@ -1317,6 +1331,11 @@ void BKE_main_collection_sync_remap(const Main *bmain)
if (view_layer->object_bases_hash) {
BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL);
view_layer->object_bases_hash = NULL;
+
+ /* Directly re-create the mapping here, so that we can also deal with duplicates in
+ * `view_layer->object_bases` list of bases properly. This is the only place where such
+ * duplicates should be fixed, and not considered as a critical error. */
+ view_layer_bases_hash_create(view_layer, true);
}
}
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 1922a54addb..6d2e89187f7 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -350,6 +350,9 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
void BKE_id_delete(Main *bmain, void *idv)
{
+ BLI_assert_msg((((ID *)idv)->tag & LIB_TAG_NO_MAIN) == 0,
+ "Cannot be used with IDs outside of Main");
+
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
((ID *)idv)->tag |= LIB_TAG_DOIT;
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 83ed0ee4c08..81c290589a6 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -470,8 +470,9 @@ static void lib_override_group_tag_data_object_to_collection_init_collection_pro
}
LinkNodePair **collections_linkedlist_p;
- if (!BLI_ghash_ensure_p(
- data->linked_object_to_instantiating_collections, ob, &collections_linkedlist_p)) {
+ if (!BLI_ghash_ensure_p(data->linked_object_to_instantiating_collections,
+ ob,
+ (void ***)&collections_linkedlist_p)) {
*collections_linkedlist_p = BLI_memarena_calloc(data->mem_arena,
sizeof(**collections_linkedlist_p));
}
@@ -611,6 +612,42 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat
}
}
+static void lib_override_linked_group_tag_clear_boneshapes_objects(LibOverrideGroupTagData *data)
+{
+ Main *bmain = data->bmain;
+
+ /* Remove (untag) bone shape objects, they shall never need to be to directly/explicitly
+ * overridden. */
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & data->tag)) {
+ for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
+ if (pchan->custom != NULL) {
+ pchan->custom->id.tag &= ~data->tag;
+ }
+ }
+ }
+ }
+
+ /* Remove (untag) collections if they do not own any tagged object (either themselves, or in
+ * their children collections). */
+ LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
+ if ((collection->id.tag & data->tag) == 0) {
+ continue;
+ }
+ bool keep_tagged = false;
+ const ListBase object_bases = BKE_collection_object_cache_get(collection);
+ LISTBASE_FOREACH (Base *, base, &object_bases) {
+ if ((base->object->id.tag & data->tag) != 0) {
+ keep_tagged = true;
+ break;
+ }
+ }
+ if (!keep_tagged) {
+ collection->id.tag &= ~data->tag;
+ }
+ }
+}
+
/* This will tag at least all 'boundary' linked IDs for a potential override group.
*
* Requires existing `Main.relations`.
@@ -639,17 +676,8 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data)
/* Tag all collections and objects. */
lib_override_linked_group_tag_recursive(data);
- /* Then, we remove (untag) bone shape objects, you shall never want to directly/explicitly
- * override those. */
- LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
- if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & data->tag)) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) {
- if (pchan->custom != NULL) {
- pchan->custom->id.tag &= ~(data->tag | data->missing_tag);
- }
- }
- }
- }
+ /* Do not override objects used as bone shapes, nor their collections if possible. */
+ lib_override_linked_group_tag_clear_boneshapes_objects(data);
/* For each object tagged for override, ensure we get at least one local or liboverride
* collection to host it. Avoids getting a bunch of random object in the scene's master
diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c
index 4ad0186f9b5..1f20a84098c 100644
--- a/source/blender/blenkernel/intern/lib_query.c
+++ b/source/blender/blenkernel/intern/lib_query.c
@@ -439,7 +439,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used)
case ID_LA:
return (ELEM(id_type_used, ID_TE));
case ID_CA:
- return ELEM(id_type_used, ID_OB);
+ return ELEM(id_type_used, ID_OB, ID_IM);
case ID_KE:
/* Warning! key->from, could be more types in future? */
return ELEM(id_type_used, ID_ME, ID_CU, ID_LT);
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 3cea0de32ee..b8e0eb2c942 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -282,6 +282,11 @@ static void libblock_remap_data_postprocess_object_update(Main *bmain,
* to remove the NULL children from collections not used in any scene. */
BKE_collections_object_remove_nulls(bmain);
}
+ else {
+ /* Remapping may have created duplicates of CollectionObject pointing to the same object within
+ * the same collection. */
+ BKE_collections_object_remove_duplicates(bmain);
+ }
BKE_main_collection_sync_remap(bmain);
@@ -319,6 +324,7 @@ static void libblock_remap_data_postprocess_collection_update(Main *bmain,
else {
/* Temp safe fix, but a "tad" brute force... We should probably be able to use parents from
* old_collection instead? */
+ /* NOTE: Also takes care of duplicated child collections that remapping may have created. */
BKE_main_collections_parent_relations_rebuild(bmain);
}
@@ -346,7 +352,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o
static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id)
{
/* Update all group nodes using a node group. */
- ntreeUpdateAllUsers(bmain, new_id, 0);
+ ntreeUpdateAllUsers(bmain, new_id);
}
/**
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index ac0dbcb715d..95f41ab4b39 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -50,6 +50,7 @@
#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_texture.h"
#include "BLO_read_write.h"
@@ -2085,5 +2086,5 @@ void BKE_linestyle_default_shader(const bContext *C, FreestyleLineStyle *linesty
tosock = BLI_findlink(&output_linestyle->inputs, 0); /* Color */
nodeAddLink(ntree, input_texure, fromsock, output_linestyle, tosock);
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ BKE_ntree_update_main_tree(CTX_data_main(C), ntree, NULL);
}
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 05aa9111fa3..12c63ab0523 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -36,13 +36,16 @@
#include "BLI_bitmap.h"
#include "BLI_edgehash.h"
#include "BLI_endian_switch.h"
+#include "BLI_float3.hh"
#include "BLI_ghash.h"
#include "BLI_hash.h"
+#include "BLI_index_range.hh"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_string.h"
+#include "BLI_task.hh"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -453,14 +456,14 @@ static int customdata_compare(
for (int i = 0; i < c1->totlayer; i++) {
l1 = &c1->layers[i];
- if (CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr && l1->anonymous_id != nullptr) {
+ if ((CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr) && l1->anonymous_id == nullptr) {
layer_count1++;
}
}
for (int i = 0; i < c2->totlayer; i++) {
l2 = &c2->layers[i];
- if (CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr && l2->anonymous_id != nullptr) {
+ if ((CD_TYPE_AS_MASK(l2->type) & cd_mask_all_attr) && l2->anonymous_id == nullptr) {
layer_count2++;
}
}
@@ -1577,13 +1580,35 @@ void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri,
bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3])
{
- int i = me->totvert;
- MVert *mvert;
- for (mvert = me->mvert; i--; mvert++) {
- minmax_v3v3_v3(r_min, r_max, mvert->co);
+ using namespace blender;
+ if (me->totvert == 0) {
+ return false;
}
- return (me->totvert != 0);
+ struct Result {
+ float3 min;
+ float3 max;
+ };
+
+ const Result minmax = threading::parallel_reduce(
+ IndexRange(me->totvert),
+ 1024,
+ Result{float3(FLT_MAX), float3(-FLT_MAX)},
+ [&](IndexRange range, const Result &init) {
+ Result result = init;
+ for (const int i : range) {
+ float3::min_max(me->mvert[i].co, result.min, result.max);
+ }
+ return result;
+ },
+ [](const Result &a, const Result &b) {
+ return Result{float3::min(a.min, b.min), float3::max(a.max, b.max)};
+ });
+
+ copy_v3_v3(r_min, float3::min(minmax.min, r_min));
+ copy_v3_v3(r_max, float3::max(minmax.max, r_max));
+
+ return true;
}
void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys)
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index e8054884f26..12fa9d16fd1 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -589,14 +589,14 @@ struct VertLink {
static void prependPolyLineVert(ListBase *lb, uint index)
{
- VertLink *vl = (VertLink *)MEM_callocN(sizeof(VertLink), "VertLink");
+ VertLink *vl = MEM_cnew<VertLink>("VertLink");
vl->index = index;
BLI_addhead(lb, vl);
}
static void appendPolyLineVert(ListBase *lb, uint index)
{
- VertLink *vl = (VertLink *)MEM_callocN(sizeof(VertLink), "VertLink");
+ VertLink *vl = MEM_cnew<VertLink>("VertLink");
vl->index = index;
BLI_addtail(lb, vl);
}
@@ -632,7 +632,7 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed
med = medge;
for (i = 0; i < medge_len; i++, med++) {
if (edge_users[i] == edge_users_test) {
- EdgeLink *edl = (EdgeLink *)MEM_callocN(sizeof(EdgeLink), "EdgeLink");
+ EdgeLink *edl = MEM_cnew<EdgeLink>("EdgeLink");
edl->edge = med;
BLI_addtail(&edges, edl);
@@ -719,7 +719,7 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed
VertLink *vl;
/* create new 'nurb' within the curve */
- nu = (Nurb *)MEM_callocN(sizeof(Nurb), "MeshNurb");
+ nu = MEM_cnew<Nurb>("MeshNurb");
nu->pntsu = totpoly;
nu->pntsv = 1;
@@ -901,6 +901,20 @@ static Object *object_for_curve_to_mesh_create(const Object *object)
return temp_object;
}
+static void object_for_curve_to_mesh_free(Object *temp_object)
+{
+ /* Clear edit mode pointers that were explicitly copied to the temporary curve. */
+ ID *final_object_data = static_cast<ID *>(temp_object->data);
+ if (GS(final_object_data->name) == ID_CU) {
+ Curve &curve = *reinterpret_cast<Curve *>(final_object_data);
+ curve.editfont = nullptr;
+ curve.editnurb = nullptr;
+ }
+
+ BKE_id_free(nullptr, temp_object->data);
+ BKE_id_free(nullptr, temp_object);
+}
+
/**
* Populate `object->runtime.curve_cache` which is then used to create the mesh.
*/
@@ -917,7 +931,7 @@ static void curve_to_mesh_eval_ensure(Object &object)
* will have no modifiers. */
Object bevel_object = {{nullptr}};
if (curve.bevobj != nullptr) {
- bevel_object = *curve.bevobj;
+ memcpy(&bevel_object, curve.bevobj, sizeof(bevel_object));
BLI_listbase_clear(&bevel_object.modifiers);
BKE_object_runtime_reset(&bevel_object);
curve.bevobj = &bevel_object;
@@ -926,7 +940,7 @@ static void curve_to_mesh_eval_ensure(Object &object)
/* Same thing for taper. */
Object taper_object = {{nullptr}};
if (curve.taperobj != nullptr) {
- taper_object = *curve.taperobj;
+ memcpy(&taper_object, curve.taperobj, sizeof(taper_object));
BLI_listbase_clear(&taper_object.modifiers);
BKE_object_runtime_reset(&taper_object);
curve.taperobj = &taper_object;
@@ -1003,8 +1017,7 @@ static Mesh *mesh_new_from_curve_type_object(const Object *object)
Mesh *mesh = mesh_new_from_evaluated_curve_type_object(temp_object);
- BKE_id_free(nullptr, temp_object->data);
- BKE_id_free(nullptr, temp_object);
+ object_for_curve_to_mesh_free(temp_object);
return mesh;
}
@@ -1065,7 +1078,8 @@ static Mesh *mesh_new_from_mesh_object_with_layers(Depsgraph *depsgraph,
return nullptr;
}
- Object object_for_eval = *object;
+ Object object_for_eval;
+ memcpy(&object_for_eval, object, sizeof(object_for_eval));
if (object_for_eval.runtime.data_orig != nullptr) {
object_for_eval.data = object_for_eval.runtime.data_orig;
}
@@ -1440,7 +1454,8 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
/* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */
/* TODO(Sybren): the above claim came from 2.7x derived-mesh code (DM_to_mesh);
* check whether it is still true with Mesh */
- Mesh tmp = *mesh_dst;
+ Mesh tmp;
+ memcpy(&tmp, mesh_dst, sizeof(tmp));
int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
bool did_shapekeys = false;
eCDAllocType alloctype = CD_DUPLICATE;
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index da5b4ccc764..47ea55be871 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -319,6 +319,7 @@ void BKE_mesh_ensure_normals(Mesh *mesh)
void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
{
switch ((eMeshWrapperType)mesh->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
/* Run code below. */
break;
diff --git a/source/blender/blenkernel/intern/mesh_wrapper.c b/source/blender/blenkernel/intern/mesh_wrapper.c
index bc1ffeb8cf4..4cc43354a44 100644
--- a/source/blender/blenkernel/intern/mesh_wrapper.c
+++ b/source/blender/blenkernel/intern/mesh_wrapper.c
@@ -36,6 +36,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "BLI_ghash.h"
@@ -50,8 +51,14 @@
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_mesh_wrapper.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_mesh.h"
+#include "BKE_subdiv_modifier.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em,
const CustomData_MeshMasks *cd_mask_extra,
@@ -106,7 +113,8 @@ static void mesh_wrapper_ensure_mdata_isolated(void *userdata)
me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA;
switch (geom_type_orig) {
- case ME_WRAPPER_TYPE_MDATA: {
+ case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD: {
break; /* Quiet warning. */
}
case ME_WRAPPER_TYPE_BMESH: {
@@ -157,6 +165,7 @@ bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3])
case ME_WRAPPER_TYPE_BMESH:
return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime.edit_data, min, max);
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return BKE_mesh_minmax(me, min, max);
}
BLI_assert_unreachable();
@@ -191,7 +200,8 @@ void BKE_mesh_wrapper_vert_coords_copy(const Mesh *me,
}
return;
}
- case ME_WRAPPER_TYPE_MDATA: {
+ case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD: {
BLI_assert(vert_coords_len <= me->totvert);
const MVert *mvert = me->mvert;
for (int i = 0; i < vert_coords_len; i++) {
@@ -228,7 +238,8 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *me,
}
return;
}
- case ME_WRAPPER_TYPE_MDATA: {
+ case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD: {
BLI_assert(vert_coords_len == me->totvert);
const MVert *mvert = me->mvert;
for (int i = 0; i < vert_coords_len; i++) {
@@ -252,6 +263,7 @@ int BKE_mesh_wrapper_vert_len(const Mesh *me)
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totvert;
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return me->totvert;
}
BLI_assert_unreachable();
@@ -264,6 +276,7 @@ int BKE_mesh_wrapper_edge_len(const Mesh *me)
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totedge;
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return me->totedge;
}
BLI_assert_unreachable();
@@ -276,6 +289,7 @@ int BKE_mesh_wrapper_loop_len(const Mesh *me)
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totloop;
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return me->totloop;
}
BLI_assert_unreachable();
@@ -288,6 +302,7 @@ int BKE_mesh_wrapper_poly_len(const Mesh *me)
case ME_WRAPPER_TYPE_BMESH:
return me->edit_mesh->bm->totface;
case ME_WRAPPER_TYPE_MDATA:
+ case ME_WRAPPER_TYPE_SUBD:
return me->totpoly;
}
BLI_assert_unreachable();
@@ -295,3 +310,70 @@ int BKE_mesh_wrapper_poly_len(const Mesh *me)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name CPU Subdivision Evaluation
+ * \{ */
+
+Mesh *BKE_mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me)
+{
+ ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex;
+ BLI_mutex_lock(mesh_eval_mutex);
+
+ if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_SUBD) {
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me->runtime.mesh_eval;
+ }
+
+ SubsurfModifierData *smd = BKE_object_get_last_subsurf_modifier(ob);
+ if (!smd) {
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me;
+ }
+
+ const bool apply_render = me->runtime.subsurf_apply_render;
+
+ SubdivSettings subdiv_settings;
+ BKE_subsurf_modifier_subdiv_settings_init(&subdiv_settings, smd, apply_render);
+ if (subdiv_settings.level == 0) {
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me;
+ }
+
+ SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
+
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &subdiv_settings, me, false);
+ if (subdiv == NULL) {
+ /* Happens on bad topology, but also on empty input mesh. */
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me;
+ }
+
+ SubdivToMeshSettings mesh_settings;
+ mesh_settings.resolution = me->runtime.subsurf_resolution;
+ mesh_settings.use_optimal_display = me->runtime.subsurf_use_optimal_display;
+
+ if (mesh_settings.resolution < 3) {
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me;
+ }
+
+ Mesh *subdiv_mesh = BKE_subdiv_to_mesh(subdiv, &mesh_settings, me);
+
+ if (subdiv != runtime_data->subdiv) {
+ BKE_subdiv_free(subdiv);
+ }
+
+ if (subdiv_mesh != me) {
+ if (me->runtime.mesh_eval != NULL) {
+ BKE_id_free(NULL, me->runtime.mesh_eval);
+ }
+ me->runtime.mesh_eval = subdiv_mesh;
+ me->runtime.wrapper_type = ME_WRAPPER_TYPE_SUBD;
+ }
+
+ BLI_mutex_unlock(mesh_eval_mutex);
+ return me->runtime.mesh_eval;
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index e1d201d7806..f3b6c2544bf 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -970,6 +970,7 @@ static void modwrap_dependsOnNormals(Mesh *me)
}
break;
}
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
BKE_mesh_calc_normals(me);
break;
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index fc2e7d0a6a3..b0c93a5614d 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -70,6 +70,7 @@
#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
#include "IMB_imbuf.h"
@@ -1695,17 +1696,7 @@ void BKE_movieclip_reload(Main *bmain, MovieClip *clip)
movieclip_calc_length(clip);
- /* same as for image update -- don't use notifiers because they are not 100% sure to succeeded
- * (node trees which are not currently visible wouldn't be refreshed)
- */
- {
- Scene *scene;
- for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
- if (scene->nodetree) {
- nodeUpdateID(scene->nodetree, &clip->id);
- }
- }
- }
+ BKE_ntree_update_tag_id_changed(bmain, &clip->id);
}
void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClipScopes *scopes)
diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c
index 3665d01926b..50b4410a28e 100644
--- a/source/blender/blenkernel/intern/multires_reshape_smooth.c
+++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c
@@ -566,7 +566,8 @@ static bool foreach_topology_info(const SubdivForeachContext *foreach_context,
const int num_vertices,
const int num_edges,
const int num_loops,
- const int num_polygons)
+ const int num_polygons,
+ const int *UNUSED(subdiv_polygon_offset))
{
MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
const int max_edges = reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR ?
@@ -1037,7 +1038,7 @@ static void reshape_subdiv_create(MultiresReshapeSmoothContext *reshape_smooth_c
converter_init(reshape_smooth_context, &converter);
Subdiv *reshape_subdiv = BKE_subdiv_new_from_converter(settings, &converter);
- BKE_subdiv_eval_begin(reshape_subdiv);
+ BKE_subdiv_eval_begin(reshape_subdiv, SUBDIV_EVALUATOR_TYPE_CPU, NULL);
reshape_smooth_context->reshape_subdiv = reshape_subdiv;
diff --git a/source/blender/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c
index b7572204182..07a5d7c4a61 100644
--- a/source/blender/blenkernel/intern/multires_reshape_util.c
+++ b/source/blender/blenkernel/intern/multires_reshape_util.c
@@ -65,7 +65,7 @@ Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph,
SubdivSettings subdiv_settings;
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, base_mesh);
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
BKE_subdiv_free(subdiv);
return NULL;
}
diff --git a/source/blender/blenkernel/intern/multires_reshape_vertcos.c b/source/blender/blenkernel/intern/multires_reshape_vertcos.c
index ed2df1ba8c5..c009349ff1b 100644
--- a/source/blender/blenkernel/intern/multires_reshape_vertcos.c
+++ b/source/blender/blenkernel/intern/multires_reshape_vertcos.c
@@ -114,7 +114,8 @@ static bool multires_reshape_vertcos_foreach_topology_info(
const int num_vertices,
const int UNUSED(num_edges),
const int UNUSED(num_loops),
- const int UNUSED(num_polygons))
+ const int UNUSED(num_polygons),
+ const int *UNUSED(subdiv_polygon_offset))
{
MultiresReshapeAssignVertcosContext *reshape_vertcos_context = foreach_context->user_data;
if (num_vertices != reshape_vertcos_context->num_vert_coords) {
diff --git a/source/blender/blenkernel/intern/multires_versioning.c b/source/blender/blenkernel/intern/multires_versioning.c
index 4c0d7165cd0..18708c43f26 100644
--- a/source/blender/blenkernel/intern/multires_versioning.c
+++ b/source/blender/blenkernel/intern/multires_versioning.c
@@ -61,7 +61,7 @@ static Subdiv *subdiv_for_simple_to_catmull_clark(Object *object, MultiresModifi
Subdiv *subdiv = BKE_subdiv_new_from_converter(&subdiv_settings, &converter);
BKE_subdiv_converter_free(&converter);
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
BKE_subdiv_free(subdiv);
return NULL;
}
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index be458ed036e..f32db41f62d 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -65,6 +65,7 @@
#include "BKE_animsys.h"
#include "BKE_bpath.h"
#include "BKE_colortools.h"
+#include "BKE_context.h"
#include "BKE_cryptomatte.h"
#include "BKE_global.h"
#include "BKE_icons.h"
@@ -74,6 +75,7 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -98,6 +100,7 @@
#define NODE_DEFAULT_MAX_WIDTH 700
using blender::Array;
+using blender::Map;
using blender::MutableSpan;
using blender::Set;
using blender::Span;
@@ -151,62 +154,42 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
BLI_listbase_clear(&ntree_dst->nodes);
BLI_listbase_clear(&ntree_dst->links);
- /* Since source nodes and sockets are unique pointers we can put everything in a single map. */
- GHash *new_pointers = BLI_ghash_ptr_new(__func__);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
- LISTBASE_FOREACH (const bNode *, node_src, &ntree_src->nodes) {
- bNode *new_node = BKE_node_copy_ex(ntree_dst, node_src, flag_subdata, true);
- BLI_ghash_insert(new_pointers, (void *)node_src, new_node);
- /* Store mapping to inputs. */
- bNodeSocket *new_input_sock = (bNodeSocket *)new_node->inputs.first;
- const bNodeSocket *input_sock_src = (const bNodeSocket *)node_src->inputs.first;
- while (new_input_sock != nullptr) {
- BLI_ghash_insert(new_pointers, (void *)input_sock_src, new_input_sock);
- new_input_sock = new_input_sock->next;
- input_sock_src = input_sock_src->next;
- }
- /* Store mapping to outputs. */
- bNodeSocket *new_output_sock = (bNodeSocket *)new_node->outputs.first;
- const bNodeSocket *output_sock_src = (const bNodeSocket *)node_src->outputs.first;
- while (new_output_sock != nullptr) {
- BLI_ghash_insert(new_pointers, (void *)output_sock_src, new_output_sock);
- new_output_sock = new_output_sock->next;
- output_sock_src = output_sock_src->next;
- }
+ BLI_listbase_clear(&ntree_dst->nodes);
+ LISTBASE_FOREACH (const bNode *, src_node, &ntree_src->nodes) {
+ /* Don't find a unique name for every node, since they should have valid names already. */
+ bNode *new_node = blender::bke::node_copy_with_mapping(
+ ntree_dst, *src_node, flag_subdata, false, socket_map);
+ node_map.add(src_node, new_node);
}
/* copy links */
- BLI_duplicatelist(&ntree_dst->links, &ntree_src->links);
- LISTBASE_FOREACH (bNodeLink *, link_dst, &ntree_dst->links) {
- link_dst->fromnode = (bNode *)BLI_ghash_lookup_default(
- new_pointers, link_dst->fromnode, nullptr);
- link_dst->fromsock = (bNodeSocket *)BLI_ghash_lookup_default(
- new_pointers, link_dst->fromsock, nullptr);
- link_dst->tonode = (bNode *)BLI_ghash_lookup_default(new_pointers, link_dst->tonode, nullptr);
- link_dst->tosock = (bNodeSocket *)BLI_ghash_lookup_default(
- new_pointers, link_dst->tosock, nullptr);
- /* update the link socket's pointer */
- if (link_dst->tosock) {
- link_dst->tosock->link = link_dst;
- }
+ BLI_listbase_clear(&ntree_dst->links);
+ LISTBASE_FOREACH (const bNodeLink *, src_link, &ntree_src->links) {
+ bNodeLink *dst_link = (bNodeLink *)MEM_dupallocN(src_link);
+ dst_link->fromnode = node_map.lookup(src_link->fromnode);
+ dst_link->fromsock = socket_map.lookup(src_link->fromsock);
+ dst_link->tonode = node_map.lookup(src_link->tonode);
+ dst_link->tosock = socket_map.lookup(src_link->tosock);
+ BLI_assert(dst_link->tosock);
+ dst_link->tosock->link = dst_link;
+ BLI_addtail(&ntree_dst->links, dst_link);
}
/* copy interface sockets */
- BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs);
- bNodeSocket *sock_dst, *sock_src;
- for (sock_dst = (bNodeSocket *)ntree_dst->inputs.first,
- sock_src = (bNodeSocket *)ntree_src->inputs.first;
- sock_dst != nullptr;
- sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) {
- node_socket_copy(sock_dst, sock_src, flag_subdata);
+ BLI_listbase_clear(&ntree_dst->inputs);
+ LISTBASE_FOREACH (const bNodeSocket *, src_socket, &ntree_src->inputs) {
+ bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket);
+ node_socket_copy(dst_socket, src_socket, flag_subdata);
+ BLI_addtail(&ntree_dst->inputs, dst_socket);
}
-
- BLI_duplicatelist(&ntree_dst->outputs, &ntree_src->outputs);
- for (sock_dst = (bNodeSocket *)ntree_dst->outputs.first,
- sock_src = (bNodeSocket *)ntree_src->outputs.first;
- sock_dst != nullptr;
- sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) {
- node_socket_copy(sock_dst, sock_src, flag_subdata);
+ BLI_listbase_clear(&ntree_dst->outputs);
+ LISTBASE_FOREACH (const bNodeSocket *, src_socket, &ntree_src->outputs) {
+ bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket);
+ node_socket_copy(dst_socket, src_socket, flag_subdata);
+ BLI_addtail(&ntree_dst->outputs, dst_socket);
}
/* copy preview hash */
@@ -226,18 +209,11 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
}
/* update node->parent pointers */
- for (bNode *node_dst = (bNode *)ntree_dst->nodes.first,
- *node_src = (bNode *)ntree_src->nodes.first;
- node_dst;
- node_dst = (bNode *)node_dst->next, node_src = (bNode *)node_src->next) {
- if (node_dst->parent) {
- node_dst->parent = (bNode *)BLI_ghash_lookup_default(
- new_pointers, node_dst->parent, nullptr);
+ LISTBASE_FOREACH (bNode *, new_node, &ntree_dst->nodes) {
+ if (new_node->parent) {
+ new_node->parent = node_map.lookup(new_node->parent);
}
}
-
- BLI_ghash_free(new_pointers, nullptr, nullptr);
-
/* node tree will generate its own interface type */
ntree_dst->interface_type = nullptr;
@@ -261,8 +237,7 @@ static void ntree_free_data(ID *id)
/* XXX hack! node trees should not store execution graphs at all.
* This should be removed when old tree types no longer require it.
* Currently the execution data for texture nodes remains in the tree
- * after execution, until the node tree is updated or freed.
- */
+ * after execution, until the node tree is updated or freed. */
if (ntree->execdata) {
switch (ntree->type) {
case NTREE_SHADER:
@@ -278,10 +253,10 @@ static void ntree_free_data(ID *id)
/* XXX not nice, but needed to free localized node groups properly */
free_localized_node_groups(ntree);
- /* unregister associated RNA types */
+ /* Unregister associated RNA types. */
ntreeInterfaceTypeFree(ntree);
- BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */
+ BLI_freelistN(&ntree->links);
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
node_free_node(ntree, node);
@@ -522,7 +497,6 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so
static void write_node_socket(BlendWriter *writer, bNodeSocket *sock)
{
- /* actual socket writing */
BLO_write_struct(writer, bNodeSocket, sock);
if (sock->prop) {
@@ -533,7 +507,6 @@ static void write_node_socket(BlendWriter *writer, bNodeSocket *sock)
}
static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock)
{
- /* actual socket writing */
BLO_write_struct(writer, bNodeSocket, sock);
if (sock->prop) {
@@ -547,8 +520,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
{
BKE_id_blend_write(writer, &ntree->id);
- /* for link_list() speed, we write per list */
-
if (ntree->adt) {
BKE_animdata_blend_write(writer, ntree->adt);
}
@@ -572,7 +543,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
}
if (node->storage) {
- /* could be handlerized at some point, now only 1 exception still */
if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) &&
ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) {
BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage);
@@ -646,13 +616,13 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
}
if (node->type == CMP_NODE_OUTPUT_FILE) {
- /* inputs have own storage data */
+ /* Inputs have their own storage data. */
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
BLO_write_struct(writer, NodeImageMultiFileSocket, sock->storage);
}
}
if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) {
- /* write extra socket info */
+ /* Write extra socket info. */
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
BLO_write_struct(writer, NodeImageLayer, sock->storage);
}
@@ -716,6 +686,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
ntree->execdata = nullptr;
ntree->field_inferencing_interface = nullptr;
+ BKE_ntree_update_tag_missing_runtime_data(ntree);
BLO_read_data_address(reader, &ntree->adt);
BKE_animdata_blend_read_data(reader, ntree->adt);
@@ -748,7 +719,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
}
if (node->storage) {
- /* could be handlerized at some point */
switch (node->type) {
case SH_NODE_CURVE_VEC:
case SH_NODE_CURVE_RGB:
@@ -859,11 +829,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
/* TODO: should be dealt by new generic cache handling of IDs... */
ntree->previews = nullptr;
- if (ntree->type == NTREE_GEOMETRY) {
- /* Update field referencing for the geometry nodes modifier. */
- ntree->update |= NTREE_UPDATE_FIELD_INFERENCING;
- }
-
BLO_read_data_address(reader, &ntree->preview);
BKE_previewimg_blend_read(reader, ntree->preview);
@@ -1096,21 +1061,18 @@ static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType
return;
}
bNodeSocketTemplate *sockdef;
- /* bNodeSocket *sock; */ /* UNUSED */
if (ntype->inputs) {
sockdef = ntype->inputs;
while (sockdef->type != -1) {
- /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_IN);
-
+ node_add_socket_from_template(ntree, node, sockdef, SOCK_IN);
sockdef++;
}
}
if (ntype->outputs) {
sockdef = ntype->outputs;
while (sockdef->type != -1) {
- /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT);
-
+ node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT);
sockdef++;
}
}
@@ -1168,8 +1130,7 @@ static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr);
/* XXX Warning: context can be nullptr in case nodes are added in do_versions.
- * Delayed init is not supported for nodes with context-based `initfunc_api` at the moment.
- */
+ * Delayed init is not supported for nodes with context-based `initfunc_api` at the moment. */
BLI_assert(C != nullptr);
ntype->initfunc_api(C, &ptr);
}
@@ -1190,6 +1151,7 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo)
/* Deprecated integer type. */
ntree->type = ntree->typeinfo->type;
+ BKE_ntree_update_tag_all(ntree);
}
static void node_set_typeinfo(const struct bContext *C,
@@ -1240,6 +1202,7 @@ static void node_socket_set_typeinfo(bNodeTree *ntree,
ntree->init &= ~NTREE_TYPE_INIT;
}
+ BKE_ntree_update_tag_socket_type(ntree, sock);
}
/* Set specific typeinfo pointers in all node trees on register/unregister */
@@ -1383,18 +1346,6 @@ bNodeType *nodeTypeFind(const char *idname)
return nullptr;
}
-static void free_dynamic_typeinfo(bNodeType *ntype)
-{
- if (ntype->type == NODE_DYNAMIC) {
- if (ntype->inputs) {
- MEM_freeN(ntype->inputs);
- }
- if (ntype->outputs) {
- MEM_freeN(ntype->outputs);
- }
- }
-}
-
/* callback for hash value free function */
static void node_free_type(void *nodetype_v)
{
@@ -1404,11 +1355,6 @@ static void node_free_type(void *nodetype_v)
* or we'd want to update *all* active Mains, which we cannot do anyway currently. */
update_typeinfo(G_MAIN, nullptr, nullptr, nodetype, nullptr, true);
- /* XXX deprecated */
- if (nodetype->type == NODE_DYNAMIC) {
- free_dynamic_typeinfo(nodetype);
- }
-
delete nodetype->fixed_declaration;
nodetype->fixed_declaration = nullptr;
@@ -1580,11 +1526,11 @@ static bNodeSocket *make_socket(bNodeTree *ntree,
/* if no explicit identifier is given, assign a unique identifier based on the name */
BLI_strncpy(auto_identifier, name, sizeof(auto_identifier));
}
- /* make the identifier unique */
+ /* Make the identifier unique. */
BLI_uniquename_cb(
unique_identifier_check, lb, "socket", '_', auto_identifier, sizeof(auto_identifier));
- bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "sock");
+ bNodeSocket *sock = MEM_cnew<bNodeSocket>("sock");
sock->in_out = in_out;
BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR);
@@ -1749,7 +1695,7 @@ bNodeSocket *nodeAddSocket(bNodeTree *ntree,
BLI_remlink(lb, sock); /* does nothing for new socket */
BLI_addtail(lb, sock);
- node->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_socket_new(ntree, sock);
return sock;
}
@@ -1768,8 +1714,6 @@ bNodeSocket *nodeInsertSocket(bNodeTree *ntree,
BLI_remlink(lb, sock); /* does nothing for new socket */
BLI_insertlinkbefore(lb, next_sock, sock);
- node->update |= NODE_UPDATE;
-
return sock;
}
@@ -2010,10 +1954,7 @@ bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree,
return sock;
}
-static void node_socket_free(bNodeTree *UNUSED(ntree),
- bNodeSocket *sock,
- bNode *UNUSED(node),
- const bool do_id_user)
+static void node_socket_free(bNodeSocket *sock, const bool do_id_user)
{
if (sock->prop) {
IDP_FreePropertyContent_ex(sock->prop, do_id_user);
@@ -2048,10 +1989,10 @@ void nodeRemoveSocketEx(struct bNodeTree *ntree,
BLI_remlink(&node->inputs, sock);
BLI_remlink(&node->outputs, sock);
- node_socket_free(ntree, sock, node, do_id_user);
+ node_socket_free(sock, do_id_user);
MEM_freeN(sock);
- node->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_socket_removed(ntree);
}
void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
@@ -2063,18 +2004,18 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node)
}
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) {
- node_socket_free(ntree, sock, node, true);
+ node_socket_free(sock, true);
MEM_freeN(sock);
}
BLI_listbase_clear(&node->inputs);
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) {
- node_socket_free(ntree, sock, node, true);
+ node_socket_free(sock, true);
MEM_freeN(sock);
}
BLI_listbase_clear(&node->outputs);
- node->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_socket_removed(ntree);
}
bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name)
@@ -2220,13 +2161,17 @@ void nodeUniqueName(bNodeTree *ntree, bNode *node)
bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idname)
{
- bNode *node = (bNode *)MEM_callocN(sizeof(bNode), "new node");
+ bNode *node = MEM_cnew<bNode>("new node");
BLI_addtail(&ntree->nodes, node);
BLI_strncpy(node->idname, idname, sizeof(node->idname));
node_set_typeinfo(C, ntree, node, nodeTypeFind(idname));
- ntree->update |= NTREE_UPDATE_NODES;
+ BKE_ntree_update_tag_node_new(ntree, node);
+
+ if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
+ DEG_relations_tag_update(CTX_data_main(C));
+ }
return node;
}
@@ -2236,9 +2181,8 @@ bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type)
const char *idname = nullptr;
NODE_TYPES_BEGIN (ntype) {
- /* do an extra poll here, because some int types are used
- * for multiple node types, this helps find the desired type
- */
+ /* Do an extra poll here, because some int types are used
+ * for multiple node types, this helps find the desired type. */
const char *disabled_hint;
if (ntype->type == type && (!ntype->poll || ntype->poll(ntype, ntree, &disabled_hint))) {
idname = ntype->idname;
@@ -2268,142 +2212,105 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src,
}
sock_dst->stack_index = 0;
- /* XXX some compositor node (e.g. image, render layers) still store
- * some persistent buffer data here, need to clear this to avoid dangling pointers.
- */
+ /* XXX some compositor nodes (e.g. image, render layers) still store
+ * some persistent buffer data here, need to clear this to avoid dangling pointers. */
sock_dst->cache = nullptr;
}
-bNode *BKE_node_copy_ex(bNodeTree *ntree,
- const bNode *node_src,
- const int flag,
- const bool unique_name)
-{
- bNode *node_dst = (bNode *)MEM_callocN(sizeof(bNode), "dupli node");
- bNodeSocket *sock_dst, *sock_src;
- bNodeLink *link_dst, *link_src;
+namespace blender::bke {
- *node_dst = *node_src;
+bNode *node_copy_with_mapping(bNodeTree *dst_tree,
+ const bNode &node_src,
+ const int flag,
+ const bool unique_name,
+ Map<const bNodeSocket *, bNodeSocket *> &socket_map)
+{
+ bNode *node_dst = (bNode *)MEM_mallocN(sizeof(bNode), __func__);
+ *node_dst = node_src;
- /* can be called for nodes outside a node tree (e.g. clipboard) */
- if (ntree) {
+ /* Can be called for nodes outside a node tree (e.g. clipboard). */
+ if (dst_tree) {
if (unique_name) {
- nodeUniqueName(ntree, node_dst);
+ nodeUniqueName(dst_tree, node_dst);
}
-
- BLI_addtail(&ntree->nodes, node_dst);
+ BLI_addtail(&dst_tree->nodes, node_dst);
}
- BLI_duplicatelist(&node_dst->inputs, &node_src->inputs);
- for (sock_dst = (bNodeSocket *)node_dst->inputs.first,
- sock_src = (bNodeSocket *)node_src->inputs.first;
- sock_dst != nullptr;
- sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) {
- node_socket_copy(sock_dst, sock_src, flag);
+ BLI_listbase_clear(&node_dst->inputs);
+ LISTBASE_FOREACH (const bNodeSocket *, src_socket, &node_src.inputs) {
+ bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket);
+ node_socket_copy(dst_socket, src_socket, flag);
+ BLI_addtail(&node_dst->inputs, dst_socket);
+ socket_map.add_new(src_socket, dst_socket);
}
- BLI_duplicatelist(&node_dst->outputs, &node_src->outputs);
- for (sock_dst = (bNodeSocket *)node_dst->outputs.first,
- sock_src = (bNodeSocket *)node_src->outputs.first;
- sock_dst != nullptr;
- sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) {
- node_socket_copy(sock_dst, sock_src, flag);
+ BLI_listbase_clear(&node_dst->outputs);
+ LISTBASE_FOREACH (const bNodeSocket *, src_socket, &node_src.outputs) {
+ bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket);
+ node_socket_copy(dst_socket, src_socket, flag);
+ BLI_addtail(&node_dst->outputs, dst_socket);
+ socket_map.add_new(src_socket, dst_socket);
}
- if (node_src->prop) {
- node_dst->prop = IDP_CopyProperty_ex(node_src->prop, flag);
+ if (node_src.prop) {
+ node_dst->prop = IDP_CopyProperty_ex(node_src.prop, flag);
}
- BLI_duplicatelist(&node_dst->internal_links, &node_src->internal_links);
- for (link_dst = (bNodeLink *)node_dst->internal_links.first,
- link_src = (bNodeLink *)node_src->internal_links.first;
- link_dst != nullptr;
- link_dst = (bNodeLink *)link_dst->next, link_src = (bNodeLink *)link_src->next) {
- /* This is a bit annoying to do index lookups in a list, but is likely to be faster than
- * trying to create a hash-map. At least for usual nodes, which only have so much sockets
- * and internal links. */
- const int from_sock_index = BLI_findindex(&node_src->inputs, link_src->fromsock);
- const int to_sock_index = BLI_findindex(&node_src->outputs, link_src->tosock);
- BLI_assert(from_sock_index != -1);
- BLI_assert(to_sock_index != -1);
- link_dst->fromnode = node_dst;
- link_dst->tonode = node_dst;
- link_dst->fromsock = (bNodeSocket *)BLI_findlink(&node_dst->inputs, from_sock_index);
- link_dst->tosock = (bNodeSocket *)BLI_findlink(&node_dst->outputs, to_sock_index);
+ BLI_listbase_clear(&node_dst->internal_links);
+ LISTBASE_FOREACH (const bNodeLink *, src_link, &node_src.internal_links) {
+ bNodeLink *dst_link = (bNodeLink *)MEM_dupallocN(src_link);
+ dst_link->fromnode = node_dst;
+ dst_link->tonode = node_dst;
+ dst_link->fromsock = socket_map.lookup(src_link->fromsock);
+ dst_link->tosock = socket_map.lookup(src_link->tosock);
+ BLI_addtail(&node_dst->internal_links, dst_link);
}
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
id_us_plus(node_dst->id);
}
- if (node_src->typeinfo->copyfunc) {
- node_src->typeinfo->copyfunc(ntree, node_dst, node_src);
+ if (node_src.typeinfo->copyfunc) {
+ node_src.typeinfo->copyfunc(dst_tree, node_dst, &node_src);
}
- node_dst->new_node = nullptr;
-
/* Only call copy function when a copy is made for the main database, not
* for cases like the dependency graph and localization. */
if (node_dst->typeinfo->copyfunc_api && !(flag & LIB_ID_CREATE_NO_MAIN)) {
PointerRNA ptr;
- RNA_pointer_create((ID *)ntree, &RNA_Node, node_dst, &ptr);
+ RNA_pointer_create((ID *)dst_tree, &RNA_Node, node_dst, &ptr);
- node_dst->typeinfo->copyfunc_api(&ptr, node_src);
+ node_dst->typeinfo->copyfunc_api(&ptr, &node_src);
}
- if (ntree) {
- ntree->update |= NTREE_UPDATE_NODES;
+ if (dst_tree) {
+ BKE_ntree_update_tag_node_new(dst_tree, node_dst);
}
/* Reset the declaration of the new node. */
node_dst->declaration = nullptr;
- nodeDeclarationEnsure(ntree, node_dst);
+ nodeDeclarationEnsure(dst_tree, node_dst);
return node_dst;
}
-static void node_set_new_pointers(bNode *node_src, bNode *new_node)
+bNode *node_copy(bNodeTree *dst_tree,
+ const bNode &src_node,
+ const int flag,
+ const bool unique_name)
{
- /* Store mapping to the node itself. */
- node_src->new_node = new_node;
- /* Store mapping to inputs. */
- bNodeSocket *new_input_sock = (bNodeSocket *)new_node->inputs.first;
- bNodeSocket *input_sock_src = (bNodeSocket *)node_src->inputs.first;
- while (new_input_sock != nullptr) {
- input_sock_src->new_sock = new_input_sock;
- new_input_sock = new_input_sock->next;
- input_sock_src = input_sock_src->next;
- }
- /* Store mapping to outputs. */
- bNodeSocket *new_output_sock = (bNodeSocket *)new_node->outputs.first;
- bNodeSocket *output_sock_src = (bNodeSocket *)node_src->outputs.first;
- while (new_output_sock != nullptr) {
- output_sock_src->new_sock = new_output_sock;
- new_output_sock = new_output_sock->next;
- output_sock_src = output_sock_src->next;
- }
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+ return node_copy_with_mapping(dst_tree, src_node, flag, unique_name, socket_map);
}
-bNode *BKE_node_copy_store_new_pointers(bNodeTree *ntree, bNode *node_src, const int flag)
-{
- bNode *new_node = BKE_node_copy_ex(ntree, node_src, flag, true);
- node_set_new_pointers(node_src, new_node);
- return new_node;
-}
+} // namespace blender::bke
-bNodeTree *ntreeCopyTree_ex_new_pointers(const bNodeTree *ntree,
- Main *bmain,
- const bool do_id_user)
+bNode *BKE_node_copy(bNodeTree *dst_tree,
+ const bNode *src_node,
+ const int flag,
+ const bool unique_name)
{
- bNodeTree *new_ntree = ntreeCopyTree_ex(ntree, bmain, do_id_user);
- bNode *new_node = (bNode *)new_ntree->nodes.first;
- bNode *node_src = (bNode *)ntree->nodes.first;
- while (new_node != nullptr) {
- node_set_new_pointers(node_src, new_node);
- new_node = new_node->next;
- node_src = node_src->next;
- }
- return new_ntree;
+ return blender::bke::node_copy(dst_tree, *src_node, flag, unique_name);
}
static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket)
@@ -2422,12 +2329,12 @@ bNodeLink *nodeAddLink(
{
bNodeLink *link = nullptr;
- /* test valid input */
+ /* Test valid input. */
BLI_assert(fromnode);
BLI_assert(tonode);
if (fromsock->in_out == SOCK_OUT && tosock->in_out == SOCK_IN) {
- link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "link");
+ link = MEM_cnew<bNodeLink>("link");
if (ntree) {
BLI_addtail(&ntree->links, link);
}
@@ -2438,7 +2345,7 @@ bNodeLink *nodeAddLink(
}
else if (fromsock->in_out == SOCK_IN && tosock->in_out == SOCK_OUT) {
/* OK but flip */
- link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "link");
+ link = MEM_cnew<bNodeLink>("link");
if (ntree) {
BLI_addtail(&ntree->links, link);
}
@@ -2449,7 +2356,7 @@ bNodeLink *nodeAddLink(
}
if (ntree) {
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_added(ntree, link);
}
if (link != nullptr && link->tosock->flag & SOCK_MULTI_INPUT) {
@@ -2461,7 +2368,7 @@ bNodeLink *nodeAddLink(
void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
{
- /* can be called for links outside a node tree (e.g. clipboard) */
+ /* Can be called for links outside a node tree (e.g. clipboard). */
if (ntree) {
BLI_remlink(&ntree->links, link);
}
@@ -2472,7 +2379,7 @@ void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
MEM_freeN(link);
if (ntree) {
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_removed(ntree);
}
}
@@ -2572,7 +2479,7 @@ void nodeMuteLinkToggle(bNodeTree *ntree, bNodeLink *link)
}
if (ntree) {
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_mute(ntree, link);
}
}
@@ -2583,8 +2490,6 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
nodeRemLink(ntree, link);
}
}
-
- ntree->update |= NTREE_UPDATE_LINKS;
}
bool nodeLinkIsHidden(const bNodeLink *link)
@@ -2649,7 +2554,7 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
link->flag |= NODE_LINK_MUTED;
}
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_changed(ntree);
}
else {
if (link->tosock->flag & SOCK_MULTI_INPUT) {
@@ -2843,13 +2748,16 @@ bool BKE_node_preview_used(const bNode *node)
return (node->typeinfo->flag & NODE_PREVIEW) != 0;
}
-bNodePreview *BKE_node_preview_verify(
- bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create)
+bNodePreview *BKE_node_preview_verify(bNodeInstanceHash *previews,
+ bNodeInstanceKey key,
+ const int xsize,
+ const int ysize,
+ const bool create)
{
bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key);
if (!preview) {
if (create) {
- preview = (bNodePreview *)MEM_callocN(sizeof(bNodePreview), "node preview");
+ preview = MEM_cnew<bNodePreview>("node preview");
BKE_node_instance_hash_insert(previews, key, preview);
}
else {
@@ -2901,9 +2809,8 @@ void BKE_node_preview_free(bNodePreview *preview)
static void node_preview_init_tree_recursive(bNodeInstanceHash *previews,
bNodeTree *ntree,
bNodeInstanceKey parent_key,
- int xsize,
- int ysize,
- bool create_previews)
+ const int xsize,
+ const int ysize)
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node);
@@ -2912,17 +2819,16 @@ static void node_preview_init_tree_recursive(bNodeInstanceHash *previews,
node->preview_xsize = xsize;
node->preview_ysize = ysize;
- BKE_node_preview_verify(previews, key, xsize, ysize, create_previews);
+ BKE_node_preview_verify(previews, key, xsize, ysize, false);
}
if (node->type == NODE_GROUP && node->id) {
- node_preview_init_tree_recursive(
- previews, (bNodeTree *)node->id, key, xsize, ysize, create_previews);
+ node_preview_init_tree_recursive(previews, (bNodeTree *)node->id, key, xsize, ysize);
}
}
}
-void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, bool create_previews)
+void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize)
{
if (!ntree) {
return;
@@ -2932,8 +2838,7 @@ void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, bool cre
ntree->previews = BKE_node_instance_hash_new("node previews");
}
- node_preview_init_tree_recursive(
- ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize, create_previews);
+ node_preview_init_tree_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize);
}
static void node_preview_tag_used_recursive(bNodeInstanceHash *previews,
@@ -2999,40 +2904,6 @@ void BKE_node_preview_clear_tree(bNodeTree *ntree)
}
}
-static void node_preview_sync(bNodePreview *to, bNodePreview *from)
-{
- /* sizes should have been initialized by BKE_node_preview_init_tree */
- BLI_assert(to->xsize == from->xsize && to->ysize == from->ysize);
-
- /* copy over contents of previews */
- if (to->rect && from->rect) {
- int xsize = to->xsize;
- int ysize = to->ysize;
- memcpy(to->rect, from->rect, xsize * ysize * sizeof(char[4]));
- }
-}
-
-void BKE_node_preview_sync_tree(bNodeTree *to_ntree, bNodeTree *from_ntree)
-{
- bNodeInstanceHash *from_previews = from_ntree->previews;
- bNodeInstanceHash *to_previews = to_ntree->previews;
-
- if (!from_previews || !to_previews) {
- return;
- }
-
- bNodeInstanceHashIterator iter;
- NODE_INSTANCE_HASH_ITER (iter, from_previews) {
- bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter);
- bNodePreview *from = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter);
- bNodePreview *to = (bNodePreview *)BKE_node_instance_hash_lookup(to_previews, key);
-
- if (from && to) {
- node_preview_sync(to, from);
- }
- }
-}
-
void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, bool remove_old)
{
if (remove_old || !to_ntree->previews) {
@@ -3069,27 +2940,6 @@ void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, boo
}
}
-void BKE_node_preview_set_pixel(
- bNodePreview *preview, const float col[4], int x, int y, bool do_manage)
-{
- if (preview) {
- if (x >= 0 && y >= 0) {
- if (x < preview->xsize && y < preview->ysize) {
- unsigned char *tar = preview->rect + 4 * ((preview->xsize * y) + x);
-
- if (do_manage) {
- linearrgb_to_srgb_uchar4(tar, col);
- }
- else {
- rgba_float_to_uchar(tar, col);
- }
- }
- // else printf("prv out bound x y %d %d\n", x, y);
- }
- // else printf("prv out bound x y %d %d\n", x, y);
- }
-}
-
/* ************** Free stuff ********** */
void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
@@ -3098,9 +2948,6 @@ void nodeUnlinkNode(bNodeTree *ntree, bNode *node)
ListBase *lb;
if (link->fromnode == node) {
lb = &node->outputs;
- if (link->tonode) {
- link->tonode->update |= NODE_UPDATE;
- }
}
else if (link->tonode == node) {
lb = &node->inputs;
@@ -3142,10 +2989,6 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
/* can be called for nodes outside a node tree (e.g. clipboard) */
if (ntree) {
- /* remove all references to this node */
- nodeUnlinkNode(ntree, node);
- node_unlink_attached(ntree, node);
-
BLI_remlink(&ntree->nodes, node);
if (ntree->typeinfo->free_node_cache) {
@@ -3165,12 +3008,12 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) {
/* Remember, no ID user refcount management here! */
- node_socket_free(ntree, sock, node, false);
+ node_socket_free(sock, false);
MEM_freeN(sock);
}
LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) {
/* Remember, no ID user refcount management here! */
- node_socket_free(ntree, sock, node, false);
+ node_socket_free(sock, false);
MEM_freeN(sock);
}
@@ -3189,7 +3032,7 @@ static void node_free_node(bNodeTree *ntree, bNode *node)
MEM_freeN(node);
if (ntree) {
- ntree->update |= NTREE_UPDATE_NODES;
+ BKE_ntree_update_tag_node_removed(ntree);
}
}
@@ -3197,6 +3040,12 @@ void ntreeFreeLocalNode(bNodeTree *ntree, bNode *node)
{
/* For removing nodes while editing localized node trees. */
BLI_assert((ntree->id.tag & LIB_TAG_LOCALIZED) != 0);
+
+ /* These two lines assume the caller might want to free a single node and maintain
+ * a valid state in the node tree. */
+ nodeUnlinkNode(ntree, node);
+ node_unlink_attached(ntree, node);
+
node_free_node(ntree, node);
}
@@ -3241,6 +3090,9 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
}
}
+ nodeUnlinkNode(ntree, node);
+ node_unlink_attached(ntree, node);
+
/* Free node itself. */
node_free_node(ntree, node);
}
@@ -3266,8 +3118,7 @@ static void free_localized_node_groups(bNodeTree *ntree)
/* Only localized node trees store a copy for each node group tree.
* Each node group tree in a localized node tree can be freed,
* since it is a localized copy itself (no risk of accessing free'd
- * data in main, see T37939).
- */
+ * data in main, see T37939). */
if (!(ntree->id.tag & LIB_TAG_LOCALIZED)) {
return;
}
@@ -3412,26 +3263,6 @@ bNodeTree *ntreeFromID(ID *id)
return (nodetree != nullptr) ? *nodetree : nullptr;
}
-bool ntreeNodeExists(const bNodeTree *ntree, const bNode *testnode)
-{
- LISTBASE_FOREACH (const bNode *, node, &ntree->nodes) {
- if (node == testnode) {
- return true;
- }
- }
- return false;
-}
-
-bool ntreeOutputExists(const bNode *node, const bNodeSocket *testsock)
-{
- LISTBASE_FOREACH (const bNodeSocket *, sock, &node->outputs) {
- if (sock == testsock) {
- return true;
- }
- }
- return false;
-}
-
void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable)
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -3463,7 +3294,7 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
}
}
- /* ensures only a single output node is enabled */
+ /* Ensures only a single output node is enabled. */
ntreeSetOutput(ntree);
bNode *node_src = (bNode *)ntree->nodes.first;
@@ -3481,15 +3312,6 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree)
return ltree;
}
-void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree)
-{
- if (localtree && ntree) {
- if (ntree->typeinfo->local_sync) {
- ntree->typeinfo->local_sync(localtree, ntree);
- }
- }
-}
-
void ntreeLocalMerge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
{
if (ntree && localtree) {
@@ -3514,7 +3336,7 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree,
return nullptr;
}
- bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "socket template");
+ bNodeSocket *sock = MEM_cnew<bNodeSocket>("socket template");
BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname));
node_socket_set_typeinfo(ntree, sock, stype);
sock->in_out = in_out;
@@ -3560,12 +3382,11 @@ bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree,
bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name);
if (in_out == SOCK_IN) {
BLI_addtail(&ntree->inputs, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_IN;
}
else if (in_out == SOCK_OUT) {
BLI_addtail(&ntree->outputs, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_OUT;
}
+ BKE_ntree_update_tag_interface(ntree);
return iosock;
}
@@ -3578,12 +3399,11 @@ bNodeSocket *ntreeInsertSocketInterface(bNodeTree *ntree,
bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name);
if (in_out == SOCK_IN) {
BLI_insertlinkbefore(&ntree->inputs, next_sock, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_IN;
}
else if (in_out == SOCK_OUT) {
BLI_insertlinkbefore(&ntree->outputs, next_sock, iosock);
- ntree->update |= NTREE_UPDATE_GROUP_OUT;
}
+ BKE_ntree_update_tag_interface(ntree);
return iosock;
}
@@ -3629,7 +3449,7 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock)
node_socket_interface_free(ntree, sock, true);
MEM_freeN(sock);
- ntree->update |= NTREE_UPDATE_GROUP;
+ BKE_ntree_update_tag_interface(ntree);
}
/* generates a valid RNA identifier from the node tree name */
@@ -3973,10 +3793,13 @@ int nodeSocketIsHidden(const bNodeSocket *sock)
return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0);
}
-void nodeSetSocketAvailability(bNodeTree *UNUSED(ntree), bNodeSocket *sock, bool is_available)
+void nodeSetSocketAvailability(bNodeTree *ntree, bNodeSocket *sock, bool is_available)
{
- /* #ntree is not needed right now, but it's generally necessary when changing the tree because we
- * want to tag it as changed in the future. */
+ const bool was_available = (sock->flag & SOCK_UNAVAIL) == 0;
+ if (is_available != was_available) {
+ BKE_ntree_update_tag_socket_availability(ntree, sock);
+ }
+
if (is_available) {
sock->flag &= ~SOCK_UNAVAIL;
}
@@ -4428,7 +4251,7 @@ void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***r_deplist,
}
/* only updates node->level for detecting cycles links */
-static void ntree_update_node_level(bNodeTree *ntree)
+void ntreeUpdateNodeLevels(bNodeTree *ntree)
{
/* first clear tag */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
@@ -4443,769 +4266,42 @@ static void ntree_update_node_level(bNodeTree *ntree)
}
}
-void ntreeTagUsedSockets(bNodeTree *ntree)
-{
- /* first clear data */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- sock->flag &= ~SOCK_IN_USE;
- }
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
- sock->flag &= ~SOCK_IN_USE;
- }
- }
-
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- link->fromsock->flag |= SOCK_IN_USE;
- if (!(link->flag & NODE_LINK_MUTED)) {
- link->tosock->flag |= SOCK_IN_USE;
- }
- }
-}
-
-static void ntree_update_link_pointers(bNodeTree *ntree)
-{
- /* first clear data */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- sock->link = nullptr;
- }
- }
-
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- link->tosock->link = link;
- }
-
- ntreeTagUsedSockets(ntree);
-}
-
-static void ntree_validate_links(bNodeTree *ntree)
-{
- LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- link->flag |= NODE_LINK_VALID;
- if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level) {
- link->flag &= ~NODE_LINK_VALID;
- }
- else if (ntree->typeinfo->validate_link) {
- if (!ntree->typeinfo->validate_link((eNodeSocketDatatype)link->fromsock->type,
- (eNodeSocketDatatype)link->tosock->type)) {
- link->flag &= ~NODE_LINK_VALID;
- }
- }
- }
-}
-
void ntreeUpdateAllNew(Main *main)
{
+ Vector<bNodeTree *> new_ntrees;
+
/* Update all new node trees on file read or append, to add/remove sockets
* in groups nodes if the group changed, and handle any update flags that
* might have been set in file reading or versioning. */
FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
if (owner_id->tag & LIB_TAG_NEW) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->typeinfo->group_update_func) {
- node->typeinfo->group_update_func(ntree, node);
- }
- }
-
- ntreeUpdateTree(nullptr, ntree);
+ BKE_ntree_update_tag_all(ntree);
}
}
FOREACH_NODETREE_END;
+ BKE_ntree_update_main(main, nullptr);
}
-namespace blender::bke::node_field_inferencing {
-
-static bool is_field_socket_type(eNodeSocketDatatype type)
-{
- return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
-}
-
-static bool is_field_socket_type(const SocketRef &socket)
-{
- return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type);
-}
-
-static bool update_field_inferencing(bNodeTree &btree);
-
-static InputSocketFieldType get_interface_input_field_type(const NodeRef &node,
- const InputSocketRef &socket)
-{
- if (!is_field_socket_type(socket)) {
- return InputSocketFieldType::None;
- }
- if (node.is_reroute_node()) {
- return InputSocketFieldType::IsSupported;
- }
- if (node.is_group_output_node()) {
- /* Outputs always support fields when the data type is correct. */
- return InputSocketFieldType::IsSupported;
- }
- if (node.is_undefined()) {
- return InputSocketFieldType::None;
- }
-
- const NodeDeclaration *node_decl = node.declaration();
-
- /* Node declarations should be implemented for nodes involved here. */
- BLI_assert(node_decl != nullptr);
-
- /* Get the field type from the declaration. */
- const SocketDeclaration &socket_decl = *node_decl->inputs()[socket.index()];
- const InputSocketFieldType field_type = socket_decl.input_field_type();
- if (field_type == InputSocketFieldType::Implicit) {
- return field_type;
- }
- if (node_decl->is_function_node()) {
- /* In a function node, every socket supports fields. */
- return InputSocketFieldType::IsSupported;
- }
- return field_type;
-}
-
-static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node,
- const OutputSocketRef &socket)
-{
- if (!is_field_socket_type(socket)) {
- /* Non-field sockets always output data. */
- return OutputFieldDependency::ForDataSource();
- }
- if (node.is_reroute_node()) {
- /* The reroute just forwards what is passed in. */
- return OutputFieldDependency::ForDependentField();
- }
- if (node.is_group_input_node()) {
- /* Input nodes get special treatment in #determine_group_input_states. */
- return OutputFieldDependency::ForDependentField();
- }
- if (node.is_undefined()) {
- return OutputFieldDependency::ForDataSource();
- }
-
- const NodeDeclaration *node_decl = node.declaration();
-
- /* Node declarations should be implemented for nodes involved here. */
- BLI_assert(node_decl != nullptr);
-
- if (node_decl->is_function_node()) {
- /* In a generic function node, all outputs depend on all inputs. */
- return OutputFieldDependency::ForDependentField();
- }
-
- /* Use the socket declaration. */
- const SocketDeclaration &socket_decl = *node_decl->outputs()[socket.index()];
- return socket_decl.output_field_dependency();
-}
-
-static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node)
-{
- FieldInferencingInterface inferencing_interface;
- inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size());
- inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(),
- node.outputs().size());
- return inferencing_interface;
-}
-
-/**
- * Retrieves information about how the node interacts with fields.
- * In the future, this information can be stored in the node declaration. This would allow this
- * function to return a reference, making it more efficient.
- */
-static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node)
-{
- /* Node groups already reference all required information, so just return that. */
- if (node.is_group_node()) {
- bNodeTree *group = (bNodeTree *)node.bnode()->id;
- if (group == nullptr) {
- return FieldInferencingInterface();
- }
- if (!ntreeIsRegistered(group)) {
- /* This can happen when there is a linked node group that was not found (see T92799). */
- return get_dummy_field_inferencing_interface(node);
- }
- if (group->field_inferencing_interface == nullptr) {
- /* Update group recursively. */
- update_field_inferencing(*group);
- }
- return *group->field_inferencing_interface;
- }
-
- FieldInferencingInterface inferencing_interface;
- for (const InputSocketRef *input_socket : node.inputs()) {
- inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket));
- }
-
- for (const OutputSocketRef *output_socket : node.outputs()) {
- inferencing_interface.outputs.append(
- get_interface_output_field_dependency(node, *output_socket));
- }
- return inferencing_interface;
-}
-
-/**
- * This struct contains information for every socket. The values are propagated through the
- * network.
- */
-struct SocketFieldState {
- /* This socket starts a new field. */
- bool is_field_source = false;
- /* This socket can never become a field, because the node itself does not support it. */
- bool is_always_single = false;
- /* This socket is currently a single value. It could become a field though. */
- bool is_single = true;
- /* This socket is required to be a single value. This can be because the node itself only
- * supports this socket to be a single value, or because a node afterwards requires this to be a
- * single value. */
- bool requires_single = false;
-};
-
-static Vector<const InputSocketRef *> gather_input_socket_dependencies(
- const OutputFieldDependency &field_dependency, const NodeRef &node)
-{
- const OutputSocketFieldType type = field_dependency.field_type();
- Vector<const InputSocketRef *> input_sockets;
- switch (type) {
- case OutputSocketFieldType::FieldSource:
- case OutputSocketFieldType::None: {
- break;
- }
- case OutputSocketFieldType::DependentField: {
- /* This output depends on all inputs. */
- input_sockets.extend(node.inputs());
- break;
- }
- case OutputSocketFieldType::PartiallyDependent: {
- /* This output depends only on a few inputs. */
- for (const int i : field_dependency.linked_input_indices()) {
- input_sockets.append(&node.input(i));
- }
- break;
- }
- }
- return input_sockets;
-}
-
-/**
- * Check what the group output socket depends on. Potentially traverses the node tree
- * to figure out if it is always a field or if it depends on any group inputs.
- */
-static OutputFieldDependency find_group_output_dependencies(
- const InputSocketRef &group_output_socket,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- if (!is_field_socket_type(group_output_socket)) {
- return OutputFieldDependency::ForDataSource();
- }
-
- /* Use a Set here instead of an array indexed by socket id, because we my only need to look at
- * very few sockets. */
- Set<const InputSocketRef *> handled_sockets;
- Stack<const InputSocketRef *> sockets_to_check;
-
- handled_sockets.add(&group_output_socket);
- sockets_to_check.push(&group_output_socket);
-
- /* Keeps track of group input indices that are (indirectly) connected to the output. */
- Vector<int> linked_input_indices;
-
- while (!sockets_to_check.is_empty()) {
- const InputSocketRef *input_socket = sockets_to_check.pop();
-
- for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
- const NodeRef &origin_node = origin_socket->node();
- const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()];
-
- if (origin_state.is_field_source) {
- if (origin_node.is_group_input_node()) {
- /* Found a group input that the group output depends on. */
- linked_input_indices.append_non_duplicates(origin_socket->index());
- }
- else {
- /* Found a field source that is not the group input. So the output is always a field. */
- return OutputFieldDependency::ForFieldSource();
- }
- }
- else if (!origin_state.is_single) {
- const FieldInferencingInterface inferencing_interface =
- get_node_field_inferencing_interface(origin_node);
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[origin_socket->index()];
-
- /* Propagate search further to the left. */
- for (const InputSocketRef *origin_input_socket :
- gather_input_socket_dependencies(field_dependency, origin_node)) {
- if (!origin_input_socket->is_available()) {
- continue;
- }
- if (!field_state_by_socket_id[origin_input_socket->id()].is_single) {
- if (handled_sockets.add(origin_input_socket)) {
- sockets_to_check.push(origin_input_socket);
- }
- }
- }
- }
- }
- }
- return OutputFieldDependency::ForPartiallyDependentField(std::move(linked_input_indices));
-}
-
-static void propagate_data_requirements_from_right_to_left(
- const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
- NodeTreeRef::ToposortDirection::RightToLeft);
-
- for (const NodeRef *node : toposort_result.sorted_nodes) {
- const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
- *node);
-
- for (const OutputSocketRef *output_socket : node->outputs()) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
-
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[output_socket->index()];
-
- if (field_dependency.field_type() == OutputSocketFieldType::FieldSource) {
- continue;
- }
- if (field_dependency.field_type() == OutputSocketFieldType::None) {
- state.requires_single = true;
- state.is_always_single = true;
- continue;
- }
-
- /* The output is required to be a single value when it is connected to any input that does
- * not support fields. */
- for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) {
- if (target_socket->is_available()) {
- state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
- }
- }
-
- if (state.requires_single) {
- bool any_input_is_field_implicitly = false;
- const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies(
- field_dependency, *node);
- for (const InputSocketRef *input_socket : connected_inputs) {
- if (!input_socket->is_available()) {
- continue;
- }
- if (inferencing_interface.inputs[input_socket->index()] ==
- InputSocketFieldType::Implicit) {
- if (!input_socket->is_logically_linked()) {
- any_input_is_field_implicitly = true;
- break;
- }
- }
- }
- if (any_input_is_field_implicitly) {
- /* This output isn't a single value actually. */
- state.requires_single = false;
- }
- else {
- /* If the output is required to be a single value, the connected inputs in the same node
- * must not be fields as well. */
- for (const InputSocketRef *input_socket : connected_inputs) {
- field_state_by_socket_id[input_socket->id()].requires_single = true;
- }
- }
- }
- }
-
- /* Some inputs do not require fields independent of what the outputs are connected to. */
- for (const InputSocketRef *input_socket : node->inputs()) {
- SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
- if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) {
- state.requires_single = true;
- state.is_always_single = true;
- }
- }
- }
-}
-
-static void determine_group_input_states(
- const NodeTreeRef &tree,
- FieldInferencingInterface &new_inferencing_interface,
- const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- {
- /* Non-field inputs never support fields. */
- int index;
- LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) {
- if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) {
- new_inferencing_interface.inputs[index] = InputSocketFieldType::None;
- }
- }
- }
- /* Check if group inputs are required to be single values, because they are (indirectly)
- * connected to some socket that does not support fields. */
- for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
- for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- if (state.requires_single) {
- new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None;
- }
- }
- }
- /* If an input does not support fields, this should be reflected in all Group Input nodes. */
- for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
- for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] !=
- InputSocketFieldType::None;
- if (supports_field) {
- state.is_single = false;
- state.is_field_source = true;
- }
- else {
- state.requires_single = true;
- }
- }
- SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()];
- dummy_socket_state.requires_single = true;
- }
-}
-
-static void propagate_field_status_from_left_to_right(
- const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
-{
- const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
- NodeTreeRef::ToposortDirection::LeftToRight);
-
- for (const NodeRef *node : toposort_result.sorted_nodes) {
- if (node->is_group_input_node()) {
- continue;
- }
-
- const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
- *node);
-
- /* Update field state of input sockets, also taking into account linked origin sockets. */
- for (const InputSocketRef *input_socket : node->inputs()) {
- SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
- if (state.is_always_single) {
- state.is_single = true;
- continue;
- }
- state.is_single = true;
- if (input_socket->directly_linked_sockets().is_empty()) {
- if (inferencing_interface.inputs[input_socket->index()] ==
- InputSocketFieldType::Implicit) {
- state.is_single = false;
- }
- }
- else {
- for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
- if (!field_state_by_socket_id[origin_socket->id()].is_single) {
- state.is_single = false;
- break;
- }
- }
- }
- }
-
- /* Update field state of output sockets, also taking into account input sockets. */
- for (const OutputSocketRef *output_socket : node->outputs()) {
- SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
- const OutputFieldDependency &field_dependency =
- inferencing_interface.outputs[output_socket->index()];
-
- switch (field_dependency.field_type()) {
- case OutputSocketFieldType::None: {
- state.is_single = true;
- break;
- }
- case OutputSocketFieldType::FieldSource: {
- state.is_single = false;
- state.is_field_source = true;
- break;
- }
- case OutputSocketFieldType::PartiallyDependent:
- case OutputSocketFieldType::DependentField: {
- for (const InputSocketRef *input_socket :
- gather_input_socket_dependencies(field_dependency, *node)) {
- if (!input_socket->is_available()) {
- continue;
- }
- if (!field_state_by_socket_id[input_socket->id()].is_single) {
- state.is_single = false;
- break;
- }
- }
- break;
- }
- }
- }
- }
-}
-
-static void determine_group_output_states(const NodeTreeRef &tree,
- FieldInferencingInterface &new_inferencing_interface,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) {
- /* Ignore inactive group output nodes. */
- if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) {
- continue;
- }
- /* Determine dependencies of all group outputs. */
- for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) {
- OutputFieldDependency field_dependency = find_group_output_dependencies(
- *group_output_socket, field_state_by_socket_id);
- new_inferencing_interface.outputs[group_output_socket->index()] = std::move(
- field_dependency);
- }
- break;
- }
-}
-
-static void update_socket_shapes(const NodeTreeRef &tree,
- const Span<SocketFieldState> field_state_by_socket_id)
-{
- const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
- const eNodeSocketDisplayShape data_but_can_be_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND_DOT;
- const eNodeSocketDisplayShape is_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND;
-
- auto get_shape_for_state = [&](const SocketFieldState &state) {
- if (state.is_always_single) {
- return requires_data_shape;
- }
- if (!state.is_single) {
- return is_field_shape;
- }
- if (state.requires_single) {
- return requires_data_shape;
- }
- return data_but_can_be_field_shape;
- };
-
- for (const InputSocketRef *socket : tree.input_sockets()) {
- bNodeSocket *bsocket = socket->bsocket();
- const SocketFieldState &state = field_state_by_socket_id[socket->id()];
- bsocket->display_shape = get_shape_for_state(state);
- }
- for (const OutputSocketRef *socket : tree.output_sockets()) {
- bNodeSocket *bsocket = socket->bsocket();
- const SocketFieldState &state = field_state_by_socket_id[socket->id()];
- bsocket->display_shape = get_shape_for_state(state);
- }
-}
-
-static bool update_field_inferencing(bNodeTree &btree)
-{
- using namespace blender::nodes;
- if (btree.type != NTREE_GEOMETRY) {
- return false;
- }
-
- /* Create new inferencing interface for this node group. */
- FieldInferencingInterface *new_inferencing_interface = new FieldInferencingInterface();
- new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs),
- InputSocketFieldType::IsSupported);
- new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs),
- OutputFieldDependency::ForDataSource());
-
- /* Create #NodeTreeRef to accelerate various queries on the node tree (e.g. linked sockets). */
- const NodeTreeRef tree{&btree};
-
- /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */
- Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size());
-
- propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id);
- determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id);
- propagate_field_status_from_left_to_right(tree, field_state_by_socket_id);
- determine_group_output_states(tree, *new_inferencing_interface, field_state_by_socket_id);
- update_socket_shapes(tree, field_state_by_socket_id);
-
- /* Update the previous group interface. */
- const bool group_interface_changed = btree.field_inferencing_interface == nullptr ||
- *btree.field_inferencing_interface !=
- *new_inferencing_interface;
- delete btree.field_inferencing_interface;
- btree.field_inferencing_interface = new_inferencing_interface;
-
- return group_interface_changed;
-}
-
-} // namespace blender::bke::node_field_inferencing
-
-void ntreeUpdateAllUsers(Main *main, ID *id, const int tree_update_flag)
+void ntreeUpdateAllUsers(Main *main, ID *id)
{
if (id == nullptr) {
return;
}
+ bool need_update = false;
+
/* Update all users of ngroup, to add/remove sockets as needed. */
FOREACH_NODETREE_BEGIN (main, ntree, owner_id) {
- bool need_update = false;
-
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->id == id) {
- if (node->typeinfo->group_update_func) {
- node->typeinfo->group_update_func(ntree, node);
- }
-
+ BKE_ntree_update_tag_node_property(ntree, node);
need_update = true;
}
}
-
- if (need_update) {
- ntree->update |= tree_update_flag;
- ntreeUpdateTree(tree_update_flag ? main : nullptr, ntree);
- }
}
FOREACH_NODETREE_END;
-
- if (GS(id->name) == ID_NT) {
- bNodeTree *ngroup = (bNodeTree *)id;
- if (ngroup->type == NTREE_GEOMETRY && (ngroup->update & NTREE_UPDATE_GROUP)) {
- LISTBASE_FOREACH (Object *, object, &main->objects) {
- LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
- if (md->type == eModifierType_Nodes) {
- NodesModifierData *nmd = (NodesModifierData *)md;
- if (nmd->node_group == ngroup) {
- MOD_nodes_update_interface(object, nmd);
- }
- }
- }
- }
- }
- }
-}
-
-void ntreeUpdateTree(Main *bmain, bNodeTree *ntree)
-{
- if (!ntree) {
- return;
- }
-
- /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
- if (ntree->is_updating) {
- return;
- }
- ntree->is_updating = true;
-
- if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
- /* set the bNodeSocket->link pointers */
- ntree_update_link_pointers(ntree);
- }
-
- /* update individual nodes */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- /* node tree update tags override individual node update flags */
- if ((node->update & NODE_UPDATE) || (ntree->update & NTREE_UPDATE)) {
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
-
- nodeUpdateInternalLinks(ntree, node);
- }
- }
-
- /* generic tree update callback */
- if (ntree->typeinfo->update) {
- ntree->typeinfo->update(ntree);
- }
- /* XXX this should be moved into the tree type update callback for tree supporting node groups.
- * Currently the node tree interface is still a generic feature of the base NodeTree type.
- */
- if (ntree->update & NTREE_UPDATE_GROUP) {
- ntreeInterfaceTypeUpdate(ntree);
- }
-
- int tree_user_update_flag = 0;
-
- if (ntree->update & NTREE_UPDATE) {
- /* If the field interface of this node tree has changed, all node trees using
- * this group will need to recalculate their interface as well. */
- if (blender::bke::node_field_inferencing::update_field_inferencing(*ntree)) {
- tree_user_update_flag |= NTREE_UPDATE_FIELD_INFERENCING;
- }
- }
-
- if (bmain) {
- ntreeUpdateAllUsers(bmain, &ntree->id, tree_user_update_flag);
- }
-
- if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) {
- /* node updates can change sockets or links, repeat link pointer update afterward */
- ntree_update_link_pointers(ntree);
-
- /* update the node level from link dependencies */
- ntree_update_node_level(ntree);
-
- /* check link validity */
- ntree_validate_links(ntree);
- }
-
- /* clear update flags */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- node->update = 0;
- }
- ntree->update = 0;
-
- ntree->is_updating = false;
-}
-
-void nodeUpdate(bNodeTree *ntree, bNode *node)
-{
- /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
- if (ntree->is_updating) {
- return;
- }
- ntree->is_updating = true;
-
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
-
- nodeUpdateInternalLinks(ntree, node);
-
- /* clear update flag */
- node->update = 0;
-
- ntree->is_updating = false;
-}
-
-bool nodeUpdateID(bNodeTree *ntree, ID *id)
-{
- bool changed = false;
-
- if (ELEM(nullptr, id, ntree)) {
- return changed;
- }
-
- /* Avoid re-entrant updates, can be caused by RNA update callbacks. */
- if (ntree->is_updating) {
- return changed;
- }
- ntree->is_updating = true;
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->id == id) {
- changed = true;
- node->update |= NODE_UPDATE_ID;
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
- /* clear update flag */
- node->update = 0;
- }
- }
-
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- nodeUpdateInternalLinks(ntree, node);
- }
-
- ntree->is_updating = false;
- return changed;
-}
-
-void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node)
-{
- BLI_freelistN(&node->internal_links);
- if (!node->typeinfo->no_muting) {
- node_internal_links_create(ntree, node);
+ if (need_update) {
+ BKE_ntree_update_main(main, nullptr);
}
}
@@ -5261,8 +4357,7 @@ static bool node_poll_instance_default(bNode *node, bNodeTree *ntree, const char
return node->typeinfo->poll(node->typeinfo, ntree, disabled_hint);
}
-/* NOLINTNEXTLINE: readability-function-size */
-void node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
/* Use static type info header to map static int type to identifier string and RNA struct type.
* Associate the RNA struct type with the bNodeType.
@@ -5289,7 +4384,6 @@ void node_type_base(bNodeType *ntype, int type, const char *name, short nclass,
ntype->type = type;
BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name));
ntype->nclass = nclass;
- ntype->flag = flag;
node_type_base_defaults(ntype);
@@ -5297,14 +4391,12 @@ void node_type_base(bNodeType *ntype, int type, const char *name, short nclass,
ntype->poll_instance = node_poll_instance_default;
}
-void node_type_base_custom(
- bNodeType *ntype, const char *idname, const char *name, short nclass, short flag)
+void node_type_base_custom(bNodeType *ntype, const char *idname, const char *name, short nclass)
{
BLI_strncpy(ntype->idname, idname, sizeof(ntype->idname));
ntype->type = NODE_CUSTOM;
BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name));
ntype->nclass = nclass;
- ntype->flag = flag;
node_type_base_defaults(ntype);
}
@@ -5480,7 +4572,7 @@ static void register_undefined_types()
strcpy(NodeTreeTypeUndefined.ui_name, N_("Undefined"));
strcpy(NodeTreeTypeUndefined.ui_description, N_("Undefined Node Tree Type"));
- node_type_base_custom(&NodeTypeUndefined, "NodeUndefined", "Undefined", 0, 0);
+ node_type_base_custom(&NodeTypeUndefined, "NodeUndefined", "Undefined", 0);
NodeTypeUndefined.poll = node_undefined_poll;
BLI_strncpy(NodeSocketTypeUndefined.idname,
@@ -5774,6 +4866,7 @@ static void registerGeometryNodes()
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();
@@ -5830,6 +4923,7 @@ static void registerGeometryNodes()
register_node_type_geo_input_index();
register_node_type_geo_input_material_index();
register_node_type_geo_input_material();
+ register_node_type_geo_input_mesh_edge_angle();
register_node_type_geo_input_mesh_edge_neighbors();
register_node_type_geo_input_mesh_edge_vertices();
register_node_type_geo_input_mesh_face_area();
diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc
new file mode 100644
index 00000000000..be9777281cb
--- /dev/null
+++ b/source/blender/blenkernel/intern/node_tree_update.cc
@@ -0,0 +1,1669 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_map.hh"
+#include "BLI_multi_value_map.hh"
+#include "BLI_noise.hh"
+#include "BLI_set.hh"
+#include "BLI_stack.hh"
+#include "BLI_vector_set.hh"
+
+#include "DNA_anim_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
+
+#include "BKE_anim_data.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
+
+#include "MOD_nodes.h"
+
+#include "NOD_node_declaration.hh"
+#include "NOD_node_tree_ref.hh"
+
+#include "DEG_depsgraph_query.h"
+
+using namespace blender::nodes;
+
+/**
+ * These flags are used by the `changed_flag` field in #bNodeTree, #bNode and #bNodeSocket.
+ * This enum is not part of the public api. It should be used through the `BKE_ntree_update_tag_*`
+ * api.
+ */
+enum eNodeTreeChangedFlag {
+ NTREE_CHANGED_NOTHING = 0,
+ NTREE_CHANGED_ANY = (1 << 1),
+ NTREE_CHANGED_NODE_PROPERTY = (1 << 2),
+ NTREE_CHANGED_NODE_OUTPUT = (1 << 3),
+ NTREE_CHANGED_INTERFACE = (1 << 4),
+ NTREE_CHANGED_LINK = (1 << 5),
+ NTREE_CHANGED_REMOVED_NODE = (1 << 6),
+ NTREE_CHANGED_REMOVED_SOCKET = (1 << 7),
+ NTREE_CHANGED_SOCKET_PROPERTY = (1 << 8),
+ NTREE_CHANGED_INTERNAL_LINK = (1 << 9),
+ NTREE_CHANGED_ALL = -1,
+};
+
+static void add_tree_tag(bNodeTree *ntree, const eNodeTreeChangedFlag flag)
+{
+ ntree->changed_flag |= flag;
+}
+
+static void add_node_tag(bNodeTree *ntree, bNode *node, const eNodeTreeChangedFlag flag)
+{
+ add_tree_tag(ntree, flag);
+ node->changed_flag |= flag;
+}
+
+static void add_socket_tag(bNodeTree *ntree, bNodeSocket *socket, const eNodeTreeChangedFlag flag)
+{
+ add_tree_tag(ntree, flag);
+ socket->changed_flag |= flag;
+}
+
+namespace blender::bke {
+
+namespace node_field_inferencing {
+
+static bool is_field_socket_type(eNodeSocketDatatype type)
+{
+ return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA);
+}
+
+static bool is_field_socket_type(const SocketRef &socket)
+{
+ return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type);
+}
+
+static InputSocketFieldType get_interface_input_field_type(const NodeRef &node,
+ const InputSocketRef &socket)
+{
+ if (!is_field_socket_type(socket)) {
+ return InputSocketFieldType::None;
+ }
+ if (node.is_reroute_node()) {
+ return InputSocketFieldType::IsSupported;
+ }
+ if (node.is_group_output_node()) {
+ /* Outputs always support fields when the data type is correct. */
+ return InputSocketFieldType::IsSupported;
+ }
+ if (node.is_undefined()) {
+ return InputSocketFieldType::None;
+ }
+
+ const NodeDeclaration *node_decl = node.declaration();
+
+ /* Node declarations should be implemented for nodes involved here. */
+ BLI_assert(node_decl != nullptr);
+
+ /* Get the field type from the declaration. */
+ const SocketDeclaration &socket_decl = *node_decl->inputs()[socket.index()];
+ const InputSocketFieldType field_type = socket_decl.input_field_type();
+ if (field_type == InputSocketFieldType::Implicit) {
+ return field_type;
+ }
+ if (node_decl->is_function_node()) {
+ /* In a function node, every socket supports fields. */
+ return InputSocketFieldType::IsSupported;
+ }
+ return field_type;
+}
+
+static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node,
+ const OutputSocketRef &socket)
+{
+ if (!is_field_socket_type(socket)) {
+ /* Non-field sockets always output data. */
+ return OutputFieldDependency::ForDataSource();
+ }
+ if (node.is_reroute_node()) {
+ /* The reroute just forwards what is passed in. */
+ return OutputFieldDependency::ForDependentField();
+ }
+ if (node.is_group_input_node()) {
+ /* Input nodes get special treatment in #determine_group_input_states. */
+ return OutputFieldDependency::ForDependentField();
+ }
+ if (node.is_undefined()) {
+ return OutputFieldDependency::ForDataSource();
+ }
+
+ const NodeDeclaration *node_decl = node.declaration();
+
+ /* Node declarations should be implemented for nodes involved here. */
+ BLI_assert(node_decl != nullptr);
+
+ if (node_decl->is_function_node()) {
+ /* In a generic function node, all outputs depend on all inputs. */
+ return OutputFieldDependency::ForDependentField();
+ }
+
+ /* Use the socket declaration. */
+ const SocketDeclaration &socket_decl = *node_decl->outputs()[socket.index()];
+ return socket_decl.output_field_dependency();
+}
+
+static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node)
+{
+ FieldInferencingInterface inferencing_interface;
+ inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size());
+ inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(),
+ node.outputs().size());
+ return inferencing_interface;
+}
+
+/**
+ * Retrieves information about how the node interacts with fields.
+ * In the future, this information can be stored in the node declaration. This would allow this
+ * function to return a reference, making it more efficient.
+ */
+static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node)
+{
+ /* Node groups already reference all required information, so just return that. */
+ if (node.is_group_node()) {
+ bNodeTree *group = (bNodeTree *)node.bnode()->id;
+ if (group == nullptr) {
+ return FieldInferencingInterface();
+ }
+ if (!ntreeIsRegistered(group)) {
+ /* This can happen when there is a linked node group that was not found (see T92799). */
+ return get_dummy_field_inferencing_interface(node);
+ }
+ if (group->field_inferencing_interface == nullptr) {
+ /* This shouldn't happen because referenced node groups should always be updated first. */
+ BLI_assert_unreachable();
+ }
+ return *group->field_inferencing_interface;
+ }
+
+ FieldInferencingInterface inferencing_interface;
+ for (const InputSocketRef *input_socket : node.inputs()) {
+ inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket));
+ }
+
+ for (const OutputSocketRef *output_socket : node.outputs()) {
+ inferencing_interface.outputs.append(
+ get_interface_output_field_dependency(node, *output_socket));
+ }
+ return inferencing_interface;
+}
+
+/**
+ * This struct contains information for every socket. The values are propagated through the
+ * network.
+ */
+struct SocketFieldState {
+ /* This socket starts a new field. */
+ bool is_field_source = false;
+ /* This socket can never become a field, because the node itself does not support it. */
+ bool is_always_single = false;
+ /* This socket is currently a single value. It could become a field though. */
+ bool is_single = true;
+ /* This socket is required to be a single value. This can be because the node itself only
+ * supports this socket to be a single value, or because a node afterwards requires this to be a
+ * single value. */
+ bool requires_single = false;
+};
+
+static Vector<const InputSocketRef *> gather_input_socket_dependencies(
+ const OutputFieldDependency &field_dependency, const NodeRef &node)
+{
+ const OutputSocketFieldType type = field_dependency.field_type();
+ Vector<const InputSocketRef *> input_sockets;
+ switch (type) {
+ case OutputSocketFieldType::FieldSource:
+ case OutputSocketFieldType::None: {
+ break;
+ }
+ case OutputSocketFieldType::DependentField: {
+ /* This output depends on all inputs. */
+ input_sockets.extend(node.inputs());
+ break;
+ }
+ case OutputSocketFieldType::PartiallyDependent: {
+ /* This output depends only on a few inputs. */
+ for (const int i : field_dependency.linked_input_indices()) {
+ input_sockets.append(&node.input(i));
+ }
+ break;
+ }
+ }
+ return input_sockets;
+}
+
+/**
+ * Check what the group output socket depends on. Potentially traverses the node tree
+ * to figure out if it is always a field or if it depends on any group inputs.
+ */
+static OutputFieldDependency find_group_output_dependencies(
+ const InputSocketRef &group_output_socket,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ if (!is_field_socket_type(group_output_socket)) {
+ return OutputFieldDependency::ForDataSource();
+ }
+
+ /* Use a Set here instead of an array indexed by socket id, because we my only need to look at
+ * very few sockets. */
+ Set<const InputSocketRef *> handled_sockets;
+ Stack<const InputSocketRef *> sockets_to_check;
+
+ handled_sockets.add(&group_output_socket);
+ sockets_to_check.push(&group_output_socket);
+
+ /* Keeps track of group input indices that are (indirectly) connected to the output. */
+ Vector<int> linked_input_indices;
+
+ while (!sockets_to_check.is_empty()) {
+ const InputSocketRef *input_socket = sockets_to_check.pop();
+
+ for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
+ const NodeRef &origin_node = origin_socket->node();
+ const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()];
+
+ if (origin_state.is_field_source) {
+ if (origin_node.is_group_input_node()) {
+ /* Found a group input that the group output depends on. */
+ linked_input_indices.append_non_duplicates(origin_socket->index());
+ }
+ else {
+ /* Found a field source that is not the group input. So the output is always a field. */
+ return OutputFieldDependency::ForFieldSource();
+ }
+ }
+ else if (!origin_state.is_single) {
+ const FieldInferencingInterface inferencing_interface =
+ get_node_field_inferencing_interface(origin_node);
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[origin_socket->index()];
+
+ /* Propagate search further to the left. */
+ for (const InputSocketRef *origin_input_socket :
+ gather_input_socket_dependencies(field_dependency, origin_node)) {
+ if (!origin_input_socket->is_available()) {
+ continue;
+ }
+ if (!field_state_by_socket_id[origin_input_socket->id()].is_single) {
+ if (handled_sockets.add(origin_input_socket)) {
+ sockets_to_check.push(origin_input_socket);
+ }
+ }
+ }
+ }
+ }
+ }
+ return OutputFieldDependency::ForPartiallyDependentField(std::move(linked_input_indices));
+}
+
+static void propagate_data_requirements_from_right_to_left(
+ const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
+ NodeTreeRef::ToposortDirection::RightToLeft);
+
+ for (const NodeRef *node : toposort_result.sorted_nodes) {
+ const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
+ *node);
+
+ for (const OutputSocketRef *output_socket : node->outputs()) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[output_socket->index()];
+
+ if (field_dependency.field_type() == OutputSocketFieldType::FieldSource) {
+ continue;
+ }
+ if (field_dependency.field_type() == OutputSocketFieldType::None) {
+ state.requires_single = true;
+ state.is_always_single = true;
+ continue;
+ }
+
+ /* The output is required to be a single value when it is connected to any input that does
+ * not support fields. */
+ for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) {
+ if (target_socket->is_available()) {
+ state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single;
+ }
+ }
+
+ if (state.requires_single) {
+ bool any_input_is_field_implicitly = false;
+ const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies(
+ field_dependency, *node);
+ for (const InputSocketRef *input_socket : connected_inputs) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ if (inferencing_interface.inputs[input_socket->index()] ==
+ InputSocketFieldType::Implicit) {
+ if (!input_socket->is_logically_linked()) {
+ any_input_is_field_implicitly = true;
+ break;
+ }
+ }
+ }
+ if (any_input_is_field_implicitly) {
+ /* This output isn't a single value actually. */
+ state.requires_single = false;
+ }
+ else {
+ /* If the output is required to be a single value, the connected inputs in the same node
+ * must not be fields as well. */
+ for (const InputSocketRef *input_socket : connected_inputs) {
+ field_state_by_socket_id[input_socket->id()].requires_single = true;
+ }
+ }
+ }
+ }
+
+ /* Some inputs do not require fields independent of what the outputs are connected to. */
+ for (const InputSocketRef *input_socket : node->inputs()) {
+ SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
+ if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) {
+ state.requires_single = true;
+ state.is_always_single = true;
+ }
+ }
+ }
+}
+
+static void determine_group_input_states(
+ const NodeTreeRef &tree,
+ FieldInferencingInterface &new_inferencing_interface,
+ const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ {
+ /* Non-field inputs never support fields. */
+ int index;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) {
+ if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) {
+ new_inferencing_interface.inputs[index] = InputSocketFieldType::None;
+ }
+ }
+ }
+ /* Check if group inputs are required to be single values, because they are (indirectly)
+ * connected to some socket that does not support fields. */
+ for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
+ for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ if (state.requires_single) {
+ new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None;
+ }
+ }
+ }
+ /* If an input does not support fields, this should be reflected in all Group Input nodes. */
+ for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) {
+ for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] !=
+ InputSocketFieldType::None;
+ if (supports_field) {
+ state.is_single = false;
+ state.is_field_source = true;
+ }
+ else {
+ state.requires_single = true;
+ }
+ }
+ SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()];
+ dummy_socket_state.requires_single = true;
+ }
+}
+
+static void propagate_field_status_from_left_to_right(
+ const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id)
+{
+ const NodeTreeRef::ToposortResult toposort_result = tree.toposort(
+ NodeTreeRef::ToposortDirection::LeftToRight);
+
+ for (const NodeRef *node : toposort_result.sorted_nodes) {
+ if (node->is_group_input_node()) {
+ continue;
+ }
+
+ const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface(
+ *node);
+
+ /* Update field state of input sockets, also taking into account linked origin sockets. */
+ for (const InputSocketRef *input_socket : node->inputs()) {
+ SocketFieldState &state = field_state_by_socket_id[input_socket->id()];
+ if (state.is_always_single) {
+ state.is_single = true;
+ continue;
+ }
+ state.is_single = true;
+ if (input_socket->directly_linked_sockets().is_empty()) {
+ if (inferencing_interface.inputs[input_socket->index()] ==
+ InputSocketFieldType::Implicit) {
+ state.is_single = false;
+ }
+ }
+ else {
+ for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) {
+ if (!field_state_by_socket_id[origin_socket->id()].is_single) {
+ state.is_single = false;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Update field state of output sockets, also taking into account input sockets. */
+ for (const OutputSocketRef *output_socket : node->outputs()) {
+ SocketFieldState &state = field_state_by_socket_id[output_socket->id()];
+ const OutputFieldDependency &field_dependency =
+ inferencing_interface.outputs[output_socket->index()];
+
+ switch (field_dependency.field_type()) {
+ case OutputSocketFieldType::None: {
+ state.is_single = true;
+ break;
+ }
+ case OutputSocketFieldType::FieldSource: {
+ state.is_single = false;
+ state.is_field_source = true;
+ break;
+ }
+ case OutputSocketFieldType::PartiallyDependent:
+ case OutputSocketFieldType::DependentField: {
+ for (const InputSocketRef *input_socket :
+ gather_input_socket_dependencies(field_dependency, *node)) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ if (!field_state_by_socket_id[input_socket->id()].is_single) {
+ state.is_single = false;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void determine_group_output_states(const NodeTreeRef &tree,
+ FieldInferencingInterface &new_inferencing_interface,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) {
+ /* Ignore inactive group output nodes. */
+ if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) {
+ continue;
+ }
+ /* Determine dependencies of all group outputs. */
+ for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) {
+ OutputFieldDependency field_dependency = find_group_output_dependencies(
+ *group_output_socket, field_state_by_socket_id);
+ new_inferencing_interface.outputs[group_output_socket->index()] = std::move(
+ field_dependency);
+ }
+ break;
+ }
+}
+
+static void update_socket_shapes(const NodeTreeRef &tree,
+ const Span<SocketFieldState> field_state_by_socket_id)
+{
+ const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
+ const eNodeSocketDisplayShape data_but_can_be_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND_DOT;
+ const eNodeSocketDisplayShape is_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND;
+
+ auto get_shape_for_state = [&](const SocketFieldState &state) {
+ if (state.is_always_single) {
+ return requires_data_shape;
+ }
+ if (!state.is_single) {
+ return is_field_shape;
+ }
+ if (state.requires_single) {
+ return requires_data_shape;
+ }
+ return data_but_can_be_field_shape;
+ };
+
+ for (const InputSocketRef *socket : tree.input_sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ const SocketFieldState &state = field_state_by_socket_id[socket->id()];
+ bsocket->display_shape = get_shape_for_state(state);
+ }
+ for (const OutputSocketRef *socket : tree.output_sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ const SocketFieldState &state = field_state_by_socket_id[socket->id()];
+ bsocket->display_shape = get_shape_for_state(state);
+ }
+}
+
+static bool update_field_inferencing(const NodeTreeRef &tree)
+{
+ bNodeTree &btree = *tree.btree();
+
+ /* Create new inferencing interface for this node group. */
+ FieldInferencingInterface *new_inferencing_interface = new FieldInferencingInterface();
+ new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs),
+ InputSocketFieldType::IsSupported);
+ new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs),
+ OutputFieldDependency::ForDataSource());
+
+ /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */
+ Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size());
+
+ propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id);
+ determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id);
+ propagate_field_status_from_left_to_right(tree, field_state_by_socket_id);
+ determine_group_output_states(tree, *new_inferencing_interface, field_state_by_socket_id);
+ update_socket_shapes(tree, field_state_by_socket_id);
+
+ /* Update the previous group interface. */
+ const bool group_interface_changed = btree.field_inferencing_interface == nullptr ||
+ *btree.field_inferencing_interface !=
+ *new_inferencing_interface;
+ delete btree.field_inferencing_interface;
+ btree.field_inferencing_interface = new_inferencing_interface;
+
+ return group_interface_changed;
+}
+
+} // namespace node_field_inferencing
+
+/**
+ * Common datatype priorities, works for compositor, shader and texture nodes alike
+ * defines priority of datatype connection based on output type (to):
+ * `< 0`: never connect these types.
+ * `>= 0`: priority of connection (higher values chosen first).
+ */
+static int get_internal_link_type_priority(const bNodeSocketType *from, const bNodeSocketType *to)
+{
+ switch (to->type) {
+ case SOCK_RGBA:
+ switch (from->type) {
+ case SOCK_RGBA:
+ return 4;
+ case SOCK_FLOAT:
+ return 3;
+ case SOCK_INT:
+ return 2;
+ case SOCK_BOOLEAN:
+ return 1;
+ }
+ return -1;
+ case SOCK_VECTOR:
+ switch (from->type) {
+ case SOCK_VECTOR:
+ return 4;
+ case SOCK_FLOAT:
+ return 3;
+ case SOCK_INT:
+ return 2;
+ case SOCK_BOOLEAN:
+ return 1;
+ }
+ return -1;
+ case SOCK_FLOAT:
+ switch (from->type) {
+ case SOCK_FLOAT:
+ return 5;
+ case SOCK_INT:
+ return 4;
+ case SOCK_BOOLEAN:
+ return 3;
+ case SOCK_RGBA:
+ return 2;
+ case SOCK_VECTOR:
+ return 1;
+ }
+ return -1;
+ case SOCK_INT:
+ switch (from->type) {
+ case SOCK_INT:
+ return 5;
+ case SOCK_FLOAT:
+ return 4;
+ case SOCK_BOOLEAN:
+ return 3;
+ case SOCK_RGBA:
+ return 2;
+ case SOCK_VECTOR:
+ return 1;
+ }
+ return -1;
+ case SOCK_BOOLEAN:
+ switch (from->type) {
+ case SOCK_BOOLEAN:
+ return 5;
+ case SOCK_INT:
+ return 4;
+ case SOCK_FLOAT:
+ return 3;
+ case SOCK_RGBA:
+ return 2;
+ case SOCK_VECTOR:
+ return 1;
+ }
+ return -1;
+ }
+
+ /* The rest of the socket types only allow an internal link if both the input and output socket
+ * have the same type. If the sockets are custom, we check the idname instead. */
+ if (to->type == from->type && (to->type != SOCK_CUSTOM || STREQ(to->idname, from->idname))) {
+ return 1;
+ }
+
+ return -1;
+}
+
+using TreeNodePair = std::pair<bNodeTree *, bNode *>;
+using ObjectModifierPair = std::pair<Object *, ModifierData *>;
+using NodeSocketPair = std::pair<bNode *, bNodeSocket *>;
+
+/**
+ * Cache common data about node trees from the #Main database that is expensive to retrieve on
+ * demand every time.
+ */
+struct NodeTreeRelations {
+ private:
+ Main *bmain_;
+ std::optional<Vector<bNodeTree *>> all_trees_;
+ std::optional<Map<bNodeTree *, ID *>> owner_ids_;
+ std::optional<MultiValueMap<bNodeTree *, TreeNodePair>> group_node_users_;
+ std::optional<MultiValueMap<bNodeTree *, ObjectModifierPair>> modifiers_users_;
+
+ public:
+ NodeTreeRelations(Main *bmain) : bmain_(bmain)
+ {
+ }
+
+ void ensure_all_trees()
+ {
+ if (all_trees_.has_value()) {
+ return;
+ }
+ all_trees_.emplace();
+ owner_ids_.emplace();
+ if (bmain_ == nullptr) {
+ return;
+ }
+
+ FOREACH_NODETREE_BEGIN (bmain_, ntree, id) {
+ all_trees_->append(ntree);
+ if (&ntree->id != id) {
+ owner_ids_->add_new(ntree, id);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
+ void ensure_owner_ids()
+ {
+ this->ensure_all_trees();
+ }
+
+ void ensure_group_node_users()
+ {
+ if (group_node_users_.has_value()) {
+ return;
+ }
+ group_node_users_.emplace();
+ if (bmain_ == nullptr) {
+ return;
+ }
+
+ this->ensure_all_trees();
+
+ for (bNodeTree *ntree : *all_trees_) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->id == nullptr) {
+ continue;
+ }
+ ID *id = node->id;
+ if (GS(id->name) == ID_NT) {
+ bNodeTree *group = (bNodeTree *)id;
+ group_node_users_->add(group, {ntree, node});
+ }
+ }
+ }
+ }
+
+ void ensure_modifier_users()
+ {
+ if (modifiers_users_.has_value()) {
+ return;
+ }
+ modifiers_users_.emplace();
+ if (bmain_ == nullptr) {
+ return;
+ }
+
+ LISTBASE_FOREACH (Object *, object, &bmain_->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
+ if (md->type == eModifierType_Nodes) {
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ if (nmd->node_group != nullptr) {
+ modifiers_users_->add(nmd->node_group, {object, md});
+ }
+ }
+ }
+ }
+ }
+
+ Span<ObjectModifierPair> get_modifier_users(bNodeTree *ntree)
+ {
+ BLI_assert(modifiers_users_.has_value());
+ return modifiers_users_->lookup(ntree);
+ }
+
+ Span<TreeNodePair> get_group_node_users(bNodeTree *ntree)
+ {
+ BLI_assert(group_node_users_.has_value());
+ return group_node_users_->lookup(ntree);
+ }
+
+ ID *get_owner_id(bNodeTree *ntree)
+ {
+ BLI_assert(owner_ids_.has_value());
+ return owner_ids_->lookup_default(ntree, &ntree->id);
+ }
+};
+
+struct TreeUpdateResult {
+ bool interface_changed = false;
+ bool output_changed = false;
+};
+
+class NodeTreeMainUpdater {
+ private:
+ Main *bmain_;
+ NodeTreeUpdateExtraParams *params_;
+ Map<bNodeTree *, TreeUpdateResult> update_result_by_tree_;
+ NodeTreeRelations relations_;
+
+ public:
+ NodeTreeMainUpdater(Main *bmain, NodeTreeUpdateExtraParams *params)
+ : bmain_(bmain), params_(params), relations_(bmain)
+ {
+ }
+
+ void update()
+ {
+ Vector<bNodeTree *> changed_ntrees;
+ FOREACH_NODETREE_BEGIN (bmain_, ntree, id) {
+ if (ntree->changed_flag != NTREE_CHANGED_NOTHING) {
+ changed_ntrees.append(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ this->update_rooted(changed_ntrees);
+ }
+
+ void update_rooted(Span<bNodeTree *> root_ntrees)
+ {
+ if (root_ntrees.is_empty()) {
+ return;
+ }
+
+ bool is_single_tree_update = false;
+
+ if (root_ntrees.size() == 1) {
+ bNodeTree *ntree = root_ntrees[0];
+ if (ntree->changed_flag == NTREE_CHANGED_NOTHING) {
+ return;
+ }
+ const TreeUpdateResult result = this->update_tree(*ntree);
+ update_result_by_tree_.add_new(ntree, result);
+ if (!result.interface_changed && !result.output_changed) {
+ is_single_tree_update = true;
+ }
+ }
+
+ if (!is_single_tree_update) {
+ Vector<bNodeTree *> ntrees_in_order = this->get_tree_update_order(root_ntrees);
+ for (bNodeTree *ntree : ntrees_in_order) {
+ if (ntree->changed_flag == NTREE_CHANGED_NOTHING) {
+ continue;
+ }
+ if (!update_result_by_tree_.contains(ntree)) {
+ const TreeUpdateResult result = this->update_tree(*ntree);
+ update_result_by_tree_.add_new(ntree, result);
+ }
+ const TreeUpdateResult result = update_result_by_tree_.lookup(ntree);
+ Span<TreeNodePair> dependent_trees = relations_.get_group_node_users(ntree);
+ if (result.output_changed) {
+ for (const TreeNodePair &pair : dependent_trees) {
+ add_node_tag(pair.first, pair.second, NTREE_CHANGED_NODE_OUTPUT);
+ }
+ }
+ if (result.interface_changed) {
+ for (const TreeNodePair &pair : dependent_trees) {
+ add_node_tag(pair.first, pair.second, NTREE_CHANGED_NODE_PROPERTY);
+ }
+ }
+ }
+ }
+
+ for (const auto item : update_result_by_tree_.items()) {
+ bNodeTree *ntree = item.key;
+ const TreeUpdateResult &result = item.value;
+
+ this->reset_changed_flags(*ntree);
+
+ if (result.interface_changed) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ relations_.ensure_modifier_users();
+ for (const ObjectModifierPair &pair : relations_.get_modifier_users(ntree)) {
+ Object *object = pair.first;
+ ModifierData *md = pair.second;
+
+ if (md->type == eModifierType_Nodes) {
+ MOD_nodes_update_interface(object, (NodesModifierData *)md);
+ }
+ }
+ }
+ }
+
+ if (params_) {
+ relations_.ensure_owner_ids();
+ ID *id = relations_.get_owner_id(ntree);
+ if (params_->tree_changed_fn) {
+ params_->tree_changed_fn(id, ntree, params_->user_data);
+ }
+ if (params_->tree_output_changed_fn && result.output_changed) {
+ params_->tree_output_changed_fn(id, ntree, params_->user_data);
+ }
+ }
+ }
+ }
+
+ private:
+ enum class ToposortMark {
+ None,
+ Temporary,
+ Permanent,
+ };
+
+ using ToposortMarkMap = Map<bNodeTree *, ToposortMark>;
+
+ /**
+ * Finds all trees that depend on the given trees (through node groups). Then those trees are
+ * ordered such that all trees used by one tree come before it.
+ */
+ Vector<bNodeTree *> get_tree_update_order(Span<bNodeTree *> root_ntrees)
+ {
+ relations_.ensure_group_node_users();
+
+ Set<bNodeTree *> trees_to_update = get_trees_to_update(root_ntrees);
+
+ Vector<bNodeTree *> sorted_ntrees;
+
+ ToposortMarkMap marks;
+ for (bNodeTree *ntree : trees_to_update) {
+ marks.add_new(ntree, ToposortMark::None);
+ }
+ for (bNodeTree *ntree : trees_to_update) {
+ if (marks.lookup(ntree) == ToposortMark::None) {
+ const bool cycle_detected = !this->get_tree_update_order__visit_recursive(
+ ntree, marks, sorted_ntrees);
+ /* This should be prevented by higher level operators. */
+ BLI_assert(!cycle_detected);
+ UNUSED_VARS_NDEBUG(cycle_detected);
+ }
+ }
+
+ std::reverse(sorted_ntrees.begin(), sorted_ntrees.end());
+
+ return sorted_ntrees;
+ }
+
+ bool get_tree_update_order__visit_recursive(bNodeTree *ntree,
+ ToposortMarkMap &marks,
+ Vector<bNodeTree *> &sorted_ntrees)
+ {
+ ToposortMark &mark = marks.lookup(ntree);
+ if (mark == ToposortMark::Permanent) {
+ return true;
+ }
+ if (mark == ToposortMark::Temporary) {
+ /* There is a dependency cycle. */
+ return false;
+ }
+
+ mark = ToposortMark::Temporary;
+
+ for (const TreeNodePair &pair : relations_.get_group_node_users(ntree)) {
+ this->get_tree_update_order__visit_recursive(pair.first, marks, sorted_ntrees);
+ }
+ sorted_ntrees.append(ntree);
+
+ mark = ToposortMark::Permanent;
+ return true;
+ }
+
+ Set<bNodeTree *> get_trees_to_update(Span<bNodeTree *> root_ntrees)
+ {
+ relations_.ensure_group_node_users();
+
+ Set<bNodeTree *> reachable_trees;
+ VectorSet<bNodeTree *> trees_to_check = root_ntrees;
+
+ while (!trees_to_check.is_empty()) {
+ bNodeTree *ntree = trees_to_check.pop();
+ if (reachable_trees.add(ntree)) {
+ for (const TreeNodePair &pair : relations_.get_group_node_users(ntree)) {
+ trees_to_check.add(pair.first);
+ }
+ }
+ }
+
+ return reachable_trees;
+ }
+
+ TreeUpdateResult update_tree(bNodeTree &ntree)
+ {
+ TreeUpdateResult result;
+
+ /* Use a #NodeTreeRef to speedup certain queries. It is rebuilt whenever the node tree topology
+ * changes, which typically happens zero or one times during the entire update of the node
+ * tree. */
+ std::unique_ptr<NodeTreeRef> tree_ref;
+ this->ensure_tree_ref(ntree, tree_ref);
+
+ this->update_socket_link_and_use(*tree_ref);
+ this->update_individual_nodes(ntree, tree_ref);
+ this->update_internal_links(ntree, tree_ref);
+ this->update_generic_callback(ntree, tree_ref);
+ this->remove_unused_previews_when_necessary(ntree);
+
+ this->ensure_tree_ref(ntree, tree_ref);
+ if (ntree.type == NTREE_GEOMETRY) {
+ if (node_field_inferencing::update_field_inferencing(*tree_ref)) {
+ result.interface_changed = true;
+ }
+ }
+
+ result.output_changed = this->check_if_output_changed(*tree_ref);
+
+ this->update_socket_link_and_use(*tree_ref);
+ this->update_node_levels(ntree);
+ this->update_link_validation(ntree);
+
+ if (ntree.type == NTREE_TEXTURE) {
+ ntreeTexCheckCyclics(&ntree);
+ }
+
+ if (ntree.changed_flag & NTREE_CHANGED_INTERFACE || ntree.changed_flag & NTREE_CHANGED_ANY) {
+ result.interface_changed = true;
+ }
+
+ if (result.interface_changed) {
+ ntreeInterfaceTypeUpdate(&ntree);
+ }
+
+ return result;
+ }
+
+ void ensure_tree_ref(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ if (!tree_ref) {
+ tree_ref = std::make_unique<NodeTreeRef>(&ntree);
+ }
+ }
+
+ void update_socket_link_and_use(const NodeTreeRef &tree)
+ {
+ for (const InputSocketRef *socket : tree.input_sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ if (socket->directly_linked_links().is_empty()) {
+ bsocket->link = nullptr;
+ }
+ else {
+ bsocket->link = socket->directly_linked_links()[0]->blink();
+ }
+ }
+
+ this->update_socket_used_tags(tree);
+ }
+
+ void update_socket_used_tags(const NodeTreeRef &tree)
+ {
+ for (const SocketRef *socket : tree.sockets()) {
+ bNodeSocket *bsocket = socket->bsocket();
+ bsocket->flag &= ~SOCK_IN_USE;
+ for (const LinkRef *link : socket->directly_linked_links()) {
+ if (!link->is_muted()) {
+ bsocket->flag |= SOCK_IN_USE;
+ break;
+ }
+ }
+ }
+ }
+
+ void update_individual_nodes(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ /* Iterate over nodes instead of #NodeTreeRef, because the #tree_ref might be outdated after
+ * some update functions. */
+ LISTBASE_FOREACH (bNode *, bnode, &ntree.nodes) {
+ this->ensure_tree_ref(ntree, tree_ref);
+ const NodeRef &node = *tree_ref->find_node(*bnode);
+ if (this->should_update_individual_node(node)) {
+ const uint32_t old_changed_flag = ntree.changed_flag;
+ ntree.changed_flag = NTREE_CHANGED_NOTHING;
+
+ /* This may set #ntree.changed_flag which is detected below. */
+ this->update_individual_node(node);
+
+ if (ntree.changed_flag != NTREE_CHANGED_NOTHING) {
+ /* The tree ref is outdated and needs to be rebuilt. Generally, only very few update
+ * functions change the node. Typically zero or one nodes change after an update. */
+ tree_ref.reset();
+ }
+ ntree.changed_flag |= old_changed_flag;
+ }
+ }
+ }
+
+ bool should_update_individual_node(const NodeRef &node)
+ {
+ bNodeTree &ntree = *node.btree();
+ bNode &bnode = *node.bnode();
+ if (ntree.changed_flag & NTREE_CHANGED_ANY) {
+ return true;
+ }
+ if (bnode.changed_flag & NTREE_CHANGED_NODE_PROPERTY) {
+ return true;
+ }
+ if (ntree.changed_flag & NTREE_CHANGED_LINK) {
+ /* Node groups currently always rebuilt their sockets when they are updated.
+ * So avoid calling the update method when no new link was added to it. */
+ if (node.is_group_input_node()) {
+ if (node.outputs().last()->is_directly_linked()) {
+ return true;
+ }
+ }
+ else if (node.is_group_output_node()) {
+ if (node.inputs().last()->is_directly_linked()) {
+ return true;
+ }
+ }
+ else {
+ /* Currently we have no way to tell if a node needs to be updated when a link changed. */
+ return true;
+ }
+ }
+ if (ntree.changed_flag & NTREE_CHANGED_INTERFACE) {
+ if (node.is_group_input_node() || node.is_group_output_node()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void update_individual_node(const NodeRef &node)
+ {
+ bNodeTree &ntree = *node.btree();
+ bNode &bnode = *node.bnode();
+ bNodeType &ntype = *bnode.typeinfo;
+ if (ntype.group_update_func) {
+ ntype.group_update_func(&ntree, &bnode);
+ }
+ if (ntype.updatefunc) {
+ ntype.updatefunc(&ntree, &bnode);
+ }
+ }
+
+ void update_internal_links(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ bool any_internal_links_updated = false;
+ this->ensure_tree_ref(ntree, tree_ref);
+ for (const NodeRef *node : tree_ref->nodes()) {
+ if (!this->should_update_individual_node(*node)) {
+ continue;
+ }
+ /* Find all expected internal links. */
+ Vector<std::pair<bNodeSocket *, bNodeSocket *>> expected_internal_links;
+ for (const OutputSocketRef *output_socket : node->outputs()) {
+ if (!output_socket->is_available()) {
+ continue;
+ }
+ if (!output_socket->is_directly_linked()) {
+ continue;
+ }
+ if (output_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) {
+ continue;
+ }
+ const InputSocketRef *input_socket = this->find_internally_linked_input(output_socket);
+ if (input_socket != nullptr) {
+ expected_internal_links.append({input_socket->bsocket(), output_socket->bsocket()});
+ }
+ }
+ /* rebuilt internal links if they have changed. */
+ if (node->internal_links().size() != expected_internal_links.size()) {
+ this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links);
+ any_internal_links_updated = true;
+ }
+ else {
+ for (auto &item : expected_internal_links) {
+ const bNodeSocket *from_socket = item.first;
+ const bNodeSocket *to_socket = item.second;
+ bool found = false;
+ for (const InternalLinkRef *internal_link : node->internal_links()) {
+ if (from_socket == internal_link->from().bsocket() &&
+ to_socket == internal_link->to().bsocket()) {
+ found = true;
+ }
+ }
+ if (!found) {
+ this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links);
+ any_internal_links_updated = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (any_internal_links_updated) {
+ tree_ref.reset();
+ }
+ }
+
+ const InputSocketRef *find_internally_linked_input(const OutputSocketRef *output_socket)
+ {
+ const InputSocketRef *selected_socket = nullptr;
+ int selected_priority = -1;
+ bool selected_is_linked = false;
+ for (const InputSocketRef *input_socket : output_socket->node().inputs()) {
+ if (!input_socket->is_available()) {
+ continue;
+ }
+ if (input_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) {
+ continue;
+ }
+ const int priority = get_internal_link_type_priority(input_socket->bsocket()->typeinfo,
+ output_socket->bsocket()->typeinfo);
+ if (priority < 0) {
+ continue;
+ }
+ const bool is_linked = input_socket->is_directly_linked();
+ const bool is_preferred = priority > selected_priority || (is_linked && !selected_is_linked);
+ if (!is_preferred) {
+ continue;
+ }
+ selected_socket = input_socket;
+ selected_priority = priority;
+ selected_is_linked = is_linked;
+ }
+ return selected_socket;
+ }
+
+ void update_internal_links_in_node(bNodeTree &ntree,
+ bNode &node,
+ Span<std::pair<bNodeSocket *, bNodeSocket *>> links)
+ {
+ BLI_freelistN(&node.internal_links);
+ for (const auto &item : links) {
+ bNodeSocket *from_socket = item.first;
+ bNodeSocket *to_socket = item.second;
+ bNodeLink *link = MEM_cnew<bNodeLink>(__func__);
+ link->fromnode = &node;
+ link->fromsock = from_socket;
+ link->tonode = &node;
+ link->tosock = to_socket;
+ link->flag |= NODE_LINK_VALID;
+ BLI_addtail(&node.internal_links, link);
+ }
+ BKE_ntree_update_tag_node_internal_link(&ntree, &node);
+ }
+
+ void update_generic_callback(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref)
+ {
+ if (ntree.typeinfo->update == nullptr) {
+ return;
+ }
+
+ /* Reset the changed_flag to allow detecting when the update callback changed the node tree. */
+ const uint32_t old_changed_flag = ntree.changed_flag;
+ ntree.changed_flag = NTREE_CHANGED_NOTHING;
+
+ ntree.typeinfo->update(&ntree);
+
+ if (ntree.changed_flag != NTREE_CHANGED_NOTHING) {
+ /* The tree ref is outdated and needs to be rebuilt. */
+ tree_ref.reset();
+ }
+ ntree.changed_flag |= old_changed_flag;
+ }
+
+ void remove_unused_previews_when_necessary(bNodeTree &ntree)
+ {
+ /* Don't trigger preview removal when only those flags are set. */
+ const uint32_t allowed_flags = NTREE_CHANGED_LINK | NTREE_CHANGED_SOCKET_PROPERTY |
+ NTREE_CHANGED_NODE_PROPERTY | NTREE_CHANGED_NODE_OUTPUT |
+ NTREE_CHANGED_INTERFACE;
+ if ((ntree.changed_flag & allowed_flags) == ntree.changed_flag) {
+ return;
+ }
+ BKE_node_preview_remove_unused(&ntree);
+ }
+
+ void update_node_levels(bNodeTree &ntree)
+ {
+ ntreeUpdateNodeLevels(&ntree);
+ }
+
+ void update_link_validation(bNodeTree &ntree)
+ {
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+ link->flag |= NODE_LINK_VALID;
+ if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level) {
+ link->flag &= ~NODE_LINK_VALID;
+ }
+ else if (ntree.typeinfo->validate_link) {
+ const eNodeSocketDatatype from_type = static_cast<eNodeSocketDatatype>(
+ link->fromsock->type);
+ const eNodeSocketDatatype to_type = static_cast<eNodeSocketDatatype>(link->tosock->type);
+ if (!ntree.typeinfo->validate_link(from_type, to_type)) {
+ link->flag &= ~NODE_LINK_VALID;
+ }
+ }
+ }
+ }
+
+ bool check_if_output_changed(const NodeTreeRef &tree)
+ {
+ bNodeTree &btree = *tree.btree();
+
+ /* Compute a hash that represents the node topology connected to the output. This always has to
+ * be updated even if it is not used to detect changes right now. Otherwise
+ * #btree.output_topology_hash will go out of date. */
+ const Vector<const SocketRef *> tree_output_sockets = this->find_output_sockets(tree);
+ const uint32_t old_topology_hash = btree.output_topology_hash;
+ const uint32_t new_topology_hash = this->get_combined_socket_topology_hash(
+ tree, tree_output_sockets);
+ btree.output_topology_hash = new_topology_hash;
+
+ if (const AnimData *adt = BKE_animdata_from_id(&btree.id)) {
+ /* Drivers may copy values in the node tree around arbitrarily and may cause the output to
+ * change even if it wouldn't without drivers. Only some special drivers like `frame/5` can
+ * be used without causing updates all the time currently. In the future we could try to
+ * handle other drivers better as well.
+ * Note that this optimization only works in practice when the depsgraph didn't also get a
+ * copy-on-write tag for the node tree (which happens when changing node properties). It does
+ * work in a few situations like adding reroutes and duplicating nodes though. */
+ LISTBASE_FOREACH (const FCurve *, fcurve, &adt->drivers) {
+ const ChannelDriver *driver = fcurve->driver;
+ const StringRef expression = driver->expression;
+ if (expression.startswith("frame")) {
+ const StringRef remaining_expression = expression.drop_known_prefix("frame");
+ if (remaining_expression.find_first_not_of(" */+-0123456789.") == StringRef::not_found) {
+ continue;
+ }
+ }
+ /* Unrecognized driver, assume that the output always changes. */
+ return true;
+ }
+ }
+
+ if (btree.changed_flag & NTREE_CHANGED_ANY) {
+ return true;
+ }
+
+ if (old_topology_hash != new_topology_hash) {
+ return true;
+ }
+
+ /* The topology hash can only be used when only topology-changing operations have been done. */
+ if (btree.changed_flag ==
+ (btree.changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) {
+ if (old_topology_hash == new_topology_hash) {
+ return false;
+ }
+ }
+
+ if (!this->check_if_socket_outputs_changed_based_on_flags(tree, tree_output_sockets)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ Vector<const SocketRef *> find_output_sockets(const NodeTreeRef &tree)
+ {
+ Vector<const SocketRef *> sockets;
+ for (const NodeRef *node : tree.nodes()) {
+ const bNode *bnode = node->bnode();
+ if (bnode->typeinfo->nclass != NODE_CLASS_OUTPUT && bnode->type != NODE_GROUP_OUTPUT) {
+ continue;
+ }
+ for (const InputSocketRef *socket : node->inputs()) {
+ if (socket->idname() != "NodeSocketVirtual") {
+ sockets.append(socket);
+ }
+ }
+ }
+ return sockets;
+ }
+
+ /**
+ * Computes a hash that changes when the node tree topology connected to an output node changes.
+ * Adding reroutes does not have an effect on the hash.
+ */
+ uint32_t get_combined_socket_topology_hash(const NodeTreeRef &tree,
+ Span<const SocketRef *> sockets)
+ {
+ if (tree.has_link_cycles()) {
+ /* Return dummy value when the link has any cycles. The algorithm below could be improved to
+ * handle cycles more gracefully. */
+ return 0;
+ }
+ Array<uint32_t> hashes = this->get_socket_topology_hashes(tree, sockets);
+ uint32_t combined_hash = 0;
+ for (uint32_t hash : hashes) {
+ combined_hash = noise::hash(combined_hash, hash);
+ }
+ return combined_hash;
+ }
+
+ Array<uint32_t> get_socket_topology_hashes(const NodeTreeRef &tree,
+ Span<const SocketRef *> sockets)
+ {
+ BLI_assert(!tree.has_link_cycles());
+ Array<std::optional<uint32_t>> hash_by_socket_id(tree.sockets().size());
+ Stack<const SocketRef *> sockets_to_check = sockets;
+
+ while (!sockets_to_check.is_empty()) {
+ const SocketRef &in_out_socket = *sockets_to_check.peek();
+ const NodeRef &node = in_out_socket.node();
+
+ if (hash_by_socket_id[in_out_socket.id()].has_value()) {
+ sockets_to_check.pop();
+ /* Socket is handled already. */
+ continue;
+ }
+
+ if (in_out_socket.is_input()) {
+ /* For input sockets, first compute the hashes of all linked sockets. */
+ const InputSocketRef &socket = in_out_socket.as_input();
+ bool all_origins_computed = true;
+ for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) {
+ if (!hash_by_socket_id[origin_socket->id()].has_value()) {
+ sockets_to_check.push(origin_socket);
+ all_origins_computed = false;
+ }
+ }
+ if (!all_origins_computed) {
+ continue;
+ }
+ /* When the hashes for the linked sockets are ready, combine them into a hash for the input
+ * socket. */
+ const uint64_t socket_ptr = (uintptr_t)socket.bsocket();
+ uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32);
+ for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) {
+ const uint32_t origin_socket_hash = *hash_by_socket_id[origin_socket->id()];
+ socket_hash = noise::hash(socket_hash, origin_socket_hash);
+ }
+ hash_by_socket_id[socket.id()] = socket_hash;
+ sockets_to_check.pop();
+ }
+ else {
+ /* For output sockets, first compute the hashes of all available input sockets. */
+ const OutputSocketRef &socket = in_out_socket.as_output();
+ bool all_available_inputs_computed = true;
+ for (const InputSocketRef *input_socket : node.inputs()) {
+ if (input_socket->is_available()) {
+ if (!hash_by_socket_id[input_socket->id()].has_value()) {
+ sockets_to_check.push(input_socket);
+ all_available_inputs_computed = false;
+ }
+ }
+ }
+ if (!all_available_inputs_computed) {
+ continue;
+ }
+ /* When all input socket hashes have been computed, combine them into a hash for the output
+ * socket. */
+ const uint64_t socket_ptr = (uintptr_t)socket.bsocket();
+ uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32);
+ for (const InputSocketRef *input_socket : node.inputs()) {
+ if (input_socket->is_available()) {
+ const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->id()];
+ socket_hash = noise::hash(socket_hash, input_socket_hash);
+ }
+ }
+ hash_by_socket_id[socket.id()] = socket_hash;
+ sockets_to_check.pop();
+ }
+ }
+
+ /* Create output array. */
+ Array<uint32_t> hashes(sockets.size());
+ for (const int i : sockets.index_range()) {
+ hashes[i] = *hash_by_socket_id[sockets[i]->id()];
+ }
+ return hashes;
+ }
+
+ /**
+ * Returns true when any of the provided sockets changed its values. A change is detected by
+ * checking the #changed_flag on connected sockets and nodes.
+ */
+ bool check_if_socket_outputs_changed_based_on_flags(const NodeTreeRef &tree,
+ Span<const SocketRef *> sockets)
+ {
+ /* Avoid visiting the same socket twice when multiple links point to the same socket. */
+ Array<bool> pushed_by_socket_id(tree.sockets().size(), false);
+ Stack<const SocketRef *> sockets_to_check = sockets;
+
+ for (const SocketRef *socket : sockets) {
+ pushed_by_socket_id[socket->id()] = true;
+ }
+
+ while (!sockets_to_check.is_empty()) {
+ const SocketRef &in_out_socket = *sockets_to_check.pop();
+ const bNode &bnode = *in_out_socket.node().bnode();
+ const bNodeSocket &bsocket = *in_out_socket.bsocket();
+ if (bsocket.changed_flag != NTREE_CHANGED_NOTHING) {
+ return true;
+ }
+ if (bnode.changed_flag != NTREE_CHANGED_NOTHING) {
+ const bool only_unused_internal_link_changed = (bnode.flag & NODE_MUTED) == 0 &&
+ bnode.changed_flag ==
+ NTREE_CHANGED_INTERNAL_LINK;
+ if (!only_unused_internal_link_changed) {
+ return true;
+ }
+ }
+ if (in_out_socket.is_input()) {
+ const InputSocketRef &socket = in_out_socket.as_input();
+ for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) {
+ bool &pushed = pushed_by_socket_id[origin_socket->id()];
+ if (!pushed) {
+ sockets_to_check.push(origin_socket);
+ pushed = true;
+ }
+ }
+ }
+ else {
+ const OutputSocketRef &socket = in_out_socket.as_output();
+ for (const InputSocketRef *input_socket : socket.node().inputs()) {
+ if (input_socket->is_available()) {
+ bool &pushed = pushed_by_socket_id[input_socket->id()];
+ if (!pushed) {
+ sockets_to_check.push(input_socket);
+ pushed = true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ void reset_changed_flags(bNodeTree &ntree)
+ {
+ ntree.changed_flag = NTREE_CHANGED_NOTHING;
+ LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
+ node->changed_flag = NTREE_CHANGED_NOTHING;
+ node->update = 0;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ socket->changed_flag = NTREE_CHANGED_NOTHING;
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ socket->changed_flag = NTREE_CHANGED_NOTHING;
+ }
+ }
+ }
+};
+
+} // namespace blender::bke
+
+void BKE_ntree_update_tag_all(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_ANY);
+}
+
+void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+}
+
+void BKE_ntree_update_tag_node_new(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_property(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_new(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_removed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_REMOVED_SOCKET);
+}
+
+void BKE_ntree_update_tag_socket_type(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_socket_availability(bNodeTree *ntree, bNodeSocket *socket)
+{
+ add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY);
+}
+
+void BKE_ntree_update_tag_node_removed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_REMOVED_NODE);
+}
+
+void BKE_ntree_update_tag_node_mute(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+}
+
+void BKE_ntree_update_tag_node_internal_link(bNodeTree *ntree, bNode *node)
+{
+ add_node_tag(ntree, node, NTREE_CHANGED_INTERNAL_LINK);
+}
+
+void BKE_ntree_update_tag_link_changed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_link_removed(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_link_added(bNodeTree *ntree, bNodeLink *UNUSED(link))
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_link_mute(bNodeTree *ntree, bNodeLink *UNUSED(link))
+{
+ add_tree_tag(ntree, NTREE_CHANGED_LINK);
+}
+
+void BKE_ntree_update_tag_missing_runtime_data(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_ALL);
+}
+
+void BKE_ntree_update_tag_interface(bNodeTree *ntree)
+{
+ add_tree_tag(ntree, NTREE_CHANGED_INTERFACE);
+}
+
+void BKE_ntree_update_tag_id_changed(Main *bmain, ID *id)
+{
+ FOREACH_NODETREE_BEGIN (bmain, ntree, ntree_id) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->id == id) {
+ node->update |= NODE_UPDATE_ID;
+ add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY);
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+}
+
+/**
+ * Protect from recursive calls into the updating function. Some node update functions might
+ * trigger this from Python or in other cases.
+ *
+ * This could be added to #Main, but given that there is generally only one #Main, that's not
+ * really worth it now.
+ */
+static bool is_updating = false;
+
+void BKE_ntree_update_main(Main *bmain, NodeTreeUpdateExtraParams *params)
+{
+ if (is_updating) {
+ return;
+ }
+
+ is_updating = true;
+ blender::bke::NodeTreeMainUpdater updater{bmain, params};
+ updater.update();
+ is_updating = false;
+}
+
+void BKE_ntree_update_main_tree(Main *bmain, bNodeTree *ntree, NodeTreeUpdateExtraParams *params)
+{
+ if (ntree == nullptr) {
+ BKE_ntree_update_main(bmain, params);
+ return;
+ }
+
+ if (is_updating) {
+ return;
+ }
+
+ is_updating = true;
+ blender::bke::NodeTreeMainUpdater updater{bmain, params};
+ updater.update_rooted({ntree});
+ is_updating = false;
+}
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index 7fec91ed65a..5045851d7f9 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -1773,8 +1773,9 @@ static void object_update_from_subsurf_ccg(Object *object)
if (!object->runtime.is_data_eval_owned) {
return;
}
- /* Object was never evaluated, so can not have CCG subdivision surface. */
- Mesh *mesh_eval = BKE_object_get_evaluated_mesh(object);
+ /* Object was never evaluated, so can not have CCG subdivision surface. If it were evaluated, do
+ * not try to compute OpenSubDiv on the CPU as it is not needed here. */
+ Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(object);
if (mesh_eval == nullptr) {
return;
}
@@ -3793,7 +3794,7 @@ BoundBox *BKE_boundbox_alloc_unit()
{
const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f};
- BoundBox *bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "OB-BoundBox");
+ BoundBox *bb = MEM_cnew<BoundBox>("OB-BoundBox");
BKE_boundbox_init_from_minmax(bb, min, max);
return bb;
@@ -3903,7 +3904,7 @@ void BKE_object_boundbox_calc_from_mesh(Object *ob, const Mesh *me_eval)
}
if (ob->runtime.bb == nullptr) {
- ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "DM-BoundBox");
+ ob->runtime.bb = MEM_cnew<BoundBox>("DM-BoundBox");
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
@@ -3917,11 +3918,15 @@ bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob)
INIT_MINMAX(min, max);
if (ob->runtime.geometry_set_eval) {
- ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max);
+ if (!ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max)) {
+ zero_v3(min);
+ zero_v3(max);
+ }
}
else if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob)) {
if (!BKE_mesh_wrapper_minmax(mesh_eval, min, max)) {
- return false;
+ zero_v3(min);
+ zero_v3(max);
}
}
else if (ob->runtime.curve_cache) {
@@ -3932,7 +3937,7 @@ bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob)
}
if (ob->runtime.bb == nullptr) {
- ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), __func__);
+ ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
@@ -4108,7 +4113,7 @@ void BKE_object_empty_draw_type_set(Object *ob, const int value)
if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) {
if (!ob->iuser) {
- ob->iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "image user");
+ ob->iuser = MEM_cnew<ImageUser>("image user");
ob->iuser->flag |= IMA_ANIM_ALWAYS;
ob->iuser->frames = 100;
ob->iuser->sfra = 1;
@@ -4447,7 +4452,7 @@ void BKE_object_handle_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
void BKE_object_sculpt_data_create(Object *ob)
{
BLI_assert((ob->sculpt == nullptr) && (ob->mode & OB_MODE_ALL_SCULPT));
- ob->sculpt = (SculptSession *)MEM_callocN(sizeof(SculptSession), __func__);
+ ob->sculpt = MEM_cnew<SculptSession>(__func__);
ob->sculpt->mode_type = (eObjectMode)ob->mode;
}
@@ -4496,7 +4501,7 @@ bool BKE_object_obdata_texspace_get(Object *ob, char **r_texflag, float **r_loc,
return true;
}
-Mesh *BKE_object_get_evaluated_mesh(const Object *object)
+Mesh *BKE_object_get_evaluated_mesh_no_subsurf(const Object *object)
{
/* First attempt to retrieve the evaluated mesh from the evaluated geometry set. Most
* object types either store it there or add a reference to it if it's owned elsewhere. */
@@ -4523,6 +4528,20 @@ Mesh *BKE_object_get_evaluated_mesh(const Object *object)
return nullptr;
}
+Mesh *BKE_object_get_evaluated_mesh(const Object *object)
+{
+ Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(object);
+ if (!mesh) {
+ return nullptr;
+ }
+
+ if (object->data && GS(((const ID *)object->data)->name) == ID_ME) {
+ mesh = BKE_mesh_wrapper_ensure_subdivision(object, mesh);
+ }
+
+ return mesh;
+}
+
Mesh *BKE_object_get_pre_modified_mesh(const Object *object)
{
if (object->type == OB_MESH && object->runtime.data_orig != nullptr) {
@@ -4621,7 +4640,7 @@ int BKE_object_insert_ptcache(Object *ob)
}
}
- link = (LinkData *)MEM_callocN(sizeof(LinkData), "PCLink");
+ link = MEM_cnew<LinkData>("PCLink");
link->data = POINTER_FROM_INT(i);
BLI_addtail(&ob->pc_ids, link);
@@ -5779,6 +5798,21 @@ void BKE_object_modifiers_lib_link_common(void *userData,
}
}
+SubsurfModifierData *BKE_object_get_last_subsurf_modifier(const Object *ob)
+{
+ ModifierData *md = (ModifierData *)(ob->modifiers.last);
+
+ while (md) {
+ if (md->type == eModifierType_Subsurf) {
+ break;
+ }
+
+ md = md->prev;
+ }
+
+ return (SubsurfModifierData *)(md);
+}
+
void BKE_object_replace_data_on_shallow_copy(Object *ob, ID *new_data)
{
ob->type = BKE_object_obdata_to_type(new_data);
diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc
index 9f998b746a2..e682486390c 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -190,7 +190,7 @@ static DupliObject *make_dupli(const DupliContext *ctx,
/* Add a #DupliObject instance to the result container. */
if (ctx->duplilist) {
- dob = (DupliObject *)MEM_callocN(sizeof(DupliObject), "dupli object");
+ dob = MEM_cnew<DupliObject>("dupli object");
BLI_addtail(ctx->duplilist, dob);
}
else {
@@ -1690,7 +1690,7 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob)
{
- ListBase *duplilist = (ListBase *)MEM_callocN(sizeof(ListBase), "duplilist");
+ ListBase *duplilist = MEM_cnew<ListBase>("duplilist");
DupliContext ctx;
Vector<Object *> instance_stack;
instance_stack.append(ob);
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index df76f003498..38575f3048f 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -3505,6 +3505,11 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c
char old_path_full[MAX_PTCACHE_FILE];
char ext[MAX_PTCACHE_PATH];
+ /* If both names are the same, there is nothing to do. */
+ if (STREQ(name_src, name_dst)) {
+ return;
+ }
+
/* save old name */
BLI_strncpy(old_name, pid->cache->name, sizeof(old_name));
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index 82dde79cff6..a041e04bf71 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -25,10 +25,13 @@
#include "DNA_object_types.h"
#include "DNA_pointcloud_types.h"
+#include "BLI_float3.hh"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "BLI_rand.h"
+#include "BLI_span.hh"
#include "BLI_string.h"
+#include "BLI_task.hh"
#include "BLI_utildefines.h"
#include "BKE_anim_data.h"
@@ -51,6 +54,10 @@
#include "BLO_read_write.h"
+using blender::float3;
+using blender::IndexRange;
+using blender::Span;
+
/* PointCloud datablock */
static void pointcloud_random(PointCloud *pointcloud);
@@ -261,18 +268,64 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
return pointcloud;
}
-void BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3])
+struct MinMaxResult {
+ float3 min;
+ float3 max;
+};
+
+static MinMaxResult min_max_no_radii(Span<float3> positions)
+{
+ return blender::threading::parallel_reduce(
+ positions.index_range(),
+ 1024,
+ MinMaxResult{float3(FLT_MAX), float3(-FLT_MAX)},
+ [&](IndexRange range, const MinMaxResult &init) {
+ MinMaxResult result = init;
+ for (const int i : range) {
+ float3::min_max(positions[i], result.min, result.max);
+ }
+ return result;
+ },
+ [](const MinMaxResult &a, const MinMaxResult &b) {
+ return MinMaxResult{float3::min(a.min, b.min), float3::max(a.max, b.max)};
+ });
+}
+
+static MinMaxResult min_max_with_radii(Span<float3> positions, Span<float> radii)
{
- float(*pointcloud_co)[3] = pointcloud->co;
- float *pointcloud_radius = pointcloud->radius;
- for (int a = 0; a < pointcloud->totpoint; a++) {
- float *co = pointcloud_co[a];
- float radius = (pointcloud_radius) ? pointcloud_radius[a] : 0.0f;
- const float co_min[3] = {co[0] - radius, co[1] - radius, co[2] - radius};
- const float co_max[3] = {co[0] + radius, co[1] + radius, co[2] + radius};
- DO_MIN(co_min, r_min);
- DO_MAX(co_max, r_max);
+ return blender::threading::parallel_reduce(
+ positions.index_range(),
+ 1024,
+ MinMaxResult{float3(FLT_MAX), float3(-FLT_MAX)},
+ [&](IndexRange range, const MinMaxResult &init) {
+ MinMaxResult result = init;
+ for (const int i : range) {
+ result.min = float3::min(positions[i] - radii[i], result.min);
+ result.max = float3::max(positions[i] + radii[i], result.max);
+ }
+ return result;
+ },
+ [](const MinMaxResult &a, const MinMaxResult &b) {
+ return MinMaxResult{float3::min(a.min, b.min), float3::max(a.max, b.max)};
+ });
+}
+
+bool BKE_pointcloud_minmax(const PointCloud *pointcloud, float r_min[3], float r_max[3])
+{
+ if (!pointcloud->totpoint) {
+ return false;
}
+
+ Span<float3> positions{reinterpret_cast<float3 *>(pointcloud->co), pointcloud->totpoint};
+ const MinMaxResult min_max = (pointcloud->radius) ?
+ min_max_with_radii(positions,
+ {pointcloud->radius, pointcloud->totpoint}) :
+ min_max_no_radii(positions);
+
+ copy_v3_v3(r_min, float3::min(min_max.min, r_min));
+ copy_v3_v3(r_max, float3::max(min_max.max, r_max));
+
+ return true;
}
BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index cd8493ee559..6e352b6ba90 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -900,7 +900,7 @@ ARegion *BKE_area_find_region_active_win(ScrArea *area)
return BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
}
-ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int y)
+ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, const int xy[2])
{
if (area == NULL) {
return NULL;
@@ -908,7 +908,7 @@ ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (ELEM(regiontype, RGN_TYPE_ANY, region->regiontype)) {
- if (BLI_rcti_isect_pt(&region->winrct, x, y)) {
+ if (BLI_rcti_isect_pt_v(&region->winrct, xy)) {
return region;
}
}
@@ -916,11 +916,11 @@ ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int
return NULL;
}
-ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, int x, int y)
+ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, const int xy[2])
{
LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
if (ELEM(regiontype, RGN_TYPE_ANY, region->regiontype)) {
- if (BLI_rcti_isect_pt(&region->winrct, x, y)) {
+ if (BLI_rcti_isect_pt_v(&region->winrct, xy)) {
return region;
}
}
@@ -961,11 +961,10 @@ ScrArea *BKE_screen_find_big_area(bScreen *screen, const int spacetype, const sh
ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap,
const int spacetype,
- int x,
- int y)
+ const int xy[2])
{
LISTBASE_FOREACH (ScrArea *, area, &areamap->areabase) {
- if (BLI_rcti_isect_pt(&area->totrct, x, y)) {
+ if (BLI_rcti_isect_pt_v(&area->totrct, xy)) {
if (ELEM(spacetype, SPACE_TYPE_ANY, area->spacetype)) {
return area;
}
@@ -974,9 +973,9 @@ ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap,
}
return NULL;
}
-ScrArea *BKE_screen_find_area_xy(bScreen *screen, const int spacetype, int x, int y)
+ScrArea *BKE_screen_find_area_xy(bScreen *screen, const int spacetype, const int xy[2])
{
- return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(screen), spacetype, x, y);
+ return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(screen), spacetype, xy);
}
void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
@@ -1016,16 +1015,13 @@ void BKE_screen_view3d_shading_init(View3DShading *shading)
memcpy(shading, shading_default, sizeof(*shading));
}
-ARegion *BKE_screen_find_main_region_at_xy(bScreen *screen,
- const int space_type,
- const int x,
- const int y)
+ARegion *BKE_screen_find_main_region_at_xy(bScreen *screen, const int space_type, const int xy[2])
{
- ScrArea *area = BKE_screen_find_area_xy(screen, space_type, x, y);
+ ScrArea *area = BKE_screen_find_area_xy(screen, space_type, xy);
if (!area) {
return NULL;
}
- return BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, x, y);
+ return BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, xy);
}
/* Magic zoom calculation, no idea what it signifies, if you find out, tell me! -zr
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
index 4ff392a5ddb..857022345f3 100644
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ b/source/blender/blenkernel/intern/spline_base.cc
@@ -417,7 +417,9 @@ Spline::LookupResult Spline::lookup_evaluated_length(const float length) const
const int next_index = (index == this->evaluated_points_size() - 1) ? 0 : index + 1;
const float previous_length = (index == 0) ? 0.0f : lengths[index - 1];
- const float factor = (length - previous_length) / (lengths[index] - previous_length);
+ const float length_in_segment = length - previous_length;
+ const float segment_length = lengths[index] - previous_length;
+ const float factor = segment_length == 0.0f ? 0.0f : length_in_segment / segment_length;
return LookupResult{index, next_index, factor};
}
diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc
index 9ce285cebb8..b24c8960857 100644
--- a/source/blender/blenkernel/intern/spline_bezier.cc
+++ b/source/blender/blenkernel/intern/spline_bezier.cc
@@ -70,24 +70,6 @@ void BezierSpline::set_resolution(const int value)
this->mark_cache_invalid();
}
-void BezierSpline::add_point(const float3 position,
- const HandleType handle_type_left,
- const float3 handle_position_left,
- const HandleType handle_type_right,
- const float3 handle_position_right,
- const float radius,
- const float tilt)
-{
- handle_types_left_.append(handle_type_left);
- handle_positions_left_.append(handle_position_left);
- positions_.append(position);
- handle_types_right_.append(handle_type_right);
- handle_positions_right_.append(handle_position_right);
- radii_.append(radius);
- tilts_.append(tilt);
- this->mark_cache_invalid();
-}
-
void BezierSpline::resize(const int size)
{
handle_types_left_.resize(size);
diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc
index 69afb82baa8..719ba4b7ecd 100644
--- a/source/blender/blenkernel/intern/spline_nurbs.cc
+++ b/source/blender/blenkernel/intern/spline_nurbs.cc
@@ -81,19 +81,6 @@ void NURBSpline::set_order(const uint8_t value)
this->mark_cache_invalid();
}
-void NURBSpline::add_point(const float3 position,
- const float radius,
- const float tilt,
- const float weight)
-{
- positions_.append(position);
- radii_.append(radius);
- tilts_.append(tilt);
- weights_.append(weight);
- knots_dirty_ = true;
- this->mark_cache_invalid();
-}
-
void NURBSpline::resize(const int size)
{
positions_.resize(size);
@@ -257,13 +244,13 @@ void NURBSpline::calculate_knots() const
Span<float> NURBSpline::knots() const
{
if (!knots_dirty_) {
- BLI_assert(knots_.size() == this->size() + order_);
+ BLI_assert(knots_.size() == this->knots_size());
return knots_;
}
std::lock_guard lock{knots_mutex_};
if (!knots_dirty_) {
- BLI_assert(knots_.size() == this->size() + order_);
+ BLI_assert(knots_.size() == this->knots_size());
return knots_;
}
diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc
index 4af68b5f270..480bbd1dfe8 100644
--- a/source/blender/blenkernel/intern/spline_poly.cc
+++ b/source/blender/blenkernel/intern/spline_poly.cc
@@ -45,14 +45,6 @@ int PolySpline::size() const
return size;
}
-void PolySpline::add_point(const float3 position, const float radius, const float tilt)
-{
- positions_.append(position);
- radii_.append(radius);
- tilts_.append(tilt);
- this->mark_cache_invalid();
-}
-
void PolySpline::resize(const int size)
{
positions_.resize(size);
diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c
index fd32f52351a..45810e29565 100644
--- a/source/blender/blenkernel/intern/subdiv.c
+++ b/source/blender/blenkernel/intern/subdiv.c
@@ -29,6 +29,9 @@
#include "BLI_utildefines.h"
+#include "BKE_modifier.h"
+#include "BKE_subdiv_modifier.h"
+
#include "MEM_guardedalloc.h"
#include "subdiv_converter.h"
@@ -189,6 +192,12 @@ Subdiv *BKE_subdiv_update_from_mesh(Subdiv *subdiv,
void BKE_subdiv_free(Subdiv *subdiv)
{
if (subdiv->evaluator != NULL) {
+ const eOpenSubdivEvaluator evaluator_type = subdiv->evaluator->type;
+ if (evaluator_type != OPENSUBDIV_EVALUATOR_CPU) {
+ /* Let the draw code do the freeing, to ensure that the OpenGL context is valid. */
+ BKE_subsurf_modifier_free_gpu_cache_cb(subdiv);
+ return;
+ }
openSubdiv_deleteEvaluator(subdiv->evaluator);
}
if (subdiv->topology_refiner != NULL) {
@@ -214,12 +223,13 @@ int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv)
}
const int num_coarse_faces = topology_refiner->getNumFaces(topology_refiner);
subdiv->cache_.face_ptex_offset = MEM_malloc_arrayN(
- num_coarse_faces, sizeof(int), "subdiv face_ptex_offset");
+ num_coarse_faces + 1, sizeof(int), "subdiv face_ptex_offset");
int ptex_offset = 0;
for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
const int num_ptex_faces = topology_refiner->getNumFacePtexFaces(topology_refiner, face_index);
subdiv->cache_.face_ptex_offset[face_index] = ptex_offset;
ptex_offset += num_ptex_faces;
}
+ subdiv->cache_.face_ptex_offset[num_coarse_faces] = ptex_offset;
return subdiv->cache_.face_ptex_offset;
}
diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c
index 77962ec924c..7d876acf776 100644
--- a/source/blender/blenkernel/intern/subdiv_ccg.c
+++ b/source/blender/blenkernel/intern/subdiv_ccg.c
@@ -603,7 +603,8 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv,
{
/* Make sure evaluator is ready. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG);
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(
+ subdiv, coarse_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
if (coarse_mesh->totpoly) {
return NULL;
}
diff --git a/source/blender/blenkernel/intern/subdiv_deform.c b/source/blender/blenkernel/intern/subdiv_deform.c
index 7a2d639e4e5..c385b1b291d 100644
--- a/source/blender/blenkernel/intern/subdiv_deform.c
+++ b/source/blender/blenkernel/intern/subdiv_deform.c
@@ -117,7 +117,8 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
const int UNUSED(num_vertices),
const int UNUSED(num_edges),
const int UNUSED(num_loops),
- const int UNUSED(num_polygons))
+ const int UNUSED(num_polygons),
+ const int *UNUSED(subdiv_polygon_offset))
{
SubdivDeformContext *subdiv_context = foreach_context->user_data;
subdiv_mesh_prepare_accumulator(subdiv_context, subdiv_context->coarse_mesh->totvert);
@@ -202,7 +203,8 @@ void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv,
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
/* Make sure evaluator is up to date with possible new topology, and that
* is refined for the new positions of coarse vertices. */
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, vertex_cos)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(
+ subdiv, coarse_mesh, vertex_cos, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index 0001eb8a205..9733a1498a6 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -28,6 +28,7 @@
#include "BLI_bitmap.h"
#include "BLI_math_vector.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BKE_customdata.h"
@@ -38,7 +39,28 @@
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_topology_refiner_capi.h"
-bool BKE_subdiv_eval_begin(Subdiv *subdiv)
+/* ============================ Helper Function ============================ */
+
+static eOpenSubdivEvaluator opensubdiv_evalutor_from_subdiv_evaluator_type(
+ eSubdivEvaluatorType evaluator_type)
+{
+ switch (evaluator_type) {
+ case SUBDIV_EVALUATOR_TYPE_CPU: {
+ return OPENSUBDIV_EVALUATOR_CPU;
+ }
+ case SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE: {
+ return OPENSUBDIV_EVALUATOR_GLSL_COMPUTE;
+ }
+ }
+ BLI_assert_msg(0, "Unknown evaluator type");
+ return OPENSUBDIV_EVALUATOR_CPU;
+}
+
+/* ====================== Main Subdivision Evaluation ====================== */
+
+bool BKE_subdiv_eval_begin(Subdiv *subdiv,
+ eSubdivEvaluatorType evaluator_type,
+ OpenSubdiv_EvaluatorCache *evaluator_cache)
{
BKE_subdiv_stats_reset(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
if (subdiv->topology_refiner == NULL) {
@@ -47,8 +69,11 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv)
return false;
}
if (subdiv->evaluator == NULL) {
+ eOpenSubdivEvaluator opensubdiv_evaluator_type =
+ opensubdiv_evalutor_from_subdiv_evaluator_type(evaluator_type);
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
- subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(subdiv->topology_refiner);
+ subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(
+ subdiv->topology_refiner, opensubdiv_evaluator_type, evaluator_cache);
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
if (subdiv->evaluator == NULL) {
return false;
@@ -80,6 +105,9 @@ static void set_coarse_positions(Subdiv *subdiv,
BLI_BITMAP_ENABLE(vertex_used_map, loop->v);
}
}
+ /* Use a temporary buffer so we do not upload vertices one at a time to the GPU. */
+ float(*buffer)[3] = MEM_mallocN(sizeof(float[3]) * mesh->totvert, "subdiv tmp coarse positions");
+ int manifold_vertex_count = 0;
for (int vertex_index = 0, manifold_vertex_index = 0; vertex_index < mesh->totvert;
vertex_index++) {
if (!BLI_BITMAP_TEST_BOOL(vertex_used_map, vertex_index)) {
@@ -93,13 +121,49 @@ static void set_coarse_positions(Subdiv *subdiv,
const MVert *vertex = &mvert[vertex_index];
vertex_co = vertex->co;
}
- subdiv->evaluator->setCoarsePositions(subdiv->evaluator, vertex_co, manifold_vertex_index, 1);
+ copy_v3_v3(&buffer[manifold_vertex_index][0], vertex_co);
manifold_vertex_index++;
+ manifold_vertex_count++;
}
+ subdiv->evaluator->setCoarsePositions(
+ subdiv->evaluator, &buffer[0][0], 0, manifold_vertex_count);
MEM_freeN(vertex_used_map);
+ MEM_freeN(buffer);
+}
+
+/* Context which is used to fill face varying data in parallel. */
+typedef struct FaceVaryingDataFromUVContext {
+ OpenSubdiv_TopologyRefiner *topology_refiner;
+ const Mesh *mesh;
+ const MLoopUV *mloopuv;
+ float (*buffer)[2];
+ int layer_index;
+} FaceVaryingDataFromUVContext;
+
+static void set_face_varying_data_from_uv_task(void *__restrict userdata,
+ const int face_index,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ FaceVaryingDataFromUVContext *ctx = userdata;
+ OpenSubdiv_TopologyRefiner *topology_refiner = ctx->topology_refiner;
+ const int layer_index = ctx->layer_index;
+ const Mesh *mesh = ctx->mesh;
+ const MPoly *mpoly = &mesh->mpoly[face_index];
+ const MLoopUV *mluv = &ctx->mloopuv[mpoly->loopstart];
+
+ /* TODO(sergey): OpenSubdiv's C-API converter can change winding of
+ * loops of a face, need to watch for that, to prevent wrong UVs assigned.
+ */
+ const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner, face_index);
+ const int *uv_indices = topology_refiner->getFaceFVarValueIndices(
+ topology_refiner, face_index, layer_index);
+ for (int vertex_index = 0; vertex_index < num_face_vertices; vertex_index++, mluv++) {
+ copy_v2_v2(ctx->buffer[uv_indices[vertex_index]], mluv->uv);
+ }
}
static void set_face_varying_data_from_uv(Subdiv *subdiv,
+ const Mesh *mesh,
const MLoopUV *mloopuv,
const int layer_index)
{
@@ -107,25 +171,37 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv,
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
const int num_faces = topology_refiner->getNumFaces(topology_refiner);
const MLoopUV *mluv = mloopuv;
- /* TODO(sergey): OpenSubdiv's C-API converter can change winding of
- * loops of a face, need to watch for that, to prevent wrong UVs assigned.
- */
- for (int face_index = 0; face_index < num_faces; face_index++) {
- const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner,
- face_index);
- const int *uv_indices = topology_refiner->getFaceFVarValueIndices(
- topology_refiner, face_index, layer_index);
- for (int vertex_index = 0; vertex_index < num_face_vertices; vertex_index++, mluv++) {
- evaluator->setFaceVaryingData(evaluator, layer_index, mluv->uv, uv_indices[vertex_index], 1);
- }
- }
+
+ const int num_fvar_values = topology_refiner->getNumFVarValues(topology_refiner, layer_index);
+ /* Use a temporary buffer so we do not upload UVs one at a time to the GPU. */
+ float(*buffer)[2] = MEM_mallocN(sizeof(float[2]) * num_fvar_values, "temp UV storage");
+
+ FaceVaryingDataFromUVContext ctx;
+ ctx.topology_refiner = topology_refiner;
+ ctx.layer_index = layer_index;
+ ctx.mloopuv = mluv;
+ ctx.mesh = mesh;
+ ctx.buffer = buffer;
+
+ TaskParallelSettings parallel_range_settings;
+ BLI_parallel_range_settings_defaults(&parallel_range_settings);
+ parallel_range_settings.min_iter_per_thread = 1;
+
+ BLI_task_parallel_range(
+ 0, num_faces, &ctx, set_face_varying_data_from_uv_task, &parallel_range_settings);
+
+ evaluator->setFaceVaryingData(evaluator, layer_index, &buffer[0][0], 0, num_fvar_values);
+
+ MEM_freeN(buffer);
}
bool BKE_subdiv_eval_begin_from_mesh(Subdiv *subdiv,
const Mesh *mesh,
- const float (*coarse_vertex_cos)[3])
+ const float (*coarse_vertex_cos)[3],
+ eSubdivEvaluatorType evaluator_type,
+ OpenSubdiv_EvaluatorCache *evaluator_cache)
{
- if (!BKE_subdiv_eval_begin(subdiv)) {
+ if (!BKE_subdiv_eval_begin(subdiv, evaluator_type, evaluator_cache)) {
return false;
}
return BKE_subdiv_eval_refine_from_mesh(subdiv, mesh, coarse_vertex_cos);
@@ -146,7 +222,7 @@ bool BKE_subdiv_eval_refine_from_mesh(Subdiv *subdiv,
const int num_uv_layers = CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV);
for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) {
const MLoopUV *mloopuv = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPUV, layer_index);
- set_face_varying_data_from_uv(subdiv, mloopuv, layer_index);
+ set_face_varying_data_from_uv(subdiv, mesh, mloopuv, layer_index);
}
/* Update evaluator to the new coarse geometry. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c
index 061c196df2a..69bead27fe6 100644
--- a/source/blender/blenkernel/intern/subdiv_foreach.c
+++ b/source/blender/blenkernel/intern/subdiv_foreach.c
@@ -1877,7 +1877,8 @@ bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv,
ctx.num_subdiv_vertices,
ctx.num_subdiv_edges,
ctx.num_subdiv_loops,
- ctx.num_subdiv_polygons)) {
+ ctx.num_subdiv_polygons,
+ ctx.subdiv_polygon_offset)) {
subdiv_foreach_ctx_free(&ctx);
return false;
}
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index e5c7d13edab..1f31d0543ad 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -514,7 +514,8 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
const int num_vertices,
const int num_edges,
const int num_loops,
- const int num_polygons)
+ const int num_polygons,
+ const int *UNUSED(subdiv_polygon_offset))
{
/* Multires grid data will be applied or become invalid after subdivision,
* so don't try to preserve it and use memory. */
@@ -1193,7 +1194,8 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
/* Make sure evaluator is up to date with possible new topology, and that
* it is refined for the new positions of coarse vertices. */
- if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, NULL)) {
+ if (!BKE_subdiv_eval_begin_from_mesh(
+ subdiv, coarse_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) {
/* This could happen in two situations:
* - OpenSubdiv is disabled.
* - Something totally bad happened, and OpenSubdiv rejected our
diff --git a/source/blender/blenkernel/intern/subdiv_modifier.c b/source/blender/blenkernel/intern/subdiv_modifier.c
new file mode 100644
index 00000000000..bafcb631f59
--- /dev/null
+++ b/source/blender/blenkernel/intern/subdiv_modifier.c
@@ -0,0 +1,162 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2021 by Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "BKE_subdiv_modifier.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_modifier.h"
+#include "BKE_subdiv.h"
+
+#include "GPU_capabilities.h"
+#include "GPU_context.h"
+
+#include "opensubdiv_capi.h"
+
+void BKE_subsurf_modifier_subdiv_settings_init(SubdivSettings *settings,
+ const SubsurfModifierData *smd,
+ const bool use_render_params)
+{
+ const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels;
+
+ settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
+ settings->is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision);
+ settings->level = settings->is_simple ?
+ 1 :
+ (settings->is_adaptive ? smd->quality : requested_levels);
+ settings->use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease);
+ settings->vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
+ smd->boundary_smooth);
+ settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
+ smd->uv_smooth);
+}
+
+static ModifierData *modifier_get_last_enabled_for_mode(const Scene *scene,
+ const Object *ob,
+ int required_mode)
+{
+ ModifierData *md = ob->modifiers.last;
+
+ while (md) {
+ if (BKE_modifier_is_enabled(scene, md, required_mode)) {
+ break;
+ }
+
+ md = md->prev;
+ }
+
+ return md;
+}
+
+bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const Scene *scene,
+ const Object *ob,
+ const SubsurfModifierData *smd,
+ int required_mode,
+ bool skip_check_is_last)
+{
+ if ((U.gpu_flag & USER_GPU_FLAG_SUBDIVISION_EVALUATION) == 0) {
+ return false;
+ }
+
+ if (!skip_check_is_last) {
+ ModifierData *md = modifier_get_last_enabled_for_mode(scene, ob, required_mode);
+ if (md != (const ModifierData *)smd) {
+ return false;
+ }
+ }
+
+ /* Only OpenGL is supported for OpenSubdiv evaluation for now. */
+ if (GPU_backend_get_type() != GPU_BACKEND_OPENGL) {
+ return false;
+ }
+
+ if (!GPU_compute_shader_support()) {
+ return false;
+ }
+
+ const int available_evaluators = openSubdiv_getAvailableEvaluators();
+ if ((available_evaluators & OPENSUBDIV_EVALUATOR_GLSL_COMPUTE) == 0) {
+ return false;
+ }
+
+ return true;
+}
+
+bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
+ const Object *ob,
+ int required_mode)
+{
+ ModifierData *md = modifier_get_last_enabled_for_mode(scene, ob, required_mode);
+
+ if (!md) {
+ return false;
+ }
+
+ if (md->type != eModifierType_Subsurf) {
+ return false;
+ }
+
+ return BKE_subsurf_modifier_can_do_gpu_subdiv_ex(
+ scene, ob, (SubsurfModifierData *)md, required_mode, true);
+}
+
+void (*BKE_subsurf_modifier_free_gpu_cache_cb)(Subdiv *subdiv) = NULL;
+
+/* Main goal of this function is to give usable subdivision surface descriptor
+ * which matches settings and topology. */
+Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(const SubsurfModifierData *smd,
+ const SubdivSettings *subdiv_settings,
+ const Mesh *mesh,
+ const bool for_draw_code)
+{
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ if (runtime_data->subdiv && runtime_data->set_by_draw_code != for_draw_code) {
+ BKE_subdiv_free(runtime_data->subdiv);
+ runtime_data->subdiv = NULL;
+ }
+ Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_settings, mesh);
+ runtime_data->subdiv = subdiv;
+ runtime_data->set_by_draw_code = for_draw_code;
+ return subdiv;
+}
+
+SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(SubsurfModifierData *smd)
+{
+ SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
+ if (runtime_data == NULL) {
+ runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
+ smd->modifier.runtime = runtime_data;
+ }
+ return runtime_data;
+}
+
+int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode)
+{
+ if (is_final_render) {
+ return eModifierMode_Render;
+ }
+
+ return eModifierMode_Realtime | (is_edit_mode ? eModifierMode_Editmode : 0);
+}
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 130aa957491..4b71c98339b 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -537,7 +537,7 @@ static void volume_copy_data(Main *UNUSED(bmain),
#ifdef WITH_OPENVDB
if (volume_src->runtime.grids) {
const VolumeGridVector &grids_src = *(volume_src->runtime.grids);
- volume_dst->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector, grids_src);
+ volume_dst->runtime.grids = MEM_new<VolumeGridVector>(__func__, grids_src);
}
#endif
@@ -551,7 +551,8 @@ static void volume_free_data(ID *id)
BKE_volume_batch_cache_free(volume);
MEM_SAFE_FREE(volume->mat);
#ifdef WITH_OPENVDB
- OBJECT_GUARDED_SAFE_DELETE(volume->runtime.grids, VolumeGridVector);
+ MEM_delete(volume->runtime.grids);
+ volume->runtime.grids = nullptr;
#endif
}
@@ -683,7 +684,7 @@ void BKE_volume_init_grids(Volume *volume)
{
#ifdef WITH_OPENVDB
if (volume->runtime.grids == nullptr) {
- volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector);
+ volume->runtime.grids = MEM_new<VolumeGridVector>(__func__);
}
#else
UNUSED_VARS(volume);
@@ -954,7 +955,7 @@ BoundBox *BKE_volume_boundbox_get(Object *ob)
}
if (ob->runtime.bb == nullptr) {
- ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), __func__);
+ ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
}
const Volume *volume = (Volume *)ob->data;
@@ -1129,16 +1130,16 @@ void BKE_volume_grids_backup_restore(Volume *volume, VolumeGridVector *grids, co
if (!grids->is_loaded()) {
/* No grids loaded in CoW datablock, nothing lost by discarding. */
- OBJECT_GUARDED_DELETE(grids, VolumeGridVector);
+ MEM_delete(grids);
}
else if (!STREQ(volume->filepath, filepath)) {
/* Filepath changed, discard grids from CoW datablock. */
- OBJECT_GUARDED_DELETE(grids, VolumeGridVector);
+ MEM_delete(grids);
}
else {
/* Keep grids from CoW datablock. We might still unload them a little
* later in BKE_volume_eval_geometry if the frame changes. */
- OBJECT_GUARDED_DELETE(volume->runtime.grids, VolumeGridVector);
+ MEM_delete(volume->runtime.grids);
volume->runtime.grids = grids;
}
#else
diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h
index 6019f0f3566..e32a19cfc25 100644
--- a/source/blender/blenlib/BLI_assert.h
+++ b/source/blender/blenlib/BLI_assert.h
@@ -30,6 +30,7 @@ extern "C" {
#endif
/* Utility functions. */
+
void _BLI_assert_print_pos(const char *file, const int line, const char *function, const char *id);
void _BLI_assert_print_extra(const char *str);
void _BLI_assert_print_backtrace(void);
diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh
index d93bd7f6f76..dce625777b9 100644
--- a/source/blender/blenlib/BLI_color.hh
+++ b/source/blender/blenlib/BLI_color.hh
@@ -73,27 +73,27 @@ namespace blender {
* - Add non RGB spaces/storages ColorXyz.
*/
-/* Enumeration containing the different alpha modes. */
+/** Enumeration containing the different alpha modes. */
enum class eAlpha {
- /* Color and alpha are unassociated. */
+ /** Color and alpha are unassociated. */
Straight,
- /* Color and alpha are associated. */
+ /** Color and alpha are associated. */
Premultiplied,
};
std::ostream &operator<<(std::ostream &stream, const eAlpha &space);
-/* Enumeration containing internal spaces. */
+/** Enumeration containing internal spaces. */
enum class eSpace {
- /* Blender theme color space (sRGB). */
+ /** Blender theme color space (sRGB). */
Theme,
- /* Blender internal scene linear color space (maps to SceneReference role in OCIO). */
+ /** Blender internal scene linear color space (maps to SceneReference role in OCIO). */
SceneLinear,
- /* Blender internal scene linear color space compressed to be stored in 4 uint8_t. */
+ /** Blender internal scene linear color space compressed to be stored in 4 uint8_t. */
SceneLinearByteEncoded,
};
std::ostream &operator<<(std::ostream &stream, const eSpace &space);
-/* Template class to store RGBA values with different precision, space and alpha association. */
+/** Template class to store RGBA values with different precision, space and alpha association. */
template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGBA {
public:
ChannelStorageType r, g, b, a;
@@ -153,11 +153,13 @@ template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGB
};
/* Forward declarations of concrete color classes. */
+
template<eAlpha Alpha> class ColorSceneLinear4f;
template<eAlpha Alpha> class ColorSceneLinearByteEncoded4b;
template<typename ChannelStorageType> class ColorTheme4;
/* Forward declaration of precision conversion methods. */
+
BLI_INLINE ColorTheme4<float> BLI_color_convert_to_theme4f(const ColorTheme4<uint8_t> &srgb4b);
BLI_INLINE ColorTheme4<uint8_t> BLI_color_convert_to_theme4b(const ColorTheme4<float> &srgb4f);
@@ -354,6 +356,7 @@ BLI_color_convert_to_theme4b(const ColorSceneLinear4f<eAlpha::Straight> &scene_l
}
/* Internal roles. For convenience to shorten the type names and hide complexity. */
+
using ColorGeometry4f = ColorSceneLinear4f<eAlpha::Premultiplied>;
using ColorGeometry4b = ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied>;
diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h
index bd8f84cedd6..023fea3853e 100644
--- a/source/blender/blenlib/BLI_compiler_compat.h
+++ b/source/blender/blenlib/BLI_compiler_compat.h
@@ -34,7 +34,7 @@
#if (defined(__GNUC__) || defined(__clang__)) && defined(__cplusplus)
extern "C++" {
-/* Some magic to be sure we don't have reference in the type. */
+/** Some magic to be sure we don't have reference in the type. */
template<typename T> static inline T decltype_helper(T x)
{
return x;
diff --git a/source/blender/blenlib/BLI_delaunay_2d.h b/source/blender/blenlib/BLI_delaunay_2d.h
index 658dcadadce..db0df95499f 100644
--- a/source/blender/blenlib/BLI_delaunay_2d.h
+++ b/source/blender/blenlib/BLI_delaunay_2d.h
@@ -222,7 +222,7 @@ void BLI_delaunay_2d_cdt_free(CDT_result *result);
namespace blender::meshintersect {
-/* vec2<Arith_t> is a 2d vector with Arith_t as the type for coordinates. */
+/** #vec2<Arith_t> is a 2d vector with #Arith_t as the type for coordinates. */
template<typename Arith_t> struct vec2_impl;
template<> struct vec2_impl<double> {
typedef double2 type;
diff --git a/source/blender/blenlib/BLI_dlrbTree.h b/source/blender/blenlib/BLI_dlrbTree.h
index 72f18244d5b..3cf849efaef 100644
--- a/source/blender/blenlib/BLI_dlrbTree.h
+++ b/source/blender/blenlib/BLI_dlrbTree.h
@@ -40,7 +40,7 @@ extern "C" {
/** \name Base Structs
* \{ */
-/* Basic Layout for a Node */
+/** Basic Layout for a Node. */
typedef struct DLRBT_Node {
/* ListBase capabilities */
struct DLRBT_Node *next, *prev;
@@ -53,7 +53,7 @@ typedef struct DLRBT_Node {
/* ... for nice alignment, next item should usually be a char too... */
} DLRBT_Node;
-/* Red/Black defines for tree_col */
+/** Red/Black defines for tree_col. */
typedef enum eDLRBT_Colors {
DLRBT_BLACK = 0,
DLRBT_RED,
@@ -61,7 +61,7 @@ typedef enum eDLRBT_Colors {
/* -------- */
-/* The Tree Data */
+/** The Tree Data. */
typedef struct DLRBT_Tree {
/* ListBase capabilities */
void *first, *last; /* these should be based on DLRBT_Node-s */
diff --git a/source/blender/blenlib/BLI_endian_switch.h b/source/blender/blenlib/BLI_endian_switch.h
index b512133b34c..e6ccbe4629a 100644
--- a/source/blender/blenlib/BLI_endian_switch.h
+++ b/source/blender/blenlib/BLI_endian_switch.h
@@ -30,6 +30,7 @@ extern "C" {
#endif
/* BLI_endian_switch_inline.h */
+
BLI_INLINE void BLI_endian_switch_int16(short *val) ATTR_NONNULL(1);
BLI_INLINE void BLI_endian_switch_uint16(unsigned short *val) ATTR_NONNULL(1);
BLI_INLINE void BLI_endian_switch_int32(int *val) ATTR_NONNULL(1);
@@ -40,6 +41,7 @@ BLI_INLINE void BLI_endian_switch_uint64(uint64_t *val) ATTR_NONNULL(1);
BLI_INLINE void BLI_endian_switch_double(double *val) ATTR_NONNULL(1);
/* endian_switch.c */
+
void BLI_endian_switch_int16_array(short *val, const int size) ATTR_NONNULL(1);
void BLI_endian_switch_uint16_array(unsigned short *val, const int size) ATTR_NONNULL(1);
void BLI_endian_switch_int32_array(int *val, const int size) ATTR_NONNULL(1);
diff --git a/source/blender/blenlib/BLI_endian_switch_inline.h b/source/blender/blenlib/BLI_endian_switch_inline.h
index ec4cfe4801a..31be7fd47e4 100644
--- a/source/blender/blenlib/BLI_endian_switch_inline.h
+++ b/source/blender/blenlib/BLI_endian_switch_inline.h
@@ -33,6 +33,7 @@ extern "C" {
* use bit shifting instead. */
/* *** 16 *** */
+
BLI_INLINE void BLI_endian_switch_int16(short *val)
{
BLI_endian_switch_uint16((unsigned short *)val);
@@ -48,6 +49,7 @@ BLI_INLINE void BLI_endian_switch_uint16(unsigned short *val)
}
/* *** 32 *** */
+
BLI_INLINE void BLI_endian_switch_int32(int *val)
{
BLI_endian_switch_uint32((unsigned int *)val);
@@ -67,6 +69,7 @@ BLI_INLINE void BLI_endian_switch_float(float *val)
}
/* *** 64 *** */
+
BLI_INLINE void BLI_endian_switch_int64(int64_t *val)
{
BLI_endian_switch_uint64((uint64_t *)val);
diff --git a/source/blender/blenlib/BLI_fileops.hh b/source/blender/blenlib/BLI_fileops.hh
new file mode 100644
index 00000000000..c69b1983c59
--- /dev/null
+++ b/source/blender/blenlib/BLI_fileops.hh
@@ -0,0 +1,52 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ * \brief File and directory operations.
+ */
+
+#pragma once
+
+#ifndef __cplusplus
+# error This is a C++ header
+#endif
+
+#include "BLI_fileops.h"
+#include "BLI_string_ref.hh"
+
+#include <fstream>
+#include <string>
+
+namespace blender {
+
+/**
+ * std::fstream subclass that handles UTF-16 encoding on Windows.
+ *
+ * For documentation, see https://en.cppreference.com/w/cpp/io/basic_fstream
+ */
+class fstream : public std::fstream {
+ public:
+ fstream() = default;
+ explicit fstream(const char *filepath,
+ std::ios_base::openmode mode = ios_base::in | ios_base::out);
+ explicit fstream(const std::string &filepath,
+ std::ios_base::openmode mode = ios_base::in | ios_base::out);
+
+ void open(StringRefNull filepath, ios_base::openmode mode = ios_base::in | ios_base::out);
+};
+
+} // namespace blender
diff --git a/source/blender/blenlib/BLI_filereader.h b/source/blender/blenlib/BLI_filereader.h
index da223cddf40..f232ad72cc4 100644
--- a/source/blender/blenlib/BLI_filereader.h
+++ b/source/blender/blenlib/BLI_filereader.h
@@ -47,7 +47,7 @@ typedef ssize_t (*FileReaderReadFn)(struct FileReader *reader, void *buffer, siz
typedef off64_t (*FileReaderSeekFn)(struct FileReader *reader, off64_t offset, int whence);
typedef void (*FileReaderCloseFn)(struct FileReader *reader);
-/* General structure for all FileReaders, implementations add custom fields at the end. */
+/** General structure for all #FileReaders, implementations add custom fields at the end. */
typedef struct FileReader {
FileReaderReadFn read;
FileReaderSeekFn seek;
@@ -64,16 +64,16 @@ typedef struct FileReader {
* take over the base FileReader and will clean it up when their clean() is called.
*/
-/* Create FileReader from raw file descriptor. */
+/** Create #FileReader from raw file descriptor. */
FileReader *BLI_filereader_new_file(int filedes) ATTR_WARN_UNUSED_RESULT;
-/* Create FileReader from raw file descriptor using memory-mapped IO. */
+/** Create #FileReader from raw file descriptor using memory-mapped IO. */
FileReader *BLI_filereader_new_mmap(int filedes) ATTR_WARN_UNUSED_RESULT;
-/* Create FileReader from a region of memory. */
+/** Create #FileReader from a region of memory. */
FileReader *BLI_filereader_new_memory(const void *data, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL();
-/* Create FileReader from applying `Zstd` decompression on an underlying file. */
+/** Create #FileReader from applying `Zstd` decompression on an underlying file. */
FileReader *BLI_filereader_new_zstd(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* Create FileReader from applying `Gzip` decompression on an underlying file. */
+/** Create #FileReader from applying `Gzip` decompression on an underlying file. */
FileReader *BLI_filereader_new_gzip(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#ifdef __cplusplus
diff --git a/source/blender/blenlib/BLI_float3.hh b/source/blender/blenlib/BLI_float3.hh
index 6ee0c4b973b..765f524fb31 100644
--- a/source/blender/blenlib/BLI_float3.hh
+++ b/source/blender/blenlib/BLI_float3.hh
@@ -228,6 +228,22 @@ struct float3 {
return result;
}
+ static float3 min(const float3 &a, const float3 &b)
+ {
+ return {a.x < b.x ? a.x : b.x, a.y < b.y ? a.y : b.y, a.z < b.z ? a.z : b.z};
+ }
+
+ static float3 max(const float3 &a, const float3 &b)
+ {
+ return {a.x > b.x ? a.x : b.x, a.y > b.y ? a.y : b.y, a.z > b.z ? a.z : b.z};
+ }
+
+ static void min_max(const float3 &vector, float3 &min, float3 &max)
+ {
+ min = float3::min(vector, min);
+ max = float3::max(vector, max);
+ }
+
static float3 safe_divide(const float3 &a, const float b)
{
return (b != 0.0f) ? a / b : float3(0.0f);
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index 0194f9aad40..fca705535a3 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -450,7 +450,7 @@ void *BLI_gset_pop_key(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
/* rely on inline api for now */
-/* so we can cast but compiler sees as different */
+/** Use a GSet specific type so we can cast but compiler sees as different */
typedef struct GSetIterator {
GHashIterator _ghi
#if defined(__GNUC__) && !defined(__clang__)
diff --git a/source/blender/blenlib/BLI_hash.hh b/source/blender/blenlib/BLI_hash.hh
index 11ff7d040aa..9132aacf7b9 100644
--- a/source/blender/blenlib/BLI_hash.hh
+++ b/source/blender/blenlib/BLI_hash.hh
@@ -243,6 +243,16 @@ uint64_t get_default_hash_3(const T1 &v1, const T2 &v2, const T3 &v3)
return h1 ^ (h2 * 19349669) ^ (h3 * 83492791);
}
+template<typename T1, typename T2, typename T3, typename T4>
+uint64_t get_default_hash_4(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4)
+{
+ const uint64_t h1 = get_default_hash(v1);
+ const uint64_t h2 = get_default_hash(v2);
+ const uint64_t h3 = get_default_hash(v3);
+ const uint64_t h4 = get_default_hash(v4);
+ return h1 ^ (h2 * 19349669) ^ (h3 * 83492791) ^ (h4 * 3632623);
+}
+
template<typename T> struct DefaultHash<std::unique_ptr<T>> {
uint64_t operator()(const std::unique_ptr<T> &value) const
{
diff --git a/source/blender/blenlib/BLI_kdtree_impl.h b/source/blender/blenlib/BLI_kdtree_impl.h
index 26a22fc2ac4..35dbf141c92 100644
--- a/source/blender/blenlib/BLI_kdtree_impl.h
+++ b/source/blender/blenlib/BLI_kdtree_impl.h
@@ -74,7 +74,7 @@ int BLI_kdtree_nd_(calc_duplicates_fast)(const KDTree *tree,
int BLI_kdtree_nd_(deduplicate)(KDTree *tree);
-/* Versions of find/range search that take a squared distance callback to support bias. */
+/** Versions of find/range search that take a squared distance callback to support bias. */
int BLI_kdtree_nd_(find_nearest_n_with_len_squared_cb)(
const KDTree *tree,
const float co[KD_DIMS],
diff --git a/source/blender/blenlib/BLI_linklist_lockfree.h b/source/blender/blenlib/BLI_linklist_lockfree.h
index 142fa1cf243..d2083bdd44e 100644
--- a/source/blender/blenlib/BLI_linklist_lockfree.h
+++ b/source/blender/blenlib/BLI_linklist_lockfree.h
@@ -48,18 +48,19 @@ typedef void (*LockfreeeLinkNodeFreeFP)(void *link);
/* NOTE: These functions are NOT safe for use from threads. */
/* NOTE: !!! I REPEAT: DO NOT USE THEM WITHOUT EXTERNAL LOCK !!! */
-/* Make list ready for lock-free access. */
+/** Make list ready for lock-free access. */
void BLI_linklist_lockfree_init(LockfreeLinkList *list);
-/* Completely free the whole list, it is NOT re-usable after this. */
+/** Completely free the whole list, it is NOT re-usable after this. */
void BLI_linklist_lockfree_free(LockfreeLinkList *list, LockfreeeLinkNodeFreeFP free_func);
-/* Remove all the elements from the list, keep it usable for further
- * inserts.
+/**
+ * Remove all the elements from the list, keep it usable for further inserts.
*/
void BLI_linklist_lockfree_clear(LockfreeLinkList *list, LockfreeeLinkNodeFreeFP free_func);
-/* Begin iteration of lock-free linked list, starting with a
+/**
+ * Begin iteration of lock-free linked list, starting with a
* first user=defined node. Will ignore the dummy node.
*/
LockfreeLinkNode *BLI_linklist_lockfree_begin(LockfreeLinkList *list);
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index 7d808d339e9..a2a6e958213 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -46,6 +46,11 @@ int BLI_findstringindex(const struct ListBase *listbase,
const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+/**
+ * Return a ListBase representing the entire list the given Link is in.
+ */
+ListBase BLI_listbase_from_link(struct Link *some_link);
+
/* Find forwards. */
/**
@@ -279,6 +284,23 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
}
/**
+ * Equality check for ListBase.
+ *
+ * This only shallowly compares the ListBase itself (so the first/last
+ * pointers), and does not do any equality checks on the list items.
+ */
+BLI_INLINE bool BLI_listbase_equal(const struct ListBase *a, const struct ListBase *b)
+{
+ if (a == NULL) {
+ return b == NULL;
+ }
+ if (b == NULL) {
+ return false;
+ }
+ return a->first == b->first && a->last == b->last;
+}
+
+/**
* Create a generic list node containing link to provided data.
*/
struct LinkData *BLI_genericNodeN(void *data);
@@ -353,3 +375,10 @@ struct LinkData *BLI_genericNodeN(void *data);
#ifdef __cplusplus
}
#endif
+
+#ifdef __cplusplus
+BLI_INLINE bool operator==(const ListBase &a, const ListBase &b)
+{
+ return BLI_listbase_equal(&a, &b);
+}
+#endif
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 83822481112..6c82bd89e64 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -76,8 +76,7 @@
#if defined(__GNUC__)
# define NAN_FLT __builtin_nanf("")
-#else
-/* evil quiet NaN definition */
+#else /* evil quiet NaN definition */
static const int NAN_INT = 0x7FC00000;
# define NAN_FLT (*((float *)(&NAN_INT)))
#endif
@@ -97,7 +96,8 @@ extern "C" {
/******************************* Float ******************************/
-/* powf is really slow for raising to integer powers. */
+/* `powf` is really slow for raising to integer powers. */
+
MINLINE float pow2f(float x);
MINLINE float pow3f(float x);
MINLINE float pow4f(float x);
diff --git a/source/blender/blenlib/BLI_math_bits.h b/source/blender/blenlib/BLI_math_bits.h
index e881f1a0e4e..70a54879446 100644
--- a/source/blender/blenlib/BLI_math_bits.h
+++ b/source/blender/blenlib/BLI_math_bits.h
@@ -28,24 +28,29 @@ extern "C" {
#endif
/* Search the value from LSB to MSB for a set bit. Returns index of this bit. */
+
MINLINE int bitscan_forward_i(int a);
MINLINE unsigned int bitscan_forward_uint(unsigned int a);
MINLINE unsigned int bitscan_forward_uint64(unsigned long long a);
/* Similar to above, but also clears the bit. */
+
MINLINE int bitscan_forward_clear_i(int *a);
MINLINE unsigned int bitscan_forward_clear_uint(unsigned int *a);
/* Search the value from MSB to LSB for a set bit. Returns index of this bit. */
+
MINLINE int bitscan_reverse_i(int a);
MINLINE unsigned int bitscan_reverse_uint(unsigned int a);
MINLINE unsigned int bitscan_reverse_uint64(unsigned long long a);
/* Similar to above, but also clears the bit. */
+
MINLINE int bitscan_reverse_clear_i(int *a);
MINLINE unsigned int bitscan_reverse_clear_uint(unsigned int *a);
/* NOTE: Those functions returns 2 to the power of index of highest order bit. */
+
MINLINE unsigned int highest_order_bit_uint(unsigned int n);
MINLINE unsigned short highest_order_bit_s(unsigned short n);
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 55d118d17de..c2a5ffafa64 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -441,7 +441,9 @@ void isect_seg_seg_v3(const float a0[3],
float r_a[3],
float r_b[3]);
-/* intersect Line-Line, shorts */
+/**
+ * Intersect Line-Line, integer.
+ */
int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2]);
/**
* Get intersection point of two 2D segments.
@@ -929,7 +931,7 @@ void interp_weights_quad_v3(float w[4],
void interp_weights_poly_v3(float w[], float v[][3], const int n, const float co[3]);
void interp_weights_poly_v2(float w[], float v[][2], const int n, const float co[2]);
-/* (x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t) */
+/** `(x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t)`. */
void interp_cubic_v3(float x[3],
float v[3],
const float x1[3],
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 3d8fe6f564a..90b74e2f504 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -56,16 +56,18 @@ void copy_m4_m2(float m1[4][4], const float m2[2][2]);
void copy_m4_m4_db(double m1[4][4], const double m2[4][4]);
/* double->float */
+
void copy_m3_m3d(float m1[3][3], const double m2[3][3]);
/* float->double */
+
void copy_m3d_m3(double m1[3][3], const float m2[3][3]);
void copy_m4d_m4(double m1[4][4], const float m2[4][4]);
void swap_m3m3(float m1[3][3], float m2[3][3]);
void swap_m4m4(float m1[4][4], float m2[4][4]);
-/* Build index shuffle matrix */
+/** Build index shuffle matrix. */
void shuffle_m4(float R[4][4], const int index[4]);
/** \} */
@@ -112,7 +114,8 @@ void mul_m4db_m4db_m4fl_uniq(double R[4][4], const double A[4][4], const float B
void mul_m4_m4_pre(float R[4][4], const float A[4][4]);
void mul_m4_m4_post(float R[4][4], const float B[4][4]);
-/* mul_m3_series */
+/* Implement #mul_m3_series macro. */
+
void _va_mul_m3_series_3(float R[3][3], const float M1[3][3], const float M2[3][3]) ATTR_NONNULL();
void _va_mul_m3_series_4(float R[3][3],
const float M1[3][3],
@@ -153,7 +156,9 @@ void _va_mul_m3_series_9(float R[3][3],
const float M6[3][3],
const float M7[3][3],
const float M8[3][3]) ATTR_NONNULL();
-/* mul_m4_series */
+
+/* Implement #mul_m4_series macro. */
+
void _va_mul_m4_series_3(float R[4][4], const float M1[4][4], const float M2[4][4]) ATTR_NONNULL();
void _va_mul_m4_series_4(float R[4][4],
const float M1[4][4],
@@ -266,11 +271,13 @@ bool invert_m4_m4(float R[4][4], const float A[4][4]);
*/
bool invert_m4_m4_fallback(float R[4][4], const float A[4][4]);
-/* double arithmetic (mixed float/double) */
+/* Double arithmetic (mixed float/double). */
+
void mul_m4_v4d(const float M[4][4], double r[4]);
void mul_v4d_m4v4d(double r[4], const float M[4][4], const double v[4]);
-/* double matrix functions (no mixing types) */
+/* Double matrix functions (no mixing types). */
+
void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3]);
void mul_m3_v3_db(const double M[3][3], double r[3]);
@@ -282,7 +289,9 @@ void mul_m3_v3_db(const double M[3][3], double r[3]);
void transpose_m3(float R[3][3]);
void transpose_m3_m3(float R[3][3], const float M[3][3]);
-/* seems obscure but in-fact a common operation */
+/**
+ * \note Seems obscure but in-fact a common operation.
+ */
void transpose_m3_m4(float R[3][3], const float M[4][4]);
void transpose_m4(float R[4][4]);
void transpose_m4_m4(float R[4][4], const float M[4][4]);
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index 5e72d502262..8106251684d 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -57,7 +57,8 @@ void unit_axis_angle(float axis[3], float *angle);
void unit_qt(float q[4]);
void copy_qt_qt(float q[4], const float a[4]);
-/* arithmetic */
+/* Arithmetic. */
+
void mul_qt_qtqt(float q[4], const float a[4], const float b[4]);
/**
* \note
@@ -106,7 +107,8 @@ float dot_qtqt(const float a[4], const float b[4]);
float normalize_qt(float q[4]);
float normalize_qt_qt(float r[4], const float q[4]);
-/* comparison */
+/* Comparison. */
+
bool is_zero_qt(const float q[4]);
/* interpolation */
@@ -122,7 +124,8 @@ void interp_dot_slerp(const float t, const float cosom, float r_w[2]);
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
-/* conversion */
+/* Conversion. */
+
void quat_to_mat3(float mat[3][3], const float q[4]);
void quat_to_mat4(float mat[4][4], const float q[4]);
@@ -188,7 +191,8 @@ float angle_signed_qtqt(const float q1[4], const float q2[4]);
*/
void mat3_to_quat_is_ok(float q[4], const float mat[3][3]);
-/* other */
+/* Other. */
+
void print_qt(const char *str, const float q[4]);
#define print_qt_id(q) print_qt(STRINGIFY(q), q)
@@ -199,7 +203,8 @@ void print_qt(const char *str, const float q[4]);
/** \name Axis Angle
* \{ */
-/* conversion */
+/* Conversion. */
+
void axis_angle_normalized_to_quat(float r[4], const float axis[3], const float angle);
void axis_angle_to_quat(float r[4], const float axis[3], const float angle);
/**
@@ -271,32 +276,25 @@ void expmap_to_quat(float r[4], const float expmap[3]);
/** \name XYZ Eulers
* \{ */
-/* XYZ order. */
void eul_to_quat(float quat[4], const float eul[3]);
-/* XYZ order */
void eul_to_mat3(float mat[3][3], const float eul[3]);
-/* XYZ order */
void eul_to_mat4(float mat[4][4], const float eul[3]);
-/* XYZ order */
void mat3_normalized_to_eul(float eul[3], const float mat[3][3]);
-/* XYZ order */
void mat4_normalized_to_eul(float eul[3], const float mat[4][4]);
void mat3_to_eul(float eul[3], const float mat[3][3]);
void mat4_to_eul(float eul[3], const float mat[4][4]);
-/* XYZ order */
void quat_to_eul(float eul[3], const float quat[4]);
-/* XYZ order */
void mat3_normalized_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void mat3_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float quat[4]);
-/* order independent! */
-void compatible_eul(float eul[3], const float old[3]);
-
-/* XYZ order */
void rotate_eul(float eul[3], const char axis, const float angle);
+/* Order independent. */
+
+void compatible_eul(float eul[3], const float old[3]);
+
void add_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
void sub_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 8f955076baf..61090e30f7b 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -79,7 +79,9 @@ MINLINE void copy_v4_v4_char(char r[4], const char a[4]);
MINLINE void copy_v2_v2_short(short r[2], const short a[2]);
MINLINE void copy_v3_v3_short(short r[3], const short a[3]);
MINLINE void copy_v4_v4_short(short r[4], const short a[4]);
+
/* int */
+
MINLINE void zero_v3_int(int r[3]);
MINLINE void copy_v2_v2_int(int r[2], const int a[2]);
MINLINE void copy_v3_v3_int(int r[3], const int a[3]);
diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh
index 14eca49d126..9a5be79b61e 100644
--- a/source/blender/blenlib/BLI_memory_utils.hh
+++ b/source/blender/blenlib/BLI_memory_utils.hh
@@ -498,6 +498,12 @@ inline constexpr bool is_span_convertible_pointer_v =
std::is_same_v<To, const void *>);
/**
+ * Same as #std::is_same_v but allows for checking multiple types at the same time.
+ */
+template<typename T, typename... Args>
+inline constexpr bool is_same_any_v = (std::is_same_v<T, Args> || ...);
+
+/**
* Inline buffers for small-object-optimization should be disable by default. Otherwise we might
* get large unexpected allocations on the stack.
*/
diff --git a/source/blender/blenlib/BLI_mempool.h b/source/blender/blenlib/BLI_mempool.h
index d6abae36e00..a3cf2a77646 100644
--- a/source/blender/blenlib/BLI_mempool.h
+++ b/source/blender/blenlib/BLI_mempool.h
@@ -103,14 +103,14 @@ void BLI_mempool_set_memory_debug(void);
* \note this may easy to produce bugs with.
*/
-/* Private structure. */
+/** \note Private structure. */
typedef struct BLI_mempool_iter {
BLI_mempool *pool;
struct BLI_mempool_chunk *curchunk;
unsigned int curindex;
} BLI_mempool_iter;
-/* flag */
+/** #BLI_mempool.flag */
enum {
BLI_MEMPOOL_NOP = 0,
/** allow iterating on this mempool.
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index 8b54ee52322..70eb80e7763 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -254,6 +254,10 @@ void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2);
/**
* Make given name safe to be used in paths.
*
+ * \param allow_tokens: Permit the usage of '<' and '>' characters. This can be
+ * leveraged by higher layers to support "virtual filenames" which contain
+ * substitution markers delineated between the two characters.
+ *
* \return true if \a fname was changed, false otherwise.
*
* For now, simply replaces reserved chars (as listed in
@@ -273,7 +277,9 @@ void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2);
* \note On Windows, it also checks for forbidden names
* (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
*/
+bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens) ATTR_NONNULL(1);
bool BLI_filename_make_safe(char *fname) ATTR_NONNULL(1);
+
/**
* Make given path OS-safe.
*
diff --git a/source/blender/blenlib/BLI_quadric.h b/source/blender/blenlib/BLI_quadric.h
index fdb7d1e67ac..450653a20ea 100644
--- a/source/blender/blenlib/BLI_quadric.h
+++ b/source/blender/blenlib/BLI_quadric.h
@@ -31,18 +31,21 @@ typedef struct Quadric {
double a2, ab, ac, ad, b2, bc, bd, c2, cd, d2;
} Quadric;
-/* conversion */
+/* Conversion. */
+
void BLI_quadric_from_plane(Quadric *q, const double v[4]);
void BLI_quadric_to_vector_v3(const Quadric *q, double v[3]);
void BLI_quadric_clear(Quadric *q);
-/* math */
+/* Math operations. */
+
void BLI_quadric_add_qu_qu(Quadric *a, const Quadric *b);
void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b);
void BLI_quadric_mul(Quadric *a, const double scalar);
-/* solve */
+/* Solve. */
+
double BLI_quadric_evaluate(const Quadric *q, const double v[3]);
bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon);
diff --git a/source/blender/blenlib/BLI_scanfill.h b/source/blender/blenlib/BLI_scanfill.h
index 744d30397d4..ec7fa8f27a0 100644
--- a/source/blender/blenlib/BLI_scanfill.h
+++ b/source/blender/blenlib/BLI_scanfill.h
@@ -91,6 +91,7 @@ typedef struct ScanFillFace {
} ScanFillFace;
/* scanfill.c */
+
struct ScanFillVert *BLI_scanfill_vert_add(ScanFillContext *sf_ctx, const float vec[3]);
struct ScanFillEdge *BLI_scanfill_edge_add(ScanFillContext *sf_ctx,
struct ScanFillVert *v1,
diff --git a/source/blender/blenlib/BLI_serialize.hh b/source/blender/blenlib/BLI_serialize.hh
index 051731ab801..5945960c450 100644
--- a/source/blender/blenlib/BLI_serialize.hh
+++ b/source/blender/blenlib/BLI_serialize.hh
@@ -36,7 +36,7 @@
* - DoubleValue: for double precision floating point numbers
* - BooleanValue: for boolean values
* - ArrayValue: An array of any supported value.
- * - ObjectValue: A key value pair where keys are std::string.
+ * - DictionaryValue: A key value pair where keys are std::string.
* - NullValue: for null values.
*
* # Basic usage
@@ -92,12 +92,12 @@ enum class eValueType {
Null,
Boolean,
Double,
- Object,
+ Dictionary,
};
class Value;
class StringValue;
-class ObjectValue;
+class DictionaryValue;
template<typename T, eValueType V> class PrimitiveValue;
using IntValue = PrimitiveValue<int64_t, eValueType::Int>;
using DoubleValue = PrimitiveValue<double, eValueType::Double>;
@@ -122,8 +122,8 @@ using ArrayValue = ContainerValue<Vector<std::shared_ptr<Value>>, eValueType::Ar
* - `NullValue`: represents nothing (null pointer or optional).
* - `BooleanValue`: contains a boolean (true/false).
* - `DoubleValue`: contains a double precision floating point number.
- * - `ObjectValue`: represents an object (key value pairs where keys are strings and values can be
- * of different types.
+ * - `DictionaryValue`: represents an object (key value pairs where keys are strings and values can
+ * be of different types.
*
*/
class Value {
@@ -174,10 +174,10 @@ class Value {
const ArrayValue *as_array_value() const;
/**
- * Casts to an ObjectValue.
+ * Casts to an DictionaryValue.
* Will return nullptr when it is a different type.
*/
- const ObjectValue *as_object_value() const;
+ const DictionaryValue *as_dictionary_value() const;
};
/**
@@ -228,7 +228,7 @@ class StringValue : public Value {
/**
* Template for arrays and objects.
*
- * Both ArrayValue and ObjectValue store their values in an array.
+ * Both ArrayValue and DictionaryValue store their values in an array.
*/
template<
/** The container type where the elements are stored in. */
@@ -264,18 +264,19 @@ class ContainerValue : public Value {
};
/**
- * Internal storage type for ObjectValue.
+ * Internal storage type for DictionaryValue.
*
* The elements are stored as an key value pair. The value is a shared pointer so it can be shared
- * when using `ObjectValue::create_lookup`.
+ * when using `DictionaryValue::create_lookup`.
*/
-using ObjectElementType = std::pair<std::string, std::shared_ptr<Value>>;
+using DictionaryElementType = std::pair<std::string, std::shared_ptr<Value>>;
/**
* Object is a key-value container where the key must be a std::string.
* Internally it is stored in a blender::Vector to ensure the order of keys.
*/
-class ObjectValue : public ContainerValue<Vector<ObjectElementType>, eValueType::Object> {
+class DictionaryValue
+ : public ContainerValue<Vector<DictionaryElementType>, eValueType::Dictionary> {
public:
using LookupValue = std::shared_ptr<Value>;
using Lookup = Map<std::string, LookupValue>;
diff --git a/source/blender/blenlib/BLI_session_uuid.h b/source/blender/blenlib/BLI_session_uuid.h
index 887044e9b54..29e291add5a 100644
--- a/source/blender/blenlib/BLI_session_uuid.h
+++ b/source/blender/blenlib/BLI_session_uuid.h
@@ -33,18 +33,19 @@ extern "C" {
#include "DNA_session_uuid_types.h"
-/* Generate new UUID which is unique throughout the Blender session. */
+/** Generate new UUID which is unique throughout the Blender session. */
SessionUUID BLI_session_uuid_generate(void);
-/* Check whether the UUID is properly generated. */
+/** Check whether the UUID is properly generated. */
bool BLI_session_uuid_is_generated(const SessionUUID *uuid);
-/* Check whether two UUIDs are identical. */
+/** Check whether two UUIDs are identical. */
bool BLI_session_uuid_is_equal(const SessionUUID *lhs, const SessionUUID *rhs);
uint64_t BLI_session_uuid_hash_uint64(const SessionUUID *uuid);
/* Utility functions to make it possible to create GHash/GSet with UUID as a key. */
+
uint BLI_session_uuid_ghash_hash(const void *uuid_v);
bool BLI_session_uuid_ghash_compare(const void *lhs_v, const void *rhs_v);
diff --git a/source/blender/blenlib/BLI_sort.h b/source/blender/blenlib/BLI_sort.h
index 969816086e2..31a052eb79d 100644
--- a/source/blender/blenlib/BLI_sort.h
+++ b/source/blender/blenlib/BLI_sort.h
@@ -30,7 +30,7 @@
# define BLI_qsort_r qsort_r
#endif
-/* Quick sort re-entrant */
+/** Quick sort (re-entrant). */
typedef int (*BLI_sort_cmp_t)(const void *a, const void *b, void *ctx);
void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh
index 5b7981e0302..995dc70a84d 100644
--- a/source/blender/blenlib/BLI_span.hh
+++ b/source/blender/blenlib/BLI_span.hh
@@ -599,6 +599,11 @@ template<typename T> class MutableSpan {
return MutableSpan(data_ + start, new_size);
}
+ constexpr MutableSpan slice(IndexRange range) const
+ {
+ return this->slice(range.start(), range.size());
+ }
+
/**
* Returns a new MutableSpan with n elements removed from the beginning. This invokes
* undefined behavior when n is negative.
diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h
index 2740e3740f2..95327ff33b8 100644
--- a/source/blender/blenlib/BLI_sys_types.h
+++ b/source/blender/blenlib/BLI_sys_types.h
@@ -72,8 +72,8 @@ typedef uint64_t u_int64_t;
#include <stddef.h> /* size_t define */
#ifndef __cplusplus
+/* The <uchar.h> standard header is missing on some systems. */
# if defined(__APPLE__) || defined(__NetBSD__)
-/* The <uchar.h> standard header is missing on macOS. */
typedef unsigned int char32_t;
# else
# include <uchar.h>
diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h
index 0d5b2e6e2df..2e5e07d8407 100644
--- a/source/blender/blenlib/BLI_system.h
+++ b/source/blender/blenlib/BLI_system.h
@@ -30,7 +30,7 @@ int BLI_cpu_support_sse2(void);
int BLI_cpu_support_sse41(void);
void BLI_system_backtrace(FILE *fp);
-/* Get CPU brand, result is to be MEM_freeN()-ed. */
+/** Get CPU brand, result is to be MEM_freeN()-ed. */
char *BLI_cpu_brand_string(void);
/**
@@ -45,15 +45,19 @@ char *BLI_cpu_brand_string(void);
*/
void BLI_hostname_get(char *buffer, size_t bufsize);
-/* Get maximum addressable memory in megabytes. */
+/** Get maximum addressable memory in megabytes. */
size_t BLI_system_memory_max_in_megabytes(void);
+/** Get maximum addressable memory in megabytes (clamped to #INT_MAX). */
int BLI_system_memory_max_in_megabytes_int(void);
/* For `getpid`. */
#ifdef WIN32
# define BLI_SYSTEM_PID_H <process.h>
-/* void* since we really do not want to drag Windows.h in to get the proper typedef. */
+/**
+ * \note Use `void *` for `exception` since we really do not want to drag Windows.h
+ * in to get the proper `typedef`.
+ */
void BLI_windows_handle_exception(void *exception);
#else
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index a67de2e2910..616237bc261 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -303,7 +303,7 @@ void BLI_task_parallel_mempool(struct BLI_mempool *mempool,
TaskParallelMempoolFunc func,
const TaskParallelSettings *settings);
-/* TODO(sergey): Think of a better place for this. */
+/** TODO(sergey): Think of a better place for this. */
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
{
memset(settings, 0, sizeof(*settings));
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index 6e60430ea38..7bae16f25ef 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -31,7 +31,7 @@
extern "C" {
#endif
-/* for tables, button in UI, etc */
+/** For tables, button in UI, etc. */
#define BLENDER_MAX_THREADS 1024
struct ListBase;
diff --git a/source/blender/blenlib/BLI_timer.h b/source/blender/blenlib/BLI_timer.h
index c219b5502f3..b1cc8d5514f 100644
--- a/source/blender/blenlib/BLI_timer.h
+++ b/source/blender/blenlib/BLI_timer.h
@@ -29,8 +29,11 @@
extern "C" {
#endif
-/* ret < 0: the timer will be removed.
- * ret >= 0: the timer will be called again in ret seconds */
+/**
+ * \return A value of:
+ * - < 0: the timer will be removed.
+ * - >= 0: the timer will be called again in this number of seconds.
+ */
typedef double (*BLI_timer_func)(uintptr_t uuid, void *user_data);
typedef void (*BLI_timer_data_free)(uintptr_t uuid, void *user_data);
@@ -45,10 +48,10 @@ void BLI_timer_register(uintptr_t uuid,
bool BLI_timer_is_registered(uintptr_t uuid);
-/* Returns False when the timer does not exist (anymore). */
+/** Returns False when the timer does not exist (anymore). */
bool BLI_timer_unregister(uintptr_t uuid);
-/* Execute all registered functions that are due. */
+/** Execute all registered functions that are due. */
void BLI_timer_execute(void);
void BLI_timer_free(void);
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index d2b94a6d8ef..4ac48f259cf 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -637,7 +637,7 @@ class Vector {
* Insert values at the beginning of the vector. The has to move all the other elements, so it
* has a linear running time.
*/
- void prepend(const T &&value)
+ void prepend(const T &value)
{
this->insert(0, value);
}
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index 5103ac4b668..86ac95e2c77 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -44,7 +44,7 @@
namespace blender {
-/* Forward declarations for generic virtual arrays. */
+/** Forward declarations for generic virtual arrays. */
namespace fn {
class GVArray;
class GVMutableArray;
@@ -194,7 +194,7 @@ template<typename T> class VArrayImpl {
}
};
-/* Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */
+/** Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */
template<typename T> class VMutableArrayImpl : public VArrayImpl<T> {
public:
using VArrayImpl<T>::VArrayImpl;
@@ -477,9 +477,9 @@ template<typename T> struct VArrayAnyExtraInfo {
template<typename StorageT> static VArrayAnyExtraInfo get()
{
/* These are the only allowed types in the #Any. */
- static_assert(std::is_base_of_v<VArrayImpl<T>, StorageT> ||
- std::is_same_v<StorageT, const VArrayImpl<T> *> ||
- std::is_same_v<StorageT, std::shared_ptr<const VArrayImpl<T>>>);
+ static_assert(
+ std::is_base_of_v<VArrayImpl<T>, StorageT> ||
+ is_same_any_v<StorageT, const VArrayImpl<T> *, std::shared_ptr<const VArrayImpl<T>>>);
/* Depending on how the virtual array implementation is stored in the #Any, a different
* #get_varray function is required. */
diff --git a/source/blender/blenlib/BLI_virtual_vector_array.hh b/source/blender/blenlib/BLI_virtual_vector_array.hh
index ab5afd2d80a..7672a76d5de 100644
--- a/source/blender/blenlib/BLI_virtual_vector_array.hh
+++ b/source/blender/blenlib/BLI_virtual_vector_array.hh
@@ -29,7 +29,7 @@
namespace blender {
-/* A readonly virtual array of vectors. */
+/** A read-only virtual array of vectors. */
template<typename T> class VVectorArray {
protected:
int64_t size_;
diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h
index cbf1716602a..568734ee8a7 100644
--- a/source/blender/blenlib/BLI_winstuff.h
+++ b/source/blender/blenlib/BLI_winstuff.h
@@ -88,7 +88,7 @@ typedef SSIZE_T ssize_t;
# endif
#endif
-/* Directory reading compatibility with UNIX. */
+/** Directory reading compatibility with UNIX. */
struct dirent {
int d_ino;
int d_off;
@@ -96,7 +96,7 @@ struct dirent {
char *d_name;
};
-/* intentionally opaque to users */
+/** Intentionally opaque to users. */
typedef struct __dirstream DIR;
DIR *opendir(const char *path);
@@ -105,6 +105,7 @@ int closedir(DIR *dp);
const char *dirname(char *path);
/* Windows utility functions. */
+
bool BLI_windows_register_blend_extension(const bool background);
void BLI_windows_get_default_root_dir(char root_dir[4]);
int BLI_windows_get_executable_dir(char *str);
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 29493c799b3..516d9d2fe84 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -76,6 +76,7 @@ set(SRC
intern/endian_switch.c
intern/expr_pylike_eval.c
intern/fileops.c
+ intern/fileops.cc
intern/filereader_file.c
intern/filereader_gzip.c
intern/filereader_memory.c
@@ -204,6 +205,7 @@ set(SRC
BLI_enumerable_thread_specific.hh
BLI_expr_pylike_eval.h
BLI_fileops.h
+ BLI_fileops.hh
BLI_fileops_types.h
BLI_filereader.h
BLI_float2.hh
@@ -422,6 +424,7 @@ if(WITH_GTESTS)
tests/BLI_edgehash_test.cc
tests/BLI_expr_pylike_eval_test.cc
tests/BLI_function_ref_test.cc
+ tests/BLI_fileops_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/fileops.cc b/source/blender/blenlib/intern/fileops.cc
new file mode 100644
index 00000000000..5ceedbd8cb5
--- /dev/null
+++ b/source/blender/blenlib/intern/fileops.cc
@@ -0,0 +1,51 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup bli
+ */
+
+#include "BLI_fileops.hh"
+
+#ifdef WIN32
+# include "utfconv.h"
+#endif
+
+namespace blender {
+fstream::fstream(const char *filepath, std::ios_base::openmode mode)
+{
+ this->open(filepath, mode);
+}
+
+fstream::fstream(const std::string &filepath, std::ios_base::openmode mode)
+{
+ this->open(filepath, mode);
+}
+
+void fstream::open(StringRefNull filepath, ios_base::openmode mode)
+{
+#ifdef WIN32
+ const char *filepath_cstr = filepath.c_str();
+ UTF16_ENCODE(filepath_cstr);
+ std::wstring filepath_wstr(filepath_cstr_16);
+ std::fstream::open(filepath_wstr.c_str(), mode);
+ UTF16_UN_ENCODE(filepath_cstr);
+#else
+ std::fstream::open(filepath, mode);
+#endif
+}
+
+} // namespace blender
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index a166c846ea7..513b08a589d 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -749,6 +749,26 @@ int BLI_findstringindex(const ListBase *listbase, const char *id, const int offs
return -1;
}
+ListBase BLI_listbase_from_link(Link *some_link)
+{
+ ListBase list = {some_link, some_link};
+ if (some_link == NULL) {
+ return list;
+ }
+
+ /* Find the first element. */
+ while (((Link *)list.first)->prev != NULL) {
+ list.first = ((Link *)list.first)->prev;
+ }
+
+ /* Find the last element. */
+ while (((Link *)list.last)->next != NULL) {
+ list.last = ((Link *)list.last)->next;
+ }
+
+ return list;
+}
+
void BLI_duplicatelist(ListBase *dst, const ListBase *src)
{
struct Link *dst_link, *src_link;
diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c
index 53257cc9285..73ecb2cf798 100644
--- a/source/blender/blenlib/intern/math_color_blend_inline.c
+++ b/source/blender/blenlib/intern/math_color_blend_inline.c
@@ -382,7 +382,7 @@ MINLINE void blend_color_pinlight_byte(uchar dst[4], const uchar src1[4], const
else {
temp = min_ii(2 * src2[i], src1[i]);
}
- dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
+ dst[i] = (uchar)((min_ii(temp, 255) * fac + src1[i] * mfac) / 255);
}
}
else {
@@ -473,7 +473,7 @@ MINLINE void blend_color_exclusion_byte(uchar dst[4], const uchar src1[4], const
int i = 3;
while (i--) {
- const int temp = 127 - ((2 * (src1[i] - 127) * (src2[i] - 127)) / 255);
+ const int temp = 127 - min_ii(((2 * (src1[i] - 127) * (src2[i] - 127)) / 255), 127);
dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
}
}
@@ -896,15 +896,9 @@ MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], cons
int i = 3;
while (i--) {
- float temp;
-
- if (src1[i] < 0.5f) {
- temp = (src2[i] + 0.5f) * src1[i];
- }
- else {
- temp = 1.0f - ((1.0f - (src2[i] + 0.5f)) * (1.0f - src1[i]));
- }
- dst[i] = (temp * fac + src1[i] * mfac);
+ float screen = 1.0f - (1.0f - src1[i]) * (1.0f - src2[i]);
+ float soft_light = ((1.0f - src1[i]) * src2[i] + screen) * src1[i];
+ dst[i] = src1[i] * mfac + soft_light * fac;
}
}
else {
diff --git a/source/blender/blenlib/intern/mesh_intersect.cc b/source/blender/blenlib/intern/mesh_intersect.cc
index ab1db3f1fda..1f150137ba3 100644
--- a/source/blender/blenlib/intern/mesh_intersect.cc
+++ b/source/blender/blenlib/intern/mesh_intersect.cc
@@ -61,11 +61,11 @@
namespace blender::meshintersect {
# ifdef PERFDEBUG
-static void perfdata_init(void);
+static void perfdata_init();
static void incperfcount(int countnum);
static void bumpperfcount(int countnum, int amt);
static void doperfmax(int maxnum, int val);
-static void dump_perfdata(void);
+static void dump_perfdata();
# endif
/** For debugging, can disable threading in intersect code with this static constant. */
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index c824def9104..958480cc616 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -245,12 +245,19 @@ void BLI_path_normalize_dir(const char *relabase, char *dir)
BLI_path_slash_ensure(dir);
}
-bool BLI_filename_make_safe(char *fname)
+bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens)
{
- const char *invalid =
- "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
- "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
- "/\\?*:|\"<>";
+#define INVALID_CHARS \
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
+ "/\\?*:|\""
+#define INVALID_TOKENS "<>"
+
+ const char *invalid = allow_tokens ? INVALID_CHARS : INVALID_CHARS INVALID_TOKENS;
+
+#undef INVALID_CHARS
+#undef INVALID_TOKENS
+
char *fn;
bool changed = false;
@@ -315,6 +322,11 @@ bool BLI_filename_make_safe(char *fname)
return changed;
}
+bool BLI_filename_make_safe(char *fname)
+{
+ return BLI_filename_make_safe_ex(fname, false);
+}
+
bool BLI_path_make_safe(char *path)
{
/* Simply apply BLI_filename_make_safe() over each component of the path.
diff --git a/source/blender/blenlib/intern/serialize.cc b/source/blender/blenlib/intern/serialize.cc
index 52aff140e3e..4e7203efe9b 100644
--- a/source/blender/blenlib/intern/serialize.cc
+++ b/source/blender/blenlib/intern/serialize.cc
@@ -44,12 +44,12 @@ const ArrayValue *Value::as_array_value() const
return static_cast<const ArrayValue *>(this);
}
-const ObjectValue *Value::as_object_value() const
+const DictionaryValue *Value::as_dictionary_value() const
{
- if (type_ != eValueType::Object) {
+ if (type_ != eValueType::Dictionary) {
return nullptr;
}
- return static_cast<const ObjectValue *>(this);
+ return static_cast<const DictionaryValue *>(this);
}
static void convert_to_json(nlohmann::ordered_json &j, const Value &value);
@@ -66,13 +66,13 @@ static void convert_to_json(nlohmann::ordered_json &j, const ArrayValue &value)
}
}
-static void convert_to_json(nlohmann::ordered_json &j, const ObjectValue &value)
+static void convert_to_json(nlohmann::ordered_json &j, const DictionaryValue &value)
{
- const ObjectValue::Items &attributes = value.elements();
+ const DictionaryValue::Items &attributes = value.elements();
/* Create a json object to store the attributes. If this isn't done and attributes is empty it
* would return use a null value, in stead of an empty object. */
j = "{}"_json;
- for (const ObjectValue::Item &attribute : attributes) {
+ for (const DictionaryValue::Item &attribute : attributes) {
nlohmann::ordered_json json_item;
convert_to_json(json_item, *attribute.second);
j[attribute.first] = json_item;
@@ -98,8 +98,8 @@ static void convert_to_json(nlohmann::ordered_json &j, const Value &value)
break;
}
- case eValueType::Object: {
- const ObjectValue &object = *value.as_object_value();
+ case eValueType::Dictionary: {
+ const DictionaryValue &object = *value.as_dictionary_value();
convert_to_json(j, object);
break;
}
@@ -133,10 +133,11 @@ static std::unique_ptr<ArrayValue> convert_from_json_to_array(const nlohmann::or
return array;
}
-static std::unique_ptr<ObjectValue> convert_from_json_to_object(const nlohmann::ordered_json &j)
+static std::unique_ptr<DictionaryValue> convert_from_json_to_object(
+ const nlohmann::ordered_json &j)
{
- std::unique_ptr<ObjectValue> object = std::make_unique<ObjectValue>();
- ObjectValue::Items &elements = object->elements();
+ std::unique_ptr<DictionaryValue> object = std::make_unique<DictionaryValue>();
+ DictionaryValue::Items &elements = object->elements();
for (auto element : j.items()) {
std::string key = element.key();
nlohmann::ordered_json element_json = element.value();
diff --git a/source/blender/blenlib/intern/string_cursor_utf8.c b/source/blender/blenlib/intern/string_cursor_utf8.c
index eb49572f06c..5e2a0b85814 100644
--- a/source/blender/blenlib/intern/string_cursor_utf8.c
+++ b/source/blender/blenlib/intern/string_cursor_utf8.c
@@ -199,7 +199,7 @@ void BLI_str_cursor_step_utf8(const char *str,
const int pos_prev = *pos;
if (BLI_str_cursor_step_prev_utf8(str, maxlen, pos)) {
if ((jump != STRCUR_JUMP_ALL) &&
- (delim_type != cursor_delim_type_utf8(str, maxlen, (size_t)*pos))) {
+ (delim_type != cursor_delim_type_utf8(str, maxlen, *pos))) {
/* left only: compensate for index/change in direction */
if ((pos_orig - (*pos)) >= 1) {
*pos = pos_prev;
diff --git a/source/blender/blenlib/intern/task_graph.cc b/source/blender/blenlib/intern/task_graph.cc
index ff7d0ecb4c4..d84857caeea 100644
--- a/source/blender/blenlib/intern/task_graph.cc
+++ b/source/blender/blenlib/intern/task_graph.cc
@@ -109,7 +109,7 @@ struct TaskNode {
#endif
};
-TaskGraph *BLI_task_graph_create(void)
+TaskGraph *BLI_task_graph_create()
{
return new TaskGraph();
}
diff --git a/source/blender/blenlib/intern/task_scheduler.cc b/source/blender/blenlib/intern/task_scheduler.cc
index 69117e9dc7e..5992e092f4d 100644
--- a/source/blender/blenlib/intern/task_scheduler.cc
+++ b/source/blender/blenlib/intern/task_scheduler.cc
@@ -50,8 +50,8 @@ void BLI_task_scheduler_init()
if (num_threads_override > 0) {
/* Override number of threads. This settings is used within the lifetime
* of tbb::global_control, so we allocate it on the heap. */
- task_scheduler_global_control = OBJECT_GUARDED_NEW(
- tbb::global_control, tbb::global_control::max_allowed_parallelism, num_threads_override);
+ task_scheduler_global_control = MEM_new<tbb::global_control>(
+ __func__, tbb::global_control::max_allowed_parallelism, num_threads_override);
task_scheduler_num_threads = num_threads_override;
}
else {
@@ -69,7 +69,7 @@ void BLI_task_scheduler_init()
void BLI_task_scheduler_exit()
{
#ifdef WITH_TBB_GLOBAL_CONTROL
- OBJECT_GUARDED_DELETE(task_scheduler_global_control, tbb::global_control);
+ MEM_delete(task_scheduler_global_control);
#endif
}
diff --git a/source/blender/blenlib/tests/BLI_fileops_test.cc b/source/blender/blenlib/tests/BLI_fileops_test.cc
new file mode 100644
index 00000000000..e2a792647dc
--- /dev/null
+++ b/source/blender/blenlib/tests/BLI_fileops_test.cc
@@ -0,0 +1,40 @@
+/* Apache License, Version 2.0 */
+
+#include "BLI_fileops.hh"
+
+#include "testing/testing.h"
+
+namespace blender::tests {
+
+TEST(fileops, fstream_open_string_filename)
+{
+ const std::string test_files_dir = blender::tests::flags_test_asset_dir();
+ if (test_files_dir.empty()) {
+ FAIL();
+ }
+
+ const std::string filepath = test_files_dir + "/asset_library/новый/blender_assets.cats.txt";
+ fstream in(filepath, std::ios_base::in);
+ ASSERT_TRUE(in.is_open()) << "could not open " << filepath;
+ in.close(); /* This should not crash. */
+
+ /* Reading the file not tested here. That's deferred to `std::fstream` anyway. */
+}
+
+TEST(fileops, fstream_open_charptr_filename)
+{
+ const std::string test_files_dir = blender::tests::flags_test_asset_dir();
+ if (test_files_dir.empty()) {
+ FAIL();
+ }
+
+ const std::string filepath_str = test_files_dir + "/asset_library/новый/blender_assets.cats.txt";
+ const char *filepath = filepath_str.c_str();
+ fstream in(filepath, std::ios_base::in);
+ ASSERT_TRUE(in.is_open()) << "could not open " << filepath;
+ in.close(); /* This should not crash. */
+
+ /* Reading the file not tested here. That's deferred to `std::fstream` anyway. */
+}
+
+} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_listbase_test.cc b/source/blender/blenlib/tests/BLI_listbase_test.cc
index d66eb214902..9e4d7c7dd36 100644
--- a/source/blender/blenlib/tests/BLI_listbase_test.cc
+++ b/source/blender/blenlib/tests/BLI_listbase_test.cc
@@ -154,6 +154,31 @@ TEST(listbase, FindLinkFromStringOrPointer)
BLI_freelistN(&lb);
}
+TEST(listbase, FromLink)
+{
+ ListBase lb = {nullptr, nullptr};
+ Link *link1 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link1"));
+ Link *link2 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link2"));
+ Link *link3 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link3"));
+
+ /* NULL safety. */
+ EXPECT_EQ(lb, BLI_listbase_from_link(nullptr));
+
+ /* One link. */
+ BLI_addtail(&lb, link1);
+ EXPECT_EQ(lb, BLI_listbase_from_link(link1));
+
+ /* Two links. */
+ BLI_addtail(&lb, link2);
+ EXPECT_EQ(lb, BLI_listbase_from_link(link2));
+
+ /* Three links, search from middle. */
+ BLI_addtail(&lb, link3);
+ EXPECT_EQ(lb, BLI_listbase_from_link(link2));
+
+ BLI_freelistN(&lb);
+}
+
/* -------------------------------------------------------------------- */
/* Sort utilities & test */
diff --git a/source/blender/blenlib/tests/BLI_memory_utils_test.cc b/source/blender/blenlib/tests/BLI_memory_utils_test.cc
index 23415e69b04..207f310d902 100644
--- a/source/blender/blenlib/tests/BLI_memory_utils_test.cc
+++ b/source/blender/blenlib/tests/BLI_memory_utils_test.cc
@@ -169,4 +169,11 @@ static_assert(is_span_convertible_pointer_v<int *, const void *>);
static_assert(!is_span_convertible_pointer_v<TestBaseClass *, TestChildClass *>);
static_assert(!is_span_convertible_pointer_v<TestChildClass *, TestBaseClass *>);
+static_assert(is_same_any_v<int, float, bool, int>);
+static_assert(is_same_any_v<int, int, float>);
+static_assert(is_same_any_v<int, int>);
+static_assert(!is_same_any_v<int, float, bool>);
+static_assert(!is_same_any_v<int, float>);
+static_assert(!is_same_any_v<int>);
+
} // namespace blender::tests
diff --git a/source/blender/blenlib/tests/BLI_serialize_test.cc b/source/blender/blenlib/tests/BLI_serialize_test.cc
index 6c55a85ca1e..120fcdc3e81 100644
--- a/source/blender/blenlib/tests/BLI_serialize_test.cc
+++ b/source/blender/blenlib/tests/BLI_serialize_test.cc
@@ -93,8 +93,8 @@ TEST(serialize, object_to_json)
{
JsonFormatter json;
std::stringstream out;
- ObjectValue value_object;
- ObjectValue::Items &attributes = value_object.elements();
+ DictionaryValue value_object;
+ DictionaryValue::Items &attributes = value_object.elements();
attributes.append_as(std::pair(std::string("best_number"), new IntValue(42)));
json.serialize(out, value_object);
diff --git a/source/blender/blenlib/tests/BLI_task_test.cc b/source/blender/blenlib/tests/BLI_task_test.cc
index dd4441517a9..3bb6f6f753c 100644
--- a/source/blender/blenlib/tests/BLI_task_test.cc
+++ b/source/blender/blenlib/tests/BLI_task_test.cc
@@ -154,7 +154,7 @@ static void task_mempool_iter_tls_func(void *UNUSED(userdata),
EXPECT_TRUE(data != nullptr);
if (task_data->accumulate_items == nullptr) {
- task_data->accumulate_items = (ListBase *)MEM_callocN(sizeof(ListBase), __func__);
+ task_data->accumulate_items = MEM_cnew<ListBase>(__func__);
}
/* Flip to prove this has been touched. */
@@ -172,7 +172,7 @@ static void task_mempool_iter_tls_reduce(const void *__restrict UNUSED(userdata)
if (data_chunk->accumulate_items != nullptr) {
if (join_chunk->accumulate_items == nullptr) {
- join_chunk->accumulate_items = (ListBase *)MEM_callocN(sizeof(ListBase), __func__);
+ join_chunk->accumulate_items = MEM_cnew<ListBase>(__func__);
}
BLI_movelisttolist(join_chunk->accumulate_items, data_chunk->accumulate_items);
}
diff --git a/source/blender/blenlib/tests/BLI_vector_test.cc b/source/blender/blenlib/tests/BLI_vector_test.cc
index e8636168308..e9393a2b1e5 100644
--- a/source/blender/blenlib/tests/BLI_vector_test.cc
+++ b/source/blender/blenlib/tests/BLI_vector_test.cc
@@ -708,6 +708,17 @@ TEST(vector, Prepend)
EXPECT_EQ_ARRAY(vec.data(), Span({7, 8, 1, 2, 3}).data(), 5);
}
+TEST(vector, PrependString)
+{
+ std::string s = "test";
+ Vector<std::string> vec;
+ vec.prepend(s);
+ vec.prepend(std::move(s));
+ EXPECT_EQ(vec.size(), 2);
+ EXPECT_EQ(vec[0], "test");
+ EXPECT_EQ(vec[1], "test");
+}
+
TEST(vector, ReverseIterator)
{
Vector<int> vec = {4, 5, 6, 7};
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 05f74bfa834..245514d4977 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -26,6 +26,7 @@ set(INC
../blentranslation
../depsgraph
../draw
+ ../editors/include
../imbuf
../makesdna
../makesrna
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 54e673b51eb..202a2a95a7c 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -70,6 +70,7 @@
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
+#include "BKE_node_tree_update.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_screen.h"
@@ -579,7 +580,6 @@ static bNodeSocket *do_versions_node_group_add_socket_2_56_2(bNodeTree *ngroup,
gsock->type = type;
gsock->next = gsock->prev = NULL;
- gsock->new_sock = NULL;
gsock->link = NULL;
/* assign new unique index */
gsock->own_index = ngroup->cur_index++;
@@ -590,7 +590,7 @@ static bNodeSocket *do_versions_node_group_add_socket_2_56_2(bNodeTree *ngroup,
BLI_addtail(in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs, gsock);
- ngroup->update |= (in_out == SOCK_IN ? NTREE_UPDATE_GROUP_IN : NTREE_UPDATE_GROUP_OUT);
+ BKE_ntree_update_tag_interface(ngroup);
return gsock;
}
@@ -2019,7 +2019,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
link->fromsock = gsock;
link->tonode = node;
link->tosock = sock;
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_added(ntree, link);
sock->link = link;
}
@@ -2042,7 +2042,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
link->fromsock = sock;
link->tonode = NULL;
link->tosock = gsock;
- ntree->update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_added(ntree, link);
gsock->link = link;
}
@@ -2282,7 +2282,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain)
do_versions_socket_default_value_259(sock);
}
- ntree->update |= NTREE_UPDATE;
+ BKE_ntree_update_tag_all(ntree);
}
FOREACH_NODETREE_END;
}
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 4333bdb851c..d9052c6b1f7 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -88,6 +88,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_paint.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
@@ -896,7 +897,7 @@ static void do_versions_material_convert_legacy_blend_mode(bNodeTree *ntree, cha
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
index bc3cd7a09cb..035aa293b62 100644
--- a/source/blender/blenloader/intern/versioning_300.c
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -30,6 +30,7 @@
#include "BLI_math_vector.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "DNA_anim_types.h"
@@ -57,6 +58,7 @@
#include "BKE_fcurve.h"
#include "BKE_fcurve_driver.h"
#include "BKE_idprop.h"
+#include "BKE_image.h"
#include "BKE_lib_id.h"
#include "BKE_lib_override.h"
#include "BKE_main.h"
@@ -592,7 +594,7 @@ static bNodeTree *add_realize_node_tree(Main *bmain)
nodeSetSelected(node, false);
}
- ntreeUpdateTree(bmain, node_tree);
+ version_socket_update_is_used(node_tree);
return node_tree;
}
@@ -790,6 +792,39 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports))
*/
{
/* Keep this block, even when empty. */
+
+ { /* Ensure driver variable names are unique within the driver. */
+ ID *id;
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt == NULL) {
+ continue;
+ }
+ LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) {
+ ChannelDriver *driver = fcu->driver;
+ /* Ensure the uniqueness front to back. Given a list of identically
+ * named variables, the last one gets to keep its original name. This
+ * matches the evaluation order, and thus shouldn't change the evaluated
+ * value of the driver expression. */
+ LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
+ BLI_uniquename(&driver->variables,
+ dvar,
+ dvar->name,
+ '_',
+ offsetof(DriverVar, name),
+ sizeof(dvar->name));
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
+ }
+
+ /* Ensure tiled image sources contain a UDIM token. */
+ LISTBASE_FOREACH (Image *, ima, &bmain->images) {
+ if (ima->source == IMA_SRC_TILED) {
+ BKE_image_ensure_tile_token(ima->filepath);
+ }
+ }
}
}
@@ -2035,7 +2070,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
SpaceFile *sfile = (SpaceFile *)sl;
if (sfile->params) {
sfile->params->flag &= ~(FILE_PARAMS_FLAG_UNUSED_1 | FILE_PARAMS_FLAG_UNUSED_2 |
- FILE_PARAMS_FLAG_UNUSED_3 | FILE_PARAMS_FLAG_UNUSED_4);
+ FILE_PARAMS_FLAG_UNUSED_3 | FILE_PATH_TOKENS_ALLOW);
}
/* New default import type: Append with reuse. */
@@ -2414,7 +2449,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
data->data_type = SOCK_FLOAT;
data->operation = node->custom1;
strcpy(node->idname, "FunctionNodeCompare");
- node->update = NODE_UPDATE;
node->storage = data;
}
}
@@ -2432,22 +2466,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
}
-
- /* Add node storage for map range node. */
- FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->type == SH_NODE_MAP_RANGE) {
- if (node->storage == NULL) {
- NodeMapRange *data = MEM_callocN(sizeof(NodeMapRange), __func__);
- data->clamp = node->custom1;
- data->data_type = CD_PROP_FLOAT;
- data->interpolation_type = node->custom2;
- node->storage = data;
- }
- }
- }
- }
- FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_ATLEAST(bmain, 301, 5)) {
@@ -2475,5 +2493,38 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
+
+ /* Add node storage for map range node. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == SH_NODE_MAP_RANGE) {
+ if (node->storage == NULL) {
+ NodeMapRange *data = MEM_callocN(sizeof(NodeMapRange), __func__);
+ data->clamp = node->custom1;
+ data->data_type = CD_PROP_FLOAT;
+ data->interpolation_type = node->custom2;
+ node->storage = data;
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+
+ /* Update spreadsheet data set region type. */
+ LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
+ if (sl->spacetype == SPACE_SPREADSHEET) {
+ ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase :
+ &sl->regionbase;
+ LISTBASE_FOREACH (ARegion *, region, regionbase) {
+ if (region->regiontype == RGN_TYPE_CHANNELS) {
+ region->regiontype = RGN_TYPE_TOOLS;
+ }
+ }
+ }
+ }
+ }
+ }
}
-}
+} \ No newline at end of file
diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc
index 3deaaa040d6..752157bffde 100644
--- a/source/blender/blenloader/intern/versioning_common.cc
+++ b/source/blender/blenloader/intern/versioning_common.cc
@@ -223,3 +223,23 @@ void version_node_socket_index_animdata(Main *bmain,
FOREACH_NODETREE_END;
}
}
+
+/**
+ * The versioning code generally expects `SOCK_IN_USE` to be set correctly. This function updates
+ * the flag on all sockets after changes to the node tree.
+ */
+void version_socket_update_is_used(bNodeTree *ntree)
+{
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ socket->flag &= ~SOCK_IN_USE;
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ socket->flag &= ~SOCK_IN_USE;
+ }
+ }
+ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
+ link->fromsock->flag |= SOCK_IN_USE;
+ link->tosock->flag |= SOCK_IN_USE;
+ }
+}
diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h
index 0613484b754..dd1dd1f22f2 100644
--- a/source/blender/blenloader/intern/versioning_common.h
+++ b/source/blender/blenloader/intern/versioning_common.h
@@ -100,6 +100,8 @@ struct bNodeSocket *version_node_add_socket_if_not_exist(struct bNodeTree *ntree
const char *identifier,
const char *name);
+void version_socket_update_is_used(bNodeTree *ntree);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c
index afe2e1067ae..f1a2e678b2e 100644
--- a/source/blender/blenloader/intern/versioning_cycles.c
+++ b/source/blender/blenloader/intern/versioning_cycles.c
@@ -48,6 +48,7 @@
#include "BLO_readfile.h"
#include "readfile.h"
+#include "versioning_common.h"
static bool socket_is_used(bNodeSocket *sock)
{
@@ -170,7 +171,7 @@ static void displacement_node_insert(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -243,7 +244,7 @@ static void square_roughness_node_insert(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -318,7 +319,7 @@ static void ambient_occlusion_node_relink(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -466,7 +467,7 @@ static void update_math_node_single_operand_operators(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -528,7 +529,7 @@ static void update_vector_math_node_add_and_subtract_operators(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -566,7 +567,7 @@ static void update_vector_math_node_dot_product_operator(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -631,7 +632,7 @@ static void update_vector_math_node_cross_product_operator(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -683,7 +684,7 @@ static void update_vector_math_node_normalize_operator(bNodeTree *ntree)
}
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -785,7 +786,7 @@ static void update_vector_math_node_average_operator(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -974,7 +975,7 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1149,7 +1150,7 @@ static void update_voronoi_node_crackle(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1191,7 +1192,7 @@ static void update_voronoi_node_coloring(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1234,7 +1235,7 @@ static void update_voronoi_node_square_distance(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
@@ -1279,7 +1280,7 @@ static void update_noise_and_wave_distortion(bNodeTree *ntree)
}
if (need_update) {
- ntreeUpdateTree(NULL, ntree);
+ version_socket_update_is_used(ntree);
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index a5c44ea711b..234951eac9a 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -61,6 +61,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_paint.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
@@ -583,11 +584,11 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
bNodeSocketValueFloat *roughness_data = roughness_socket->default_value;
roughness_data->value = 0.4f;
node->custom2 = SHD_SUBSURFACE_RANDOM_WALK;
- nodeUpdate(ma->nodetree, node);
+ BKE_ntree_update_tag_node_property(ma->nodetree, node);
}
else if (node->type == SH_NODE_SUBSURFACE_SCATTERING) {
node->custom1 = SHD_SUBSURFACE_RANDOM_WALK;
- nodeUpdate(ma->nodetree, node);
+ BKE_ntree_update_tag_node_property(ma->nodetree, node);
}
}
}
diff --git a/source/blender/blenloader/tests/blendfile_loading_base_test.cc b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
index a4a5ced070d..7a8afbcb227 100644
--- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc
+++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc
@@ -21,14 +21,17 @@
#include "BKE_appdir.h"
#include "BKE_blender.h"
+#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_mball_tessellate.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_scene.h"
+#include "BKE_vfont.h"
#include "BLI_path_util.h"
#include "BLI_threads.h"
@@ -43,6 +46,8 @@
#include "IMB_imbuf.h"
+#include "ED_datafiles.h"
+
#include "RNA_define.h"
#include "WM_api.h"
@@ -71,6 +76,8 @@ void BlendfileLoadingBaseTest::SetUpTestCase()
DEG_register_node_types();
RNA_init();
BKE_node_system_init();
+ BKE_callback_global_init();
+ BKE_vfont_builtin_register(datatoc_bfont_pfb, datatoc_bfont_pfb_size);
G.background = true;
G.factory_startup = true;
@@ -109,6 +116,7 @@ void BlendfileLoadingBaseTest::TearDownTestCase()
void BlendfileLoadingBaseTest::TearDown()
{
+ BKE_mball_cubeTable_free();
depsgraph_free();
blendfile_free();
diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc
index 50a69e55b2b..8525e2fde50 100644
--- a/source/blender/compositor/intern/COM_Debug.cc
+++ b/source/blender/compositor/intern/COM_Debug.cc
@@ -431,8 +431,9 @@ void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name)
if (!COM_EXPORT_GRAPHVIZ) {
return;
}
- char str[1000000];
- if (graphviz_system(system, str, sizeof(str) - 1)) {
+ const int max_textlength = 1000000;
+ char *str = (char *)MEM_mallocN(max_textlength, __func__);
+ if (graphviz_system(system, str, max_textlength - 1)) {
char basename[FILE_MAX];
char filename[FILE_MAX];
@@ -451,6 +452,7 @@ void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name)
fputs(str, fp);
fclose(fp);
}
+ MEM_freeN(str);
}
static std::string get_operations_export_dir()
diff --git a/source/blender/compositor/intern/COM_compositor.cc b/source/blender/compositor/intern/COM_compositor.cc
index be70ae792cb..5c9b34c4772 100644
--- a/source/blender/compositor/intern/COM_compositor.cc
+++ b/source/blender/compositor/intern/COM_compositor.cc
@@ -51,7 +51,7 @@ static void compositor_init_node_previews(const RenderData *render_data, bNodeTr
preview_width = (int)(blender::compositor::COM_PREVIEW_SIZE / aspect);
preview_height = blender::compositor::COM_PREVIEW_SIZE;
}
- BKE_node_preview_init_tree(node_tree, preview_width, preview_height, false);
+ BKE_node_preview_init_tree(node_tree, preview_width, preview_height);
}
static void compositor_reset_node_tree_status(bNodeTree *node_tree)
diff --git a/source/blender/compositor/operations/COM_CropOperation.cc b/source/blender/compositor/operations/COM_CropOperation.cc
index 5d78ed9d41a..2385a0b54ba 100644
--- a/source/blender/compositor/operations/COM_CropOperation.cc
+++ b/source/blender/compositor/operations/COM_CropOperation.cc
@@ -42,22 +42,22 @@ void CropBaseOperation::update_area()
local_settings.y1 = height * local_settings.fac_y1;
local_settings.y2 = height * local_settings.fac_y2;
}
- if (width <= local_settings.x1 + 1) {
- local_settings.x1 = width - 1;
+ if (width < local_settings.x1) {
+ local_settings.x1 = width;
}
- if (height <= local_settings.y1 + 1) {
- local_settings.y1 = height - 1;
+ if (height < local_settings.y1) {
+ local_settings.y1 = height;
}
- if (width <= local_settings.x2 + 1) {
- local_settings.x2 = width - 1;
+ if (width < local_settings.x2) {
+ local_settings.x2 = width;
}
- if (height <= local_settings.y2 + 1) {
- local_settings.y2 = height - 1;
+ if (height < local_settings.y2) {
+ local_settings.y2 = height;
}
- xmax_ = MAX2(local_settings.x1, local_settings.x2) + 1;
+ xmax_ = MAX2(local_settings.x1, local_settings.x2);
xmin_ = MIN2(local_settings.x1, local_settings.x2);
- ymax_ = MAX2(local_settings.y1, local_settings.y2) + 1;
+ ymax_ = MAX2(local_settings.y1, local_settings.y2);
ymin_ = MIN2(local_settings.y1, local_settings.y2);
}
else {
@@ -98,10 +98,8 @@ void CropOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- rcti crop_area;
- BLI_rcti_init(&crop_area, xmin_, xmax_, ymin_, ymax_);
for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) {
- if (BLI_rcti_isect_pt(&crop_area, it.x, it.y)) {
+ if ((it.x < xmax_ && it.x >= xmin_) && (it.y < ymax_ && it.y >= ymin_)) {
copy_v4_v4(it.out, it.in(0));
}
else {
@@ -166,11 +164,11 @@ void CropImageOperation::update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs)
{
- rcti op_area;
- BLI_rcti_init(&op_area, 0, get_width(), 0, get_height());
const MemoryBuffer *input = inputs[0];
+ const int width = get_width();
+ const int height = get_height();
for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
- if (BLI_rcti_isect_pt(&op_area, it.x, it.y)) {
+ if (it.x >= 0 && it.x < width && it.y >= 0 && it.y < height) {
input->read_elem_checked(it.x + xmin_, it.y + ymin_, it.out);
}
else {
diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc
index c34eaad87ef..aa92c5c0c2b 100644
--- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc
+++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc
@@ -132,8 +132,7 @@ KeyingScreenOperation::TriangulationData *KeyingScreenOperation::build_voronoi_t
return nullptr;
}
- triangulation = (TriangulationData *)MEM_callocN(sizeof(TriangulationData),
- "keying screen triangulation data");
+ triangulation = MEM_cnew<TriangulationData>("keying screen triangulation data");
sites = (VoronoiSite *)MEM_callocN(sizeof(VoronoiSite) * sites_total,
"keyingscreen voronoi sites");
@@ -243,7 +242,7 @@ KeyingScreenOperation::TileData *KeyingScreenOperation::triangulate(const rcti *
return nullptr;
}
- tile_data = (TileData *)MEM_callocN(sizeof(TileData), "keying screen tile data");
+ tile_data = MEM_cnew<TileData>("keying screen tile data");
for (i = 0; i < triangulation->triangles_total; i++) {
if (BLI_rcti_isect(rect, &triangulation->triangles_AABB[i], nullptr)) {
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index 94cba833096..8a69dbf3312 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -153,9 +153,9 @@ void DEG_add_collection_geometry_customdata_mask(struct DepsNodeHandle *node_han
void DEG_add_simulation_relation(struct DepsNodeHandle *node_handle,
struct Simulation *simulation,
const char *description);
-void DEG_add_node_tree_relation(struct DepsNodeHandle *node_handle,
- struct bNodeTree *node_tree,
- const char *description);
+void DEG_add_node_tree_output_relation(struct DepsNodeHandle *node_handle,
+ struct bNodeTree *node_tree,
+ const char *description);
void DEG_add_bone_relation(struct DepsNodeHandle *handle,
struct Object *object,
const char *bone_name,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index 51582508b6f..ecbe89b1e7f 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -199,9 +199,7 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id)
nullptr, OperationCode::OPERATION, "", -1);
/* Pin the node so that it and its relations are preserved by the unused nodes/relations
* deletion. This is mainly to make it easier to debug visibility. */
- /* NOTE: Keep un-pinned for the 3.0 release. This way we are more sure that side effects of the
- * change is minimal outside of the dependency graph area. */
- // visibility_operation->flag |= OperationFlag::DEPSOP_FLAG_PINNED;
+ visibility_operation->flag |= OperationFlag::DEPSOP_FLAG_PINNED;
graph_->operations.append(visibility_operation);
}
return id_node;
@@ -589,11 +587,7 @@ void DepsgraphNodeBuilder::build_id(ID *id)
case ID_HA:
case ID_PT:
case ID_VO:
- /* TODO(sergey): Get visibility from a "parent" somehow.
- *
- * NOTE: Similarly to above, we don't want false-positives on
- * visibility. */
- build_object_data_geometry_datablock(id, false);
+ build_object_data_geometry_datablock(id);
break;
case ID_SPK:
build_speaker((Speaker *)id);
@@ -769,32 +763,28 @@ void DepsgraphNodeBuilder::build_object(int base_index,
if (object->modifiers.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_visible;
BKE_modifiers_foreach_ID_link(object, modifier_walk, &data);
}
/* Grease Pencil Modifiers. */
if (object->greasepencil_modifiers.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_visible;
BKE_gpencil_modifiers_foreach_ID_link(object, modifier_walk, &data);
}
/* Shader FX. */
if (object->shader_fx.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_visible;
BKE_shaderfx_foreach_ID_link(object, modifier_walk, &data);
}
/* Constraints. */
if (object->constraints.first != nullptr) {
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_visible;
BKE_constraints_id_loop(&object->constraints, constraint_walk, &data);
}
/* Object data. */
- build_object_data(object, is_visible);
+ build_object_data(object);
/* Parameters, used by both drivers/animation and also to inform dependency
* from object's data. */
build_parameters(&object->id);
@@ -897,7 +887,7 @@ void DepsgraphNodeBuilder::build_object_instance_collection(Object *object, bool
is_parent_collection_visible_ = is_current_parent_collection_visible;
}
-void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visible)
+void DepsgraphNodeBuilder::build_object_data(Object *object)
{
if (object->data == nullptr) {
return;
@@ -914,14 +904,14 @@ void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visi
case OB_HAIR:
case OB_POINTCLOUD:
case OB_VOLUME:
- build_object_data_geometry(object, is_object_visible);
+ build_object_data_geometry(object);
break;
case OB_ARMATURE:
if (ID_IS_LINKED(object) && object->proxy_from != nullptr) {
- build_proxy_rig(object, is_object_visible);
+ build_proxy_rig(object);
}
else {
- build_rig(object, is_object_visible);
+ build_rig(object);
}
break;
case OB_LAMP:
@@ -1121,7 +1111,14 @@ void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips)
void DepsgraphNodeBuilder::build_animation_images(ID *id)
{
- if (BKE_image_user_id_has_animation(id)) {
+ /* GPU materials might use an animated image. However, these materials have no been built yet. We
+ * could scan the entire node tree recursively to check if any texture node has a video. That is
+ * quite expensive. For now just always add this operation node, because it is very fast. */
+ /* TODO: Add a more precise check when it is cheaper to iterate over all image nodes in a node
+ * tree. */
+ const bool can_have_gpu_material = ELEM(GS(id->name), ID_MA, ID_WO);
+
+ if (BKE_image_user_id_has_animation(id) || can_have_gpu_material) {
ID *id_cow = get_cow_id(id);
add_operation_node(
id,
@@ -1465,7 +1462,7 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key)
/* ObData Geometry Evaluation */
/* XXX: what happens if the datablock is shared! */
-void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_object_visible)
+void DepsgraphNodeBuilder::build_object_data_geometry(Object *object)
{
OperationNode *op_node;
Scene *scene_cow = get_cow_datablock(scene_);
@@ -1487,7 +1484,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_ob
/* Point caches. */
build_object_pointcache(object);
/* Geometry. */
- build_object_data_geometry_datablock((ID *)object->data, is_object_visible);
+ build_object_data_geometry_datablock((ID *)object->data);
build_dimensions(object);
/* Batch cache. */
add_operation_node(
@@ -1497,7 +1494,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_ob
[object_cow](::Depsgraph *depsgraph) { BKE_object_select_update(depsgraph, object_cow); });
}
-void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool is_object_visible)
+void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata)
{
if (built_map_.checkIsBuiltAndTag(obdata)) {
return;
@@ -1541,17 +1538,15 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool
BKE_curve_eval_geometry(depsgraph, (Curve *)obdata_cow);
});
op_node->set_as_entry();
- /* Make sure objects used for bevel.taper are in the graph.
- * NOTE: This objects might be not linked to the scene. */
Curve *cu = (Curve *)obdata;
if (cu->bevobj != nullptr) {
- build_object(-1, cu->bevobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ build_object(-1, cu->bevobj, DEG_ID_LINKED_INDIRECTLY, false);
}
if (cu->taperobj != nullptr) {
- build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY, false);
}
if (cu->textoncurve != nullptr) {
- build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY, false);
}
break;
}
@@ -1710,8 +1705,8 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree)
build_idproperties(ntree->id.properties);
/* Animation, */
build_animdata(&ntree->id);
- /* Shading update. */
- add_operation_node(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
+ /* Output update. */
+ add_operation_node(&ntree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
build_idproperties(bnode->prop);
@@ -2114,10 +2109,7 @@ void DepsgraphNodeBuilder::modifier_walk(void *user_data,
}
switch (GS(id->name)) {
case ID_OB:
- /* Special case for object, so we take owner visibility into
- * account. */
- data->builder->build_object(
- -1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, data->is_parent_visible);
+ data->builder->build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, false);
break;
default:
data->builder->build_id(id);
@@ -2137,10 +2129,7 @@ void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/,
}
switch (GS(id->name)) {
case ID_OB:
- /* Special case for object, so we take owner visibility into
- * account. */
- data->builder->build_object(
- -1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, data->is_parent_visible);
+ data->builder->build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, false);
break;
default:
data->builder->build_id(id);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
index 2d24dc49802..83bc33b6a4e 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h
@@ -186,20 +186,17 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_object_flags(int base_index,
Object *object,
eDepsNode_LinkedState_Type linked_state);
- virtual void build_object_data(Object *object, bool is_object_visible);
+ virtual void build_object_data(Object *object);
virtual void build_object_data_camera(Object *object);
- virtual void build_object_data_geometry(Object *object, bool is_object_visible);
- virtual void build_object_data_geometry_datablock(ID *obdata, bool is_object_visible);
+ virtual void build_object_data_geometry(Object *object);
+ virtual void build_object_data_geometry_datablock(ID *obdata);
virtual void build_object_data_light(Object *object);
virtual void build_object_data_lightprobe(Object *object);
virtual void build_object_data_speaker(Object *object);
virtual void build_object_transform(Object *object);
virtual void build_object_constraints(Object *object);
virtual void build_object_pointcache(Object *object);
- virtual void build_pose_constraints(Object *object,
- bPoseChannel *pchan,
- int pchan_index,
- bool is_object_visible);
+ virtual void build_pose_constraints(Object *object, bPoseChannel *pchan, int pchan_index);
virtual void build_rigidbody(Scene *scene);
virtual void build_particle_systems(Object *object, bool is_object_visible);
virtual void build_particle_settings(ParticleSettings *part);
@@ -227,8 +224,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
virtual void build_dimensions(Object *object);
virtual void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
virtual void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con);
- virtual void build_rig(Object *object, bool is_object_visible);
- virtual void build_proxy_rig(Object *object, bool is_object_visible);
+ virtual void build_rig(Object *object);
+ virtual void build_proxy_rig(Object *object);
virtual void build_armature(bArmature *armature);
virtual void build_armature_bones(ListBase *bones);
virtual void build_shapekeys(Key *key);
@@ -284,8 +281,6 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
struct BuilderWalkUserData {
DepsgraphNodeBuilder *builder;
- /* Denotes whether object the walk is invoked from is visible. */
- bool is_parent_visible;
};
static void modifier_walk(void *user_data,
struct Object *object,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
index 00c78b8edce..e8dda7b8de4 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -58,13 +58,11 @@ namespace blender::deg {
void DepsgraphNodeBuilder::build_pose_constraints(Object *object,
bPoseChannel *pchan,
- int pchan_index,
- bool is_object_visible)
+ int pchan_index)
{
/* Pull indirect dependencies via constraints. */
BuilderWalkUserData data;
data.builder = this;
- data.is_parent_visible = is_object_visible;
BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data);
/* Create node for constraint stack. */
@@ -147,7 +145,7 @@ void DepsgraphNodeBuilder::build_splineik_pose(Object *object,
}
/* Pose/Armature Bones Graph */
-void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
+void DepsgraphNodeBuilder::build_rig(Object *object)
{
bArmature *armature = (bArmature *)object->data;
Scene *scene_cow = get_cow_datablock(scene_);
@@ -272,7 +270,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
}
/* Build constraints. */
if (pchan->constraints.first != nullptr) {
- build_pose_constraints(object, pchan, pchan_index, is_object_visible);
+ build_pose_constraints(object, pchan, pchan_index);
}
/**
* IK Solvers.
@@ -301,14 +299,14 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible)
}
/* Custom shape. */
if (pchan->custom != nullptr) {
- /* TODO(sergey): Use own visibility. */
- build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ /* NOTE: The relation builder will ensure visibility of the custom shape object. */
+ build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, false);
}
pchan_index++;
}
}
-void DepsgraphNodeBuilder::build_proxy_rig(Object *object, bool is_object_visible)
+void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
{
bArmature *armature = (bArmature *)object->data;
OperationNode *op_node;
@@ -356,7 +354,8 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object, bool is_object_visibl
/* Custom shape. */
if (pchan->custom != nullptr) {
- build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, is_object_visible);
+ /* NOTE: The relation builder will ensure visibility of the custom shape object. */
+ build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, false);
}
pchan_index++;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index b195b2d9e11..558ea3dd6e0 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -1466,8 +1466,11 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id)
void DepsgraphRelationBuilder::build_animation_images(ID *id)
{
+ /* See #DepsgraphNodeBuilder::build_animation_images. */
+ const bool can_have_gpu_material = ELEM(GS(id->name), ID_MA, ID_WO);
+
/* TODO: can we check for existence of node for performance? */
- if (BKE_image_user_id_has_animation(id)) {
+ if (BKE_image_user_id_has_animation(id) || can_have_gpu_material) {
OperationKey image_animation_key(
id, NodeType::IMAGE_ANIMATION, OperationCode::IMAGE_ANIMATION);
TimeSourceKey time_src_key;
@@ -1770,7 +1773,7 @@ void DepsgraphRelationBuilder::build_world(World *world)
if (world->nodetree != nullptr) {
build_nodetree(world->nodetree);
OperationKey ntree_key(
- &world->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
+ &world->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
add_relation(ntree_key, world_key, "World's NTree");
build_nested_nodetree(&world->id, world->nodetree);
}
@@ -2381,17 +2384,17 @@ void DepsgraphRelationBuilder::build_light(Light *lamp)
ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS);
+ /* For allowing drivers on lamp properties. */
+ ComponentKey shading_key(&lamp->id, NodeType::SHADING);
+ add_relation(lamp_parameters_key, shading_key, "Light Shading Parameters");
+
/* light's nodetree */
if (lamp->nodetree != nullptr) {
build_nodetree(lamp->nodetree);
- ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::SHADING);
- add_relation(nodetree_key, lamp_parameters_key, "NTree->Light Parameters");
+ ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::NTREE_OUTPUT);
+ add_relation(nodetree_key, shading_key, "NTree->Light Parameters");
build_nested_nodetree(&lamp->id, lamp->nodetree);
}
-
- /* For allowing drivers on lamp properties. */
- ComponentKey shading_key(&lamp->id, NodeType::SHADING);
- add_relation(lamp_parameters_key, shading_key, "Light Shading Parameters");
}
void DepsgraphRelationBuilder::build_nodetree_socket(bNodeSocket *socket)
@@ -2441,7 +2444,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
build_idproperties(ntree->id.properties);
build_animdata(&ntree->id);
build_parameters(&ntree->id);
- ComponentKey shading_key(&ntree->id, NodeType::SHADING);
+ OperationKey ntree_output_key(&ntree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
/* nodetree's nodes... */
LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) {
build_idproperties(bnode->prop);
@@ -2460,25 +2463,25 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
if (id_type == ID_MA) {
build_material((Material *)bnode->id);
ComponentKey material_key(id, NodeType::SHADING);
- add_relation(material_key, shading_key, "Material -> Node");
+ add_relation(material_key, ntree_output_key, "Material -> Node");
}
else if (id_type == ID_TE) {
build_texture((Tex *)bnode->id);
ComponentKey texture_key(id, NodeType::GENERIC_DATABLOCK);
- add_relation(texture_key, shading_key, "Texture -> Node");
+ add_relation(texture_key, ntree_output_key, "Texture -> Node");
}
else if (id_type == ID_IM) {
build_image((Image *)bnode->id);
ComponentKey image_key(id, NodeType::GENERIC_DATABLOCK);
- add_relation(image_key, shading_key, "Image -> Node");
+ add_relation(image_key, ntree_output_key, "Image -> Node");
}
else if (id_type == ID_OB) {
build_object((Object *)id);
ComponentKey object_transform_key(id, NodeType::TRANSFORM);
- add_relation(object_transform_key, shading_key, "Object Transform -> Node");
+ add_relation(object_transform_key, ntree_output_key, "Object Transform -> Node");
if (object_have_geometry_component(reinterpret_cast<Object *>(id))) {
ComponentKey object_geometry_key(id, NodeType::GEOMETRY);
- add_relation(object_geometry_key, shading_key, "Object Geometry -> Node");
+ add_relation(object_geometry_key, ntree_output_key, "Object Geometry -> Node");
}
}
else if (id_type == ID_SCE) {
@@ -2498,23 +2501,28 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
else if (id_type == ID_MSK) {
build_mask((Mask *)id);
OperationKey mask_key(id, NodeType::PARAMETERS, OperationCode::MASK_EVAL);
- add_relation(mask_key, shading_key, "Mask -> Node");
+ add_relation(mask_key, ntree_output_key, "Mask -> Node");
}
else if (id_type == ID_MC) {
build_movieclip((MovieClip *)id);
OperationKey clip_key(id, NodeType::PARAMETERS, OperationCode::MOVIECLIP_EVAL);
- add_relation(clip_key, shading_key, "Clip -> Node");
+ add_relation(clip_key, ntree_output_key, "Clip -> Node");
}
else if (id_type == ID_VF) {
build_vfont((VFont *)id);
ComponentKey vfont_key(id, NodeType::GENERIC_DATABLOCK);
- add_relation(vfont_key, shading_key, "VFont -> Node");
+ add_relation(vfont_key, ntree_output_key, "VFont -> Node");
}
else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
bNodeTree *group_ntree = (bNodeTree *)id;
build_nodetree(group_ntree);
- ComponentKey group_shading_key(&group_ntree->id, NodeType::SHADING);
- add_relation(group_shading_key, shading_key, "Group Node");
+ ComponentKey group_output_key(&group_ntree->id, NodeType::NTREE_OUTPUT);
+ /* The output of the current tree does not necessarily change when the output of the group
+ * changed. The parent node group is currently explicitly tagged for update in
+ * #ED_node_tree_propagate_change. In the future we could move this relation to the
+ * depsgraph, but then the depsgraph has to do some more static analysis of the node tree to
+ * see which groups the output actually depends on. */
+ add_relation(group_output_key, ntree_output_key, "Group Node", RELATION_FLAG_NO_FLUSH);
}
else {
BLI_assert_msg(0, "Unknown ID type used for node");
@@ -2528,14 +2536,10 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
build_idproperties(socket->prop);
}
- OperationKey shading_update_key(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
-
if (check_id_has_anim_component(&ntree->id)) {
ComponentKey animation_key(&ntree->id, NodeType::ANIMATION);
- add_relation(animation_key, shading_update_key, "NTree Shading Parameters");
+ add_relation(animation_key, ntree_output_key, "NTree Shading Parameters");
}
- ComponentKey parameters_key(&ntree->id, NodeType::PARAMETERS);
- add_relation(parameters_key, shading_update_key, "NTree Shading Parameters");
}
/* Recursively build graph for material */
@@ -2558,7 +2562,7 @@ void DepsgraphRelationBuilder::build_material(Material *material)
if (material->nodetree != nullptr) {
build_nodetree(material->nodetree);
OperationKey ntree_key(
- &material->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE);
+ &material->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
add_relation(ntree_key, material_key, "Material's NTree");
build_nested_nodetree(&material->id, material->nodetree);
}
@@ -2587,8 +2591,13 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture)
build_parameters(&texture->id);
/* texture's nodetree */
- build_nodetree(texture->nodetree);
- build_nested_nodetree(&texture->id, texture->nodetree);
+ if (texture->nodetree) {
+ build_nodetree(texture->nodetree);
+ OperationKey ntree_key(
+ &texture->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT);
+ add_relation(ntree_key, texture_key, "Texture's NTree");
+ build_nested_nodetree(&texture->id, texture->nodetree);
+ }
/* Special cases for different IDs which texture uses. */
if (texture->type == TEX_IMAGE) {
@@ -2875,12 +2884,16 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations()
*
* This is similar to what happens in ntree_hack_remap_pointers().
*/
-void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id)
+void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id, bool flush_cow_changes)
{
+ int relation_flag = 0;
+ if (!flush_cow_changes) {
+ relation_flag |= RELATION_FLAG_NO_FLUSH;
+ }
OperationKey owner_copy_on_write_key(
owner, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE);
OperationKey id_copy_on_write_key(id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE);
- add_relation(id_copy_on_write_key, owner_copy_on_write_key, "Eval Order");
+ add_relation(id_copy_on_write_key, owner_copy_on_write_key, "Eval Order", relation_flag);
}
void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree)
@@ -2888,7 +2901,10 @@ void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree
if (ntree == nullptr) {
return;
}
- build_nested_datablock(owner, &ntree->id);
+ /* Don't flush cow changes, because the node tree may change in ways that do not affect the
+ * owner data block (e.g. when a node is deleted that is not connected to any output).
+ * Data blocks owning node trees should add a relation to the `NTREE_OUTPUT` node instead. */
+ build_nested_datablock(owner, &ntree->id, false);
}
void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key)
@@ -2896,7 +2912,7 @@ void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key)
if (key == nullptr) {
return;
}
- build_nested_datablock(owner, &key->id);
+ build_nested_datablock(owner, &key->id, true);
}
void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 09003de3ce4..787e3799029 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -299,7 +299,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer);
virtual void build_vfont(VFont *vfont);
- virtual void build_nested_datablock(ID *owner, ID *id);
+ virtual void build_nested_datablock(ID *owner, ID *id, bool flush_cow_changes);
virtual void build_nested_nodetree(ID *owner, bNodeTree *ntree);
virtual void build_nested_shapekey(ID *owner, Key *key);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index 40e59875832..43d24125dc2 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -351,7 +351,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
return node_identifier;
}
else if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
- node_identifier.type = NodeType::SHADING;
+ node_identifier.type = NodeType::NTREE_OUTPUT;
return node_identifier;
}
else if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) {
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
index 7be661d9668..36120ae76d1 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
@@ -425,6 +425,7 @@ static void deg_debug_graphviz_node(DotExportContext &ctx,
case NodeType::ARMATURE:
case NodeType::GENERIC_DATABLOCK:
case NodeType::VISIBILITY:
+ case NodeType::NTREE_OUTPUT:
case NodeType::SIMULATION: {
ComponentNode *comp_node = (ComponentNode *)node;
if (comp_node->operations.is_empty()) {
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index db00c595383..acb8fa8fe88 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -148,15 +148,15 @@ void DEG_add_simulation_relation(DepsNodeHandle *node_handle,
deg_node_handle->builder->add_node_handle_relation(operation_key, deg_node_handle, description);
}
-void DEG_add_node_tree_relation(DepsNodeHandle *node_handle,
- bNodeTree *node_tree,
- const char *description)
+void DEG_add_node_tree_output_relation(DepsNodeHandle *node_handle,
+ bNodeTree *node_tree,
+ const char *description)
{
- /* Using shading key, because that's the one that exists right now. Should use something else in
- * the future. */
- deg::ComponentKey shading_key(&node_tree->id, deg::NodeType::SHADING);
+ deg::OperationKey ntree_output_key(
+ &node_tree->id, deg::NodeType::NTREE_OUTPUT, deg::OperationCode::NTREE_OUTPUT);
deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
- deg_node_handle->builder->add_node_handle_relation(shading_key, deg_node_handle, description);
+ deg_node_handle->builder->add_node_handle_relation(
+ ntree_output_key, deg_node_handle, description);
}
void DEG_add_object_cache_relation(DepsNodeHandle *node_handle,
diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
index 7af3d03d478..c84adbcde00 100644
--- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc
+++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc
@@ -334,10 +334,13 @@ static void DEG_iterator_ids_step(BLI_Iterator *iter, deg::IDNode *id_node, bool
return;
}
if (only_updated && !(id_cow->recalc & ID_RECALC_ALL)) {
- bNodeTree *ntree = ntreeFromID(id_cow);
-
/* Node-tree is considered part of the data-block. */
- if (!(ntree && (ntree->id.recalc & ID_RECALC_ALL))) {
+ bNodeTree *ntree = ntreeFromID(id_cow);
+ if (ntree == nullptr) {
+ iter->skip = true;
+ return;
+ }
+ if ((ntree->id.recalc & ID_RECALC_NTREE_OUTPUT) == 0) {
iter->skip = true;
return;
}
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
index 2b0d0e6e780..4bc9e0d2d14 100644
--- a/source/blender/depsgraph/intern/depsgraph_tag.cc
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -232,6 +232,10 @@ void depsgraph_tag_to_component_opcode(const ID *id,
break;
case ID_RECALC_TAG_FOR_UNDO:
break; /* Must be ignored by depsgraph. */
+ case ID_RECALC_NTREE_OUTPUT:
+ *component_type = NodeType::NTREE_OUTPUT;
+ *operation_code = OperationCode::NTREE_OUTPUT;
+ break;
}
}
@@ -749,6 +753,8 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
return "ALL";
case ID_RECALC_TAG_FOR_UNDO:
return "TAG_FOR_UNDO";
+ case ID_RECALC_NTREE_OUTPUT:
+ return "ID_RECALC_NTREE_OUTPUT";
}
return nullptr;
}
diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc
index 8bc03d8b736..075bfd35ec1 100644
--- a/source/blender/depsgraph/intern/node/deg_node.cc
+++ b/source/blender/depsgraph/intern/node/deg_node.cc
@@ -116,6 +116,8 @@ const char *nodeTypeAsString(NodeType type)
return "VISIBILITY";
case NodeType::SIMULATION:
return "SIMULATION";
+ case NodeType::NTREE_OUTPUT:
+ return "NTREE_OUTPUT";
/* Total number of meaningful node types. */
case NodeType::NUM_TYPES:
@@ -174,6 +176,7 @@ eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type)
case NodeType::CACHE:
case NodeType::PROXY:
case NodeType::SIMULATION:
+ case NodeType::NTREE_OUTPUT:
return DEG_SCENE_COMP_PARAMETERS;
case NodeType::VISIBILITY:
@@ -251,6 +254,7 @@ eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type)
case NodeType::DUPLI:
case NodeType::SYNCHRONIZATION:
case NodeType::SIMULATION:
+ case NodeType::NTREE_OUTPUT:
case NodeType::UNDEFINED:
case NodeType::NUM_TYPES:
return DEG_OB_COMP_PARAMETERS;
diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h
index 7e093ab8765..6cb5e31303f 100644
--- a/source/blender/depsgraph/intern/node/deg_node.h
+++ b/source/blender/depsgraph/intern/node/deg_node.h
@@ -112,11 +112,11 @@ enum class NodeType {
* which simplifies common algorithms which are dealing with relations and visibility.
*
* The fact that the visibility operates on the ID level basically means that all components in
- * NodeA will be considered as affecting directly visible when NodeB's visibility is
+ * the NodeA will be considered as affecting directly visible when NodeB's visibility is
* affecting directly visible ID.
*
* This is the way to ensure objects needed for visualization without any actual data dependency
- * are properly evaluated. Example of this is custom shapes for bones. */
+ * properly evaluated. Example of this is custom shapes for bones. */
VISIBILITY,
/* **** Evaluation-Related Outer Types (with Subdata) **** */
@@ -147,6 +147,8 @@ enum class NodeType {
SYNCHRONIZATION,
/* Simulation component. */
SIMULATION,
+ /* Node tree output component. */
+ NTREE_OUTPUT,
/* Total number of meaningful node types. */
NUM_TYPES,
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc
index b716877902c..4c430904e44 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_component.cc
@@ -351,6 +351,7 @@ DEG_COMPONENT_NODE_DEFINE(Armature, ARMATURE, 0);
DEG_COMPONENT_NODE_DEFINE(GenericDatablock, GENERIC_DATABLOCK, 0);
DEG_COMPONENT_NODE_DEFINE(Visibility, VISIBILITY, 0);
DEG_COMPONENT_NODE_DEFINE(Simulation, SIMULATION, 0);
+DEG_COMPONENT_NODE_DEFINE(NTreeOutput, NTREE_OUTPUT, ID_RECALC_NTREE_OUTPUT);
/** \} */
@@ -385,6 +386,7 @@ void deg_register_component_depsnodes()
register_node_typeinfo(&DNTI_GENERIC_DATABLOCK);
register_node_typeinfo(&DNTI_VISIBILITY);
register_node_typeinfo(&DNTI_SIMULATION);
+ register_node_typeinfo(&DNTI_NTREE_OUTPUT);
}
/** \} */
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h
index 9f108af8012..8fd28dfc497 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.h
+++ b/source/blender/depsgraph/intern/node/deg_node_component.h
@@ -222,6 +222,7 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(Armature);
DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock);
DEG_COMPONENT_NODE_DECLARE_NO_COW(Visibility);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Simulation);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(NTreeOutput);
/* Bone Component */
struct BoneComponentNode : public ComponentNode {
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc
index eaae5d2d5dc..2d0d6854851 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc
@@ -182,6 +182,9 @@ const char *operationCodeAsString(OperationCode opcode)
return "LIGHT_UPDATE";
case OperationCode::WORLD_UPDATE:
return "WORLD_UPDATE";
+ /* Node Tree. */
+ case OperationCode::NTREE_OUTPUT:
+ return "NTREE_OUTPUT";
/* Movie clip. */
case OperationCode::MOVIECLIP_EVAL:
return "MOVIECLIP_EVAL";
diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h
index 31cbb9702ba..4abdc014946 100644
--- a/source/blender/depsgraph/intern/node/deg_node_operation.h
+++ b/source/blender/depsgraph/intern/node/deg_node_operation.h
@@ -177,6 +177,9 @@ enum class OperationCode {
LIGHT_UPDATE,
WORLD_UPDATE,
+ /* Node Tree. ----------------------------------------------------------- */
+ NTREE_OUTPUT,
+
/* Batch caches. -------------------------------------------------------- */
GEOMETRY_SELECT_UPDATE,
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index 30a3b8087c0..eea3adc440a 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -44,9 +44,11 @@ set(INC
../../../intern/atomic
../../../intern/glew-mx
../../../intern/guardedalloc
+ ../../../intern/opensubdiv
# dna_type_offsets.h
${CMAKE_CURRENT_BINARY_DIR}/../makesdna/intern
+ ${OPENSUBDIV_INCLUDE_DIRS}
)
set(SRC
@@ -85,12 +87,13 @@ set(SRC
intern/draw_cache_impl_curve.cc
intern/draw_cache_impl_displist.c
intern/draw_cache_impl_gpencil.c
- intern/draw_cache_impl_hair.c
+ intern/draw_cache_impl_hair.cc
intern/draw_cache_impl_lattice.c
intern/draw_cache_impl_mesh.c
intern/draw_cache_impl_metaball.c
intern/draw_cache_impl_particles.c
intern/draw_cache_impl_pointcloud.c
+ intern/draw_cache_impl_subdivision.cc
intern/draw_cache_impl_volume.c
intern/draw_color_management.cc
intern/draw_common.c
@@ -209,6 +212,7 @@ set(SRC
intern/draw_manager_testing.h
intern/draw_manager_text.h
intern/draw_shader.h
+ intern/draw_subdivision.h
intern/draw_texture_pool.h
intern/draw_view.h
intern/draw_view_data.h
@@ -372,6 +376,18 @@ data_to_c_simple(intern/shaders/common_view_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_fxaa_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_smaa_lib.glsl SRC)
data_to_c_simple(intern/shaders/common_fullscreen_vert.glsl SRC)
+data_to_c_simple(intern/shaders/common_subdiv_custom_data_interp_comp.glsl SRC)
+data_to_c_simple(intern/shaders/common_subdiv_ibo_lines_comp.glsl SRC)
+data_to_c_simple(intern/shaders/common_subdiv_ibo_tris_comp.glsl SRC)
+data_to_c_simple(intern/shaders/common_subdiv_lib.glsl SRC)
+data_to_c_simple(intern/shaders/common_subdiv_normals_accumulate_comp.glsl SRC)
+data_to_c_simple(intern/shaders/common_subdiv_normals_finalize_comp.glsl SRC)
+data_to_c_simple(intern/shaders/common_subdiv_patch_evaluation_comp.glsl SRC)
+data_to_c_simple(intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl SRC)
+data_to_c_simple(intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl SRC)
+data_to_c_simple(intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl SRC)
+data_to_c_simple(intern/shaders/common_subdiv_vbo_lnor_comp.glsl SRC)
+data_to_c_simple(intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_frag.glsl SRC)
data_to_c_simple(engines/gpencil/shaders/gpencil_vert.glsl SRC)
diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h
index 98e166ac3a7..132f66ecb1e 100644
--- a/source/blender/draw/DRW_engine.h
+++ b/source/blender/draw/DRW_engine.h
@@ -191,6 +191,10 @@ void DRW_xr_drawing_end(void);
/* For garbage collection */
void DRW_cache_free_old_batches(struct Main *bmain);
+void DRW_cache_free_old_subdiv(void);
+
+/* For the OpenGL evaluators and garbage collected subdivision data. */
+void DRW_subdiv_free(void);
/* Never use this. Only for closing blender. */
void DRW_opengl_context_enable_ex(bool restore);
diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h
index ccd53f6c037..589b035b8bd 100644
--- a/source/blender/draw/engines/eevee/eevee_lightcache.h
+++ b/source/blender/draw/engines/eevee/eevee_lightcache.h
@@ -33,6 +33,10 @@ struct Scene;
struct SceneEEVEE;
struct ViewLayer;
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/**
* Light Bake.
*/
@@ -77,3 +81,7 @@ void EEVEE_lightcache_info_update(struct SceneEEVEE *eevee);
void EEVEE_lightcache_blend_write(struct BlendWriter *writer, struct LightCache *cache);
void EEVEE_lightcache_blend_read_data(struct BlendDataReader *reader, struct LightCache *cache);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
index 315133186da..dfff45cbca5 100644
--- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
+++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
@@ -99,6 +99,11 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it
return;
}
+ if ((fx->flag & FX_BLUR_DOF_MODE) && iter->pd->camera == NULL) {
+ /* No blur outside camera view (or when DOF is disabled on the camera). */
+ return;
+ }
+
DRWShadingGroup *grp;
const float s = sin(fx->rotation);
const float c = cos(fx->rotation);
@@ -108,7 +113,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it
DRW_view_persmat_get(NULL, persmat, false);
const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3]));
- if ((fx->flag & FX_BLUR_DOF_MODE) && iter->pd->camera != NULL) {
+ if ((fx->flag & FX_BLUR_DOF_MODE)) {
/* Compute circle of confusion size. */
float coc = (iter->pd->dof_params[0] / -w) - iter->pd->dof_params[1];
copy_v2_fl(blur_size, fabsf(coc));
diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c
index 2345a110134..a754e81b949 100644
--- a/source/blender/draw/engines/overlay/overlay_armature.c
+++ b/source/blender/draw/engines/overlay/overlay_armature.c
@@ -589,7 +589,7 @@ static void drw_shgroup_bone_custom_wire(ArmatureDrawContext *ctx,
Object *custom)
{
/* See comments in #drw_shgroup_bone_custom_solid. */
- Mesh *mesh = BKE_object_get_evaluated_mesh(custom);
+ Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(custom);
if (mesh == NULL) {
return;
}
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c
index 03fb3b92277..1110658e3b2 100644
--- a/source/blender/draw/intern/draw_cache.c
+++ b/source/blender/draw/intern/draw_cache.c
@@ -923,7 +923,7 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob)
GPUVertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob)
{
- Mesh *me = BKE_object_get_evaluated_mesh(ob);
+ Mesh *me = BKE_object_get_evaluated_mesh_no_subsurf(ob);
short type = (me != NULL) ? OB_MESH : ob->type;
switch (type) {
@@ -950,7 +950,7 @@ int DRW_cache_object_material_count_get(struct Object *ob)
{
short type = ob->type;
- Mesh *me = BKE_object_get_evaluated_mesh(ob);
+ Mesh *me = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (me != NULL && type != OB_POINTCLOUD) {
/* Some object types can have one data type in ob->data, but will be rendered as mesh.
* For point clouds this never happens. Ideally this check would happen at another level
@@ -3021,7 +3021,7 @@ GPUBatch *DRW_cache_surf_surface_get(Object *ob)
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_surface(mesh_eval);
}
@@ -3034,7 +3034,7 @@ GPUBatch *DRW_cache_surf_edge_wire_get(Object *ob)
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_loose_edges(mesh_eval);
}
@@ -3047,7 +3047,7 @@ GPUBatch *DRW_cache_surf_face_wireframe_get(Object *ob)
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_wireframes_face(mesh_eval);
}
@@ -3059,7 +3059,7 @@ GPUBatch *DRW_cache_surf_edge_detection_get(Object *ob, bool *r_is_manifold)
{
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_edge_detection(mesh_eval, r_is_manifold);
}
@@ -3072,7 +3072,7 @@ GPUBatch *DRW_cache_surf_loose_edges_get(Object *ob)
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_loose_edges(mesh_eval);
}
@@ -3089,7 +3089,7 @@ GPUBatch **DRW_cache_surf_surface_shaded_get(Object *ob,
BLI_assert(ob->type == OB_SURF);
struct Curve *cu = ob->data;
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
if (mesh_eval != NULL) {
return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len);
}
@@ -3382,7 +3382,7 @@ GPUBatch *DRW_cache_cursor_get(bool crosshair_lines)
void drw_batch_cache_validate(Object *ob)
{
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
switch (ob->type) {
case OB_MESH:
DRW_mesh_batch_cache_validate((Mesh *)ob->data);
@@ -3431,7 +3431,7 @@ void drw_batch_cache_generate_requested(Object *ob)
DRW_object_use_hide_faces(ob)) ||
((mode == CTX_MODE_EDIT_MESH) && DRW_object_is_in_edit_mode(ob))));
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
switch (ob->type) {
case OB_MESH:
DRW_mesh_batch_cache_create_requested(
@@ -3470,7 +3470,7 @@ void drw_batch_cache_generate_requested_evaluated_mesh(Object *ob)
DRW_object_use_hide_faces(ob)) ||
((mode == CTX_MODE_EDIT_MESH) && DRW_object_is_in_edit_mode(ob))));
- Mesh *mesh = BKE_object_get_evaluated_mesh(ob);
+ Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(ob);
DRW_mesh_batch_cache_create_requested(DST.task_graph, ob, mesh, scene, is_paint_mode, use_hide);
}
@@ -3481,7 +3481,7 @@ void drw_batch_cache_generate_requested_delayed(Object *ob)
void DRW_batch_cache_free_old(Object *ob, int ctime)
{
- struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
switch (ob->type) {
case OB_MESH:
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h
index ba42cdf66e7..6de9788b434 100644
--- a/source/blender/draw/intern/draw_cache_extract.h
+++ b/source/blender/draw/intern/draw_cache_extract.h
@@ -22,6 +22,7 @@
#pragma once
+struct DRWSubdivCache;
struct TaskGraph;
#include "DNA_customdata_types.h"
@@ -244,6 +245,13 @@ typedef enum DRWBatchFlag {
BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of bit fields");
+typedef struct MeshExtractLooseGeom {
+ int edge_len;
+ int vert_len;
+ int *verts;
+ int *edges;
+} MeshExtractLooseGeom;
+
/**
* Data that are kept around between extractions to reduce rebuilding time.
*
@@ -252,12 +260,7 @@ BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of b
typedef struct MeshBufferCache {
MeshBufferList buff;
- struct {
- int edge_len;
- int vert_len;
- int *verts;
- int *edges;
- } loose_geom;
+ MeshExtractLooseGeom loose_geom;
struct {
int *tri_first_index;
@@ -283,6 +286,8 @@ typedef struct MeshBatchCache {
GPUBatch **surface_per_mat;
+ struct DRWSubdivCache *subdiv_cache;
+
DRWBatchFlag batch_requested; /* DRWBatchFlag */
DRWBatchFlag batch_ready; /* DRWBatchFlag */
@@ -332,9 +337,14 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
const bool do_uvedit,
const bool use_subsurf_fdots,
const Scene *scene,
- const ToolSettings *ts,
+ const struct ToolSettings *ts,
const bool use_hide);
+void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ struct DRWSubdivCache *subdiv_cache,
+ const struct ToolSettings *ts);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc
index 485b803310c..383a3b05b67 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh.cc
+++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc
@@ -42,6 +42,7 @@
#include "draw_cache_extract.h"
#include "draw_cache_inline.h"
+#include "draw_subdivision.h"
#include "mesh_extractors/extract_mesh.h"
@@ -783,6 +784,99 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
/** \} */
+/* ---------------------------------------------------------------------- */
+/** \name Subdivision Extract Loop
+ * \{ */
+
+static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ DRWSubdivCache *subdiv_cache,
+ const ToolSettings *ts)
+{
+ /* Create an array containing all the extractors that needs to be executed. */
+ ExtractorRunDatas extractors;
+
+ MeshBufferList *mbuflist = &mbc->buff;
+
+#define EXTRACT_ADD_REQUESTED(type, name) \
+ do { \
+ if (DRW_##type##_requested(mbuflist->type.name)) { \
+ const MeshExtract *extractor = &extract_##name; \
+ extractors.append(extractor); \
+ } \
+ } while (0)
+
+ /* The order in which extractors are added to the list matters somewhat, as some buffers are
+ * reused when building others. */
+ EXTRACT_ADD_REQUESTED(ibo, tris);
+ EXTRACT_ADD_REQUESTED(vbo, pos_nor);
+ EXTRACT_ADD_REQUESTED(vbo, lnor);
+ for (int i = 0; i < GPU_MAX_ATTR; i++) {
+ EXTRACT_ADD_REQUESTED(vbo, attr[i]);
+ }
+
+ /* We use only one extractor for face dots, as the work is done in a single compute shader. */
+ if (DRW_vbo_requested(mbuflist->vbo.fdots_nor) || DRW_vbo_requested(mbuflist->vbo.fdots_pos) ||
+ DRW_ibo_requested(mbuflist->ibo.fdots)) {
+ extractors.append(&extract_fdots_pos);
+ }
+
+ EXTRACT_ADD_REQUESTED(ibo, lines);
+ EXTRACT_ADD_REQUESTED(ibo, edituv_points);
+ EXTRACT_ADD_REQUESTED(ibo, edituv_tris);
+ EXTRACT_ADD_REQUESTED(ibo, edituv_lines);
+ EXTRACT_ADD_REQUESTED(vbo, vert_idx);
+ EXTRACT_ADD_REQUESTED(vbo, edge_idx);
+ EXTRACT_ADD_REQUESTED(vbo, poly_idx);
+ EXTRACT_ADD_REQUESTED(vbo, edge_fac);
+ EXTRACT_ADD_REQUESTED(ibo, points);
+ EXTRACT_ADD_REQUESTED(vbo, edit_data);
+ EXTRACT_ADD_REQUESTED(vbo, edituv_data);
+ /* Make sure UVs are computed before edituv stuffs. */
+ EXTRACT_ADD_REQUESTED(vbo, uv);
+ EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_area);
+ EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
+ EXTRACT_ADD_REQUESTED(ibo, lines_adjacency);
+ EXTRACT_ADD_REQUESTED(vbo, vcol);
+ EXTRACT_ADD_REQUESTED(vbo, weights);
+ EXTRACT_ADD_REQUESTED(vbo, sculpt_data);
+
+#undef EXTRACT_ADD_REQUESTED
+
+ if (extractors.is_empty()) {
+ return;
+ }
+
+ MeshRenderData mr;
+ draw_subdiv_init_mesh_render_data(subdiv_cache, &mr, ts);
+ mesh_render_data_update_loose_geom(&mr, mbc, MR_ITER_LEDGE | MR_ITER_LVERT, MR_DATA_LOOSE_GEOM);
+
+ void *data_stack = MEM_mallocN(extractors.data_size_total(), __func__);
+ uint32_t data_offset = 0;
+ for (const ExtractorRunData &run_data : extractors) {
+ const MeshExtract *extractor = run_data.extractor;
+ void *buffer = mesh_extract_buffer_get(extractor, mbuflist);
+ void *data = POINTER_OFFSET(data_stack, data_offset);
+
+ extractor->init_subdiv(subdiv_cache, &mr, cache, buffer, data);
+
+ if (extractor->iter_subdiv) {
+ extractor->iter_subdiv(subdiv_cache, &mr, data);
+ }
+
+ if (extractor->iter_loose_geom_subdiv) {
+ extractor->iter_loose_geom_subdiv(subdiv_cache, &mr, &mbc->loose_geom, buffer, data);
+ }
+
+ if (extractor->finish_subdiv) {
+ extractor->finish_subdiv(subdiv_cache, buffer, data);
+ }
+ }
+ MEM_freeN(data_stack);
+}
+
+/** \} */
+
} // namespace blender::draw
extern "C" {
@@ -818,4 +912,12 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
use_hide);
}
+void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache,
+ MeshBufferCache *mbc,
+ DRWSubdivCache *subdiv_cache,
+ const ToolSettings *ts)
+{
+ blender::draw::mesh_buffer_cache_create_requested_subdiv(cache, mbc, subdiv_cache, ts);
+}
+
} // extern "C"
diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c
index 483e52ed547..ddad07a7476 100644
--- a/source/blender/draw/intern/draw_cache_impl_gpencil.c
+++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c
@@ -642,7 +642,7 @@ static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_
float(*tpoints2d)[2] = MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__);
/* Triangulate in 2D. */
for (int i = 0; i < vert_len; i++) {
- copy_v2_v2(tpoints2d[i], &tpoints[i].x);
+ copy_v2_v2(tpoints2d[i], tpoints[i].m_xy);
}
/* Compute directly inside the IBO data buffer. */
/* OPTI: This is a bottleneck if the stroke is very long. */
diff --git a/source/blender/draw/intern/draw_cache_impl_hair.c b/source/blender/draw/intern/draw_cache_impl_hair.cc
index ed0c46ad45a..80f0a3daecc 100644
--- a/source/blender/draw/intern/draw_cache_impl_hair.c
+++ b/source/blender/draw/intern/draw_cache_impl_hair.cc
@@ -23,7 +23,7 @@
* \brief Hair API for render engines
*/
-#include <string.h>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -49,27 +49,28 @@ static void hair_batch_cache_clear(Hair *hair);
/* ---------------------------------------------------------------------- */
/* Hair GPUBatch Cache */
-typedef struct HairBatchCache {
+struct HairBatchCache {
ParticleHairCache hair;
/* settings to determine if cache is invalid */
bool is_dirty;
-} HairBatchCache;
+};
/* GPUBatch cache management. */
static bool hair_batch_cache_valid(Hair *hair)
{
- HairBatchCache *cache = hair->batch_cache;
+ HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache);
return (cache && cache->is_dirty == false);
}
static void hair_batch_cache_init(Hair *hair)
{
- HairBatchCache *cache = hair->batch_cache;
+ HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache);
if (!cache) {
- cache = hair->batch_cache = MEM_callocN(sizeof(*cache), __func__);
+ cache = MEM_cnew<HairBatchCache>(__func__);
+ hair->batch_cache = cache;
}
else {
memset(cache, 0, sizeof(*cache));
@@ -89,13 +90,13 @@ void DRW_hair_batch_cache_validate(Hair *hair)
static HairBatchCache *hair_batch_cache_get(Hair *hair)
{
DRW_hair_batch_cache_validate(hair);
- return hair->batch_cache;
+ return static_cast<HairBatchCache *>(hair->batch_cache);
}
void DRW_hair_batch_cache_dirty_tag(Hair *hair, int mode)
{
- HairBatchCache *cache = hair->batch_cache;
- if (cache == NULL) {
+ HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache);
+ if (cache == nullptr) {
return;
}
switch (mode) {
@@ -109,7 +110,7 @@ void DRW_hair_batch_cache_dirty_tag(Hair *hair, int mode)
static void hair_batch_cache_clear(Hair *hair)
{
- HairBatchCache *cache = hair->batch_cache;
+ HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache);
if (!cache) {
return;
}
@@ -125,8 +126,8 @@ void DRW_hair_batch_cache_free(Hair *hair)
static void ensure_seg_pt_count(Hair *hair, ParticleHairCache *hair_cache)
{
- if ((hair_cache->pos != NULL && hair_cache->indices != NULL) ||
- (hair_cache->proc_point_buf != NULL)) {
+ if ((hair_cache->pos != nullptr && hair_cache->indices != nullptr) ||
+ (hair_cache->proc_point_buf != nullptr)) {
return;
}
@@ -153,7 +154,7 @@ static void hair_batch_cache_fill_segments_proc_pos(Hair *hair,
for (int i = 0; i < num_curves; i++, curve++) {
float(*curve_co)[3] = hair->co + curve->firstpoint;
float total_len = 0.0f;
- float *co_prev = NULL, *seg_data_first;
+ float *co_prev = nullptr, *seg_data_first;
for (int j = 0; j < curve->numpoints; j++) {
float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step);
copy_v3_v3(seg_data, curve_co[j]);
@@ -181,7 +182,7 @@ static void hair_batch_cache_ensure_procedural_pos(Hair *hair,
ParticleHairCache *cache,
GPUMaterial *gpu_material)
{
- if (cache->proc_point_buf == NULL) {
+ if (cache->proc_point_buf == nullptr) {
/* initialize vertex format */
GPUVertFormat format = {0};
uint pos_id = GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
@@ -209,7 +210,7 @@ static void hair_batch_cache_ensure_procedural_pos(Hair *hair,
cache->point_tex = GPU_texture_create_from_vertbuf("hair_point", cache->proc_point_buf);
}
- if (gpu_material && cache->proc_length_buf != NULL && cache->length_tex) {
+ if (gpu_material && cache->proc_length_buf != nullptr && cache->length_tex) {
ListBase gpu_attrs = GPU_material_attributes(gpu_material);
LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &gpu_attrs) {
if (attr->type == CD_HAIRLENGTH) {
@@ -306,7 +307,7 @@ static void hair_batch_cache_ensure_procedural_indices(Hair *hair,
{
BLI_assert(thickness_res <= MAX_THICKRES); /* Cylinder strip not currently supported. */
- if (cache->final[subdiv].proc_hairs[thickness_res - 1] != NULL) {
+ if (cache->final[subdiv].proc_hairs[thickness_res - 1] != nullptr) {
return;
}
@@ -340,7 +341,7 @@ bool hair_ensure_procedural_data(Object *object,
int thickness_res)
{
bool need_ft_update = false;
- Hair *hair = object->data;
+ Hair *hair = static_cast<Hair *>(object->data);
HairBatchCache *cache = hair_batch_cache_get(hair);
*r_hair_cache = &cache->hair;
@@ -349,23 +350,23 @@ bool hair_ensure_procedural_data(Object *object,
(*r_hair_cache)->final[subdiv].strands_res = 1 << (steps + subdiv);
/* Refreshed on combing and simulation. */
- if ((*r_hair_cache)->proc_point_buf == NULL) {
+ if ((*r_hair_cache)->proc_point_buf == nullptr) {
ensure_seg_pt_count(hair, &cache->hair);
hair_batch_cache_ensure_procedural_pos(hair, &cache->hair, gpu_material);
need_ft_update = true;
}
/* Refreshed if active layer or custom data changes. */
- if ((*r_hair_cache)->strand_tex == NULL) {
+ if ((*r_hair_cache)->strand_tex == nullptr) {
hair_batch_cache_ensure_procedural_strand_data(hair, &cache->hair);
}
/* Refreshed only on subdiv count change. */
- if ((*r_hair_cache)->final[subdiv].proc_buf == NULL) {
+ if ((*r_hair_cache)->final[subdiv].proc_buf == nullptr) {
hair_batch_cache_ensure_procedural_final_points(&cache->hair, subdiv);
need_ft_update = true;
}
- if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == NULL) {
+ if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == nullptr) {
hair_batch_cache_ensure_procedural_indices(hair, &cache->hair, thickness_res, subdiv);
}
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index 82b3b5aee41..1e5ffc14911 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -54,6 +54,7 @@
#include "BKE_object_deform.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
+#include "BKE_subdiv_modifier.h"
#include "atomic_ops.h"
@@ -69,6 +70,7 @@
#include "draw_cache_extract.h"
#include "draw_cache_inline.h"
+#include "draw_subdivision.h"
#include "draw_cache_impl.h" /* own include */
@@ -380,6 +382,7 @@ static void drw_mesh_attributes_add_request(DRW_MeshAttributes *attrs,
BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->ldata;
break;
@@ -395,6 +398,7 @@ BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me)
BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->pdata;
break;
@@ -410,6 +414,7 @@ BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me)
BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->edata;
break;
@@ -425,6 +430,7 @@ BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me)
BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me)
{
switch ((eMeshWrapperType)me->runtime.wrapper_type) {
+ case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
return &me->vdata;
break;
@@ -1037,6 +1043,15 @@ static void mesh_buffer_cache_clear(MeshBufferCache *mbc)
mbc->poly_sorted.visible_tri_len = 0;
}
+static void mesh_batch_cache_free_subdiv_cache(MeshBatchCache *cache)
+{
+ if (cache->subdiv_cache) {
+ draw_subdiv_cache_free(cache->subdiv_cache);
+ MEM_freeN(cache->subdiv_cache);
+ cache->subdiv_cache = NULL;
+ }
+}
+
static void mesh_batch_cache_clear(Mesh *me)
{
MeshBatchCache *cache = me->runtime.batch_cache;
@@ -1064,6 +1079,8 @@ static void mesh_batch_cache_clear(Mesh *me)
cache->batch_ready = 0;
drw_mesh_weight_state_clear(&cache->weight_state);
+
+ mesh_batch_cache_free_subdiv_cache(cache);
}
void DRW_mesh_batch_cache_free(Mesh *me)
@@ -1693,6 +1710,10 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
const bool do_uvcage = is_editmode && !me->edit_mesh->mesh_eval_final->runtime.is_original;
+ const int required_mode = BKE_subsurf_modifier_eval_required_mode(DRW_state_is_scene_render(),
+ is_editmode);
+ const bool do_subdivision = BKE_subsurf_modifier_can_do_gpu_subdiv(scene, ob, required_mode);
+
MeshBufferList *mbuflist = &cache->final.buff;
/* Initialize batches and request VBO's & IBO's. */
@@ -2038,6 +2059,15 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph,
true);
}
+ if (do_subdivision) {
+ DRW_create_subdivision(scene, ob, me, cache, &cache->final, ts);
+ }
+ else {
+ /* The subsurf modifier may have been recently removed, or another modifier was added after it,
+ * so free any potential subdivision cache as it is not needed anymore. */
+ mesh_batch_cache_free_subdiv_cache(cache);
+ }
+
mesh_buffer_cache_create_requested(task_graph,
cache,
&cache->final,
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
new file mode 100644
index 00000000000..f8d8674f2a7
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -0,0 +1,1932 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#include "draw_subdivision.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_editmesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_subdiv.h"
+#include "BKE_subdiv_eval.h"
+#include "BKE_subdiv_foreach.h"
+#include "BKE_subdiv_mesh.h"
+#include "BKE_subdiv_modifier.h"
+
+#include "BLI_linklist.h"
+
+#include "BLI_string.h"
+
+#include "PIL_time.h"
+
+#include "DRW_engine.h"
+#include "DRW_render.h"
+
+#include "GPU_capabilities.h"
+#include "GPU_compute.h"
+#include "GPU_index_buffer.h"
+#include "GPU_state.h"
+#include "GPU_vertex_buffer.h"
+
+#include "opensubdiv_capi.h"
+#include "opensubdiv_capi_type.h"
+#include "opensubdiv_converter_capi.h"
+#include "opensubdiv_evaluator_capi.h"
+#include "opensubdiv_topology_refiner_capi.h"
+
+#include "draw_cache_extract.h"
+#include "draw_cache_impl.h"
+#include "draw_cache_inline.h"
+#include "mesh_extractors/extract_mesh.h"
+
+extern "C" char datatoc_common_subdiv_custom_data_interp_comp_glsl[];
+extern "C" char datatoc_common_subdiv_ibo_lines_comp_glsl[];
+extern "C" char datatoc_common_subdiv_ibo_tris_comp_glsl[];
+extern "C" char datatoc_common_subdiv_lib_glsl[];
+extern "C" char datatoc_common_subdiv_normals_accumulate_comp_glsl[];
+extern "C" char datatoc_common_subdiv_normals_finalize_comp_glsl[];
+extern "C" char datatoc_common_subdiv_patch_evaluation_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_edge_fac_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_lnor_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_sculpt_data_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_edituv_strech_angle_comp_glsl[];
+extern "C" char datatoc_common_subdiv_vbo_edituv_strech_area_comp_glsl[];
+
+enum {
+ SHADER_BUFFER_LINES,
+ SHADER_BUFFER_LINES_LOOSE,
+ SHADER_BUFFER_EDGE_FAC,
+ SHADER_BUFFER_LNOR,
+ SHADER_BUFFER_TRIS,
+ SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS,
+ SHADER_BUFFER_NORMALS_ACCUMULATE,
+ SHADER_BUFFER_NORMALS_FINALIZE,
+ SHADER_PATCH_EVALUATION,
+ SHADER_PATCH_EVALUATION_LIMIT_NORMALS,
+ SHADER_PATCH_EVALUATION_FVAR,
+ SHADER_PATCH_EVALUATION_FACE_DOTS,
+ SHADER_COMP_CUSTOM_DATA_INTERP_1D,
+ SHADER_COMP_CUSTOM_DATA_INTERP_2D,
+ SHADER_COMP_CUSTOM_DATA_INTERP_3D,
+ SHADER_COMP_CUSTOM_DATA_INTERP_4D,
+ SHADER_BUFFER_SCULPT_DATA,
+ SHADER_BUFFER_UV_STRETCH_ANGLE,
+ SHADER_BUFFER_UV_STRETCH_AREA,
+
+ NUM_SHADERS,
+};
+
+static GPUShader *g_subdiv_shaders[NUM_SHADERS];
+
+static const char *get_shader_code(int shader_type)
+{
+ switch (shader_type) {
+ case SHADER_BUFFER_LINES:
+ case SHADER_BUFFER_LINES_LOOSE: {
+ return datatoc_common_subdiv_ibo_lines_comp_glsl;
+ }
+ case SHADER_BUFFER_EDGE_FAC: {
+ return datatoc_common_subdiv_vbo_edge_fac_comp_glsl;
+ }
+ case SHADER_BUFFER_LNOR: {
+ return datatoc_common_subdiv_vbo_lnor_comp_glsl;
+ }
+ case SHADER_BUFFER_TRIS:
+ case SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS: {
+ return datatoc_common_subdiv_ibo_tris_comp_glsl;
+ }
+ case SHADER_BUFFER_NORMALS_ACCUMULATE: {
+ return datatoc_common_subdiv_normals_accumulate_comp_glsl;
+ }
+ case SHADER_BUFFER_NORMALS_FINALIZE: {
+ return datatoc_common_subdiv_normals_finalize_comp_glsl;
+ }
+ case SHADER_PATCH_EVALUATION:
+ case SHADER_PATCH_EVALUATION_LIMIT_NORMALS:
+ case SHADER_PATCH_EVALUATION_FVAR:
+ case SHADER_PATCH_EVALUATION_FACE_DOTS: {
+ return datatoc_common_subdiv_patch_evaluation_comp_glsl;
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_1D:
+ case SHADER_COMP_CUSTOM_DATA_INTERP_2D:
+ case SHADER_COMP_CUSTOM_DATA_INTERP_3D:
+ case SHADER_COMP_CUSTOM_DATA_INTERP_4D: {
+ return datatoc_common_subdiv_custom_data_interp_comp_glsl;
+ }
+ case SHADER_BUFFER_SCULPT_DATA: {
+ return datatoc_common_subdiv_vbo_sculpt_data_comp_glsl;
+ }
+ case SHADER_BUFFER_UV_STRETCH_ANGLE: {
+ return datatoc_common_subdiv_vbo_edituv_strech_angle_comp_glsl;
+ }
+ case SHADER_BUFFER_UV_STRETCH_AREA: {
+ return datatoc_common_subdiv_vbo_edituv_strech_area_comp_glsl;
+ }
+ }
+ return nullptr;
+}
+
+static const char *get_shader_name(int shader_type)
+{
+ switch (shader_type) {
+ case SHADER_BUFFER_LINES: {
+ return "subdiv lines build";
+ }
+ case SHADER_BUFFER_LINES_LOOSE: {
+ return "subdiv lines loose build";
+ }
+ case SHADER_BUFFER_LNOR: {
+ return "subdiv lnor build";
+ }
+ case SHADER_BUFFER_EDGE_FAC: {
+ return "subdiv edge fac build";
+ }
+ case SHADER_BUFFER_TRIS:
+ case SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS: {
+ return "subdiv tris";
+ }
+ case SHADER_BUFFER_NORMALS_ACCUMULATE: {
+ return "subdiv normals accumulate";
+ }
+ case SHADER_BUFFER_NORMALS_FINALIZE: {
+ return "subdiv normals finalize";
+ }
+ case SHADER_PATCH_EVALUATION: {
+ return "subdiv patch evaluation";
+ }
+ case SHADER_PATCH_EVALUATION_LIMIT_NORMALS: {
+ return "subdiv patch evaluation limit normals";
+ }
+ case SHADER_PATCH_EVALUATION_FVAR: {
+ return "subdiv patch evaluation face-varying";
+ }
+ case SHADER_PATCH_EVALUATION_FACE_DOTS: {
+ return "subdiv patch evaluation face dots";
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_1D: {
+ return "subdiv custom data interp 1D";
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_2D: {
+ return "subdiv custom data interp 2D";
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_3D: {
+ return "subdiv custom data interp 3D";
+ }
+ case SHADER_COMP_CUSTOM_DATA_INTERP_4D: {
+ return "subdiv custom data interp 4D";
+ }
+ case SHADER_BUFFER_SCULPT_DATA: {
+ return "subdiv sculpt data";
+ }
+ case SHADER_BUFFER_UV_STRETCH_ANGLE: {
+ return "subdiv uv stretch angle";
+ }
+ case SHADER_BUFFER_UV_STRETCH_AREA: {
+ return "subdiv uv stretch area";
+ }
+ }
+ return nullptr;
+}
+
+static GPUShader *get_patch_evaluation_shader(int shader_type)
+{
+ if (g_subdiv_shaders[shader_type] == nullptr) {
+ const char *compute_code = get_shader_code(shader_type);
+
+ const char *defines = nullptr;
+ if (shader_type == SHADER_PATCH_EVALUATION_LIMIT_NORMALS) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define LIMIT_NORMALS\n";
+ }
+ else if (shader_type == SHADER_PATCH_EVALUATION_FVAR) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define FVAR_EVALUATION\n";
+ }
+ else if (shader_type == SHADER_PATCH_EVALUATION_FACE_DOTS) {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"
+ "#define FDOTS_EVALUATION\n";
+ }
+ else {
+ defines =
+ "#define OSD_PATCH_BASIS_GLSL\n"
+ "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n";
+ }
+
+ /* Merge OpenSubdiv library code with our own library code. */
+ const char *patch_basis_source = openSubdiv_getGLSLPatchBasisSource();
+ const char *subdiv_lib_code = datatoc_common_subdiv_lib_glsl;
+ char *library_code = static_cast<char *>(
+ MEM_mallocN(strlen(patch_basis_source) + strlen(subdiv_lib_code) + 1,
+ "subdiv patch evaluation library code"));
+ library_code[0] = '\0';
+ strcat(library_code, patch_basis_source);
+ strcat(library_code, subdiv_lib_code);
+
+ g_subdiv_shaders[shader_type] = GPU_shader_create_compute(
+ compute_code, library_code, defines, get_shader_name(shader_type));
+
+ MEM_freeN(library_code);
+ }
+
+ return g_subdiv_shaders[shader_type];
+}
+
+static GPUShader *get_subdiv_shader(int shader_type, const char *defines)
+{
+ if (shader_type == SHADER_PATCH_EVALUATION ||
+ shader_type == SHADER_PATCH_EVALUATION_LIMIT_NORMALS ||
+ shader_type == SHADER_PATCH_EVALUATION_FVAR ||
+ shader_type == SHADER_PATCH_EVALUATION_FACE_DOTS) {
+ return get_patch_evaluation_shader(shader_type);
+ }
+ if (g_subdiv_shaders[shader_type] == nullptr) {
+ const char *compute_code = get_shader_code(shader_type);
+ g_subdiv_shaders[shader_type] = GPU_shader_create_compute(
+ compute_code, datatoc_common_subdiv_lib_glsl, defines, get_shader_name(shader_type));
+ }
+ return g_subdiv_shaders[shader_type];
+}
+
+/* -------------------------------------------------------------------- */
+/** Vertex formats used for data transfer from OpenSubdiv, and for data processing on our side.
+ * \{ */
+
+static GPUVertFormat *get_uvs_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
+/* Vertex format for `OpenSubdiv::Osd::PatchArray`. */
+static GPUVertFormat *get_patch_array_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "regDesc", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "desc", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "numPatches", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "indexBase", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "stride", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "primitiveIdBase", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/* Vertex format used for the `PatchTable::PatchHandle`. */
+static GPUVertFormat *get_patch_handle_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "vertex_index", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "array_index", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "patch_index", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/* Vertex format used for the quad-tree nodes of the PatchMap. */
+static GPUVertFormat *get_quadtree_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "child", GPU_COMP_U32, 4, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/* Vertex format for `OpenSubdiv::Osd::PatchParam`, not really used, it is only for making sure
+ * that the #GPUVertBuf used to wrap the OpenSubdiv patch param buffer is valid. */
+static GPUVertFormat *get_patch_param_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
+/* Vertex format for the patches' vertices index buffer. */
+static GPUVertFormat *get_patch_index_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_I32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/* Vertex format for the OpenSubdiv vertex buffer. */
+static GPUVertFormat *get_subdiv_vertex_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* We use 4 components for the vectors to account for padding in the compute shaders, where
+ * vec3 is promoted to vec4. */
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
+struct CompressedPatchCoord {
+ int ptex_face_index;
+ /* UV coordinate encoded as u << 16 | v, where u and v are quantized on 16-bits. */
+ unsigned int encoded_uv;
+};
+
+MINLINE CompressedPatchCoord make_patch_coord(int ptex_face_index, float u, float v)
+{
+ CompressedPatchCoord patch_coord = {
+ ptex_face_index,
+ (static_cast<unsigned int>(u * 65535.0f) << 16) | static_cast<unsigned int>(v * 65535.0f),
+ };
+ return patch_coord;
+}
+
+/* Vertex format used for the #CompressedPatchCoord. */
+static GPUVertFormat *get_blender_patch_coords_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* WARNING! Adjust #CompressedPatchCoord accordingly. */
+ GPU_vertformat_attr_add(&format, "ptex_face_index", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ GPU_vertformat_attr_add(&format, "uv", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+static GPUVertFormat *get_origindex_format()
+{
+ static GPUVertFormat format;
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+ return &format;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities to initialize a OpenSubdiv_Buffer for a GPUVertBuf.
+ * \{ */
+
+static void vertbuf_bind_gpu(const OpenSubdiv_Buffer *buffer)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(buffer->data);
+ GPU_vertbuf_use(verts);
+}
+
+static void *vertbuf_alloc(const OpenSubdiv_Buffer *interface, const uint len)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(interface->data);
+ GPU_vertbuf_data_alloc(verts, len);
+ return GPU_vertbuf_get_data(verts);
+}
+
+static void vertbuf_device_alloc(const OpenSubdiv_Buffer *interface, const uint len)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(interface->data);
+ /* This assumes that GPU_USAGE_DEVICE_ONLY was used, which won't allocate host memory. */
+ // BLI_assert(GPU_vertbuf_get_usage(verts) == GPU_USAGE_DEVICE_ONLY);
+ GPU_vertbuf_data_alloc(verts, len);
+}
+
+static void vertbuf_wrap_device_handle(const OpenSubdiv_Buffer *interface, uint64_t handle)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(interface->data);
+ GPU_vertbuf_wrap_handle(verts, handle);
+}
+
+static void vertbuf_update_data(const OpenSubdiv_Buffer *interface,
+ uint start,
+ uint len,
+ const void *data)
+{
+ GPUVertBuf *verts = (GPUVertBuf *)(interface->data);
+ GPU_vertbuf_update_sub(verts, start, len, data);
+}
+
+static void opensubdiv_gpu_buffer_init(OpenSubdiv_Buffer *buffer_interface, GPUVertBuf *vertbuf)
+{
+ buffer_interface->data = vertbuf;
+ buffer_interface->bind_gpu = vertbuf_bind_gpu;
+ buffer_interface->buffer_offset = 0;
+ buffer_interface->wrap_device_handle = vertbuf_wrap_device_handle;
+ buffer_interface->alloc = vertbuf_alloc;
+ buffer_interface->device_alloc = vertbuf_device_alloc;
+ buffer_interface->device_update = vertbuf_update_data;
+}
+
+static GPUVertBuf *create_buffer_and_interface(OpenSubdiv_Buffer *interface, GPUVertFormat *format)
+{
+ GPUVertBuf *buffer = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(buffer, format, GPU_USAGE_DEVICE_ONLY);
+ opensubdiv_gpu_buffer_init(interface, buffer);
+ return buffer;
+}
+
+/** \} */
+
+// --------------------------------------------------------
+
+static uint tris_count_from_number_of_loops(const uint number_of_loops)
+{
+ const uint32_t number_of_quads = number_of_loops / 4;
+ return number_of_quads * 2;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities to build a GPUVertBuf from an origindex buffer.
+ * \{ */
+
+void draw_subdiv_init_origindex_buffer(GPUVertBuf *buffer,
+ int *vert_origindex,
+ uint num_loops,
+ uint loose_len)
+{
+ GPU_vertbuf_init_with_format_ex(buffer, get_origindex_format(), GPU_USAGE_STATIC);
+ GPU_vertbuf_data_alloc(buffer, num_loops + loose_len);
+
+ int *vbo_data = (int *)GPU_vertbuf_get_data(buffer);
+ memcpy(vbo_data, vert_origindex, num_loops * sizeof(int));
+}
+
+GPUVertBuf *draw_subdiv_build_origindex_buffer(int *vert_origindex, uint num_loops)
+{
+ GPUVertBuf *buffer = GPU_vertbuf_calloc();
+ draw_subdiv_init_origindex_buffer(buffer, vert_origindex, num_loops, 0);
+ return buffer;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities for DRWPatchMap.
+ * \{ */
+
+static void draw_patch_map_build(DRWPatchMap *gpu_patch_map, Subdiv *subdiv)
+{
+ GPUVertBuf *patch_map_handles = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(patch_map_handles, get_patch_handle_format(), GPU_USAGE_STATIC);
+
+ GPUVertBuf *patch_map_quadtree = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(patch_map_quadtree, get_quadtree_format(), GPU_USAGE_STATIC);
+
+ OpenSubdiv_Buffer patch_map_handles_interface;
+ opensubdiv_gpu_buffer_init(&patch_map_handles_interface, patch_map_handles);
+
+ OpenSubdiv_Buffer patch_map_quad_tree_interface;
+ opensubdiv_gpu_buffer_init(&patch_map_quad_tree_interface, patch_map_quadtree);
+
+ int min_patch_face = 0;
+ int max_patch_face = 0;
+ int max_depth = 0;
+ int patches_are_triangular = 0;
+
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+ evaluator->getPatchMap(evaluator,
+ &patch_map_handles_interface,
+ &patch_map_quad_tree_interface,
+ &min_patch_face,
+ &max_patch_face,
+ &max_depth,
+ &patches_are_triangular);
+
+ gpu_patch_map->patch_map_handles = patch_map_handles;
+ gpu_patch_map->patch_map_quadtree = patch_map_quadtree;
+ gpu_patch_map->min_patch_face = min_patch_face;
+ gpu_patch_map->max_patch_face = max_patch_face;
+ gpu_patch_map->max_depth = max_depth;
+ gpu_patch_map->patches_are_triangular = patches_are_triangular;
+}
+
+static void draw_patch_map_free(DRWPatchMap *gpu_patch_map)
+{
+ GPU_VERTBUF_DISCARD_SAFE(gpu_patch_map->patch_map_handles);
+ GPU_VERTBUF_DISCARD_SAFE(gpu_patch_map->patch_map_quadtree);
+ gpu_patch_map->min_patch_face = 0;
+ gpu_patch_map->max_patch_face = 0;
+ gpu_patch_map->max_depth = 0;
+ gpu_patch_map->patches_are_triangular = 0;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DRWSubdivCache
+ * \{ */
+
+static void draw_subdiv_cache_free_material_data(DRWSubdivCache *cache)
+{
+ GPU_VERTBUF_DISCARD_SAFE(cache->polygon_mat_offset);
+ MEM_SAFE_FREE(cache->mat_start);
+ MEM_SAFE_FREE(cache->mat_end);
+}
+
+static void draw_subdiv_free_edit_mode_cache(DRWSubdivCache *cache)
+{
+ GPU_VERTBUF_DISCARD_SAFE(cache->verts_orig_index);
+ GPU_VERTBUF_DISCARD_SAFE(cache->edges_orig_index);
+ GPU_VERTBUF_DISCARD_SAFE(cache->fdots_patch_coords);
+}
+
+void draw_subdiv_cache_free(DRWSubdivCache *cache)
+{
+ GPU_VERTBUF_DISCARD_SAFE(cache->patch_coords);
+ GPU_VERTBUF_DISCARD_SAFE(cache->face_ptex_offset_buffer);
+ GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_polygon_offset_buffer);
+ GPU_VERTBUF_DISCARD_SAFE(cache->extra_coarse_face_data);
+ MEM_SAFE_FREE(cache->subdiv_loop_subdiv_vert_index);
+ MEM_SAFE_FREE(cache->subdiv_loop_poly_index);
+ MEM_SAFE_FREE(cache->point_indices);
+ MEM_SAFE_FREE(cache->subdiv_polygon_offset);
+ GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_vertex_face_adjacency_offsets);
+ GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_vertex_face_adjacency);
+ cache->resolution = 0;
+ cache->num_subdiv_loops = 0;
+ cache->num_coarse_poly = 0;
+ cache->num_subdiv_quads = 0;
+ draw_subdiv_free_edit_mode_cache(cache);
+ draw_subdiv_cache_free_material_data(cache);
+ draw_patch_map_free(&cache->gpu_patch_map);
+ if (cache->ubo) {
+ GPU_uniformbuf_free(cache->ubo);
+ cache->ubo = nullptr;
+ }
+}
+
+/* Flags used in #DRWSubdivCache.extra_coarse_face_data. The flags are packed in the upper bits of
+ * each uint (one per coarse face), #SUBDIV_COARSE_FACE_FLAG_OFFSET tells where they are in the
+ * packed bits. */
+#define SUBDIV_COARSE_FACE_FLAG_SMOOTH 1u
+#define SUBDIV_COARSE_FACE_FLAG_SELECT 2u
+#define SUBDIV_COARSE_FACE_FLAG_ACTIVE 4u
+
+#define SUBDIV_COARSE_FACE_FLAG_OFFSET 29u
+
+#define SUBDIV_COARSE_FACE_FLAG_SMOOTH_MASK \
+ (SUBDIV_COARSE_FACE_FLAG_SMOOTH << SUBDIV_COARSE_FACE_FLAG_OFFSET)
+#define SUBDIV_COARSE_FACE_FLAG_SELECT_MASK \
+ (SUBDIV_COARSE_FACE_FLAG_SELECT << SUBDIV_COARSE_FACE_FLAG_OFFSET)
+#define SUBDIV_COARSE_FACE_FLAG_ACTIVE_MASK \
+ (SUBDIV_COARSE_FACE_FLAG_ACTIVE << SUBDIV_COARSE_FACE_FLAG_OFFSET)
+
+#define SUBDIV_COARSE_FACE_LOOP_START_MASK \
+ ~((SUBDIV_COARSE_FACE_FLAG_SMOOTH | SUBDIV_COARSE_FACE_FLAG_SELECT | \
+ SUBDIV_COARSE_FACE_FLAG_ACTIVE) \
+ << SUBDIV_COARSE_FACE_FLAG_OFFSET)
+
+static void draw_subdiv_cache_update_extra_coarse_face_data(DRWSubdivCache *cache, Mesh *mesh)
+{
+ if (cache->extra_coarse_face_data == nullptr) {
+ cache->extra_coarse_face_data = GPU_vertbuf_calloc();
+ static GPUVertFormat format;
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ }
+ GPU_vertbuf_init_with_format_ex(cache->extra_coarse_face_data, &format, GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(cache->extra_coarse_face_data, mesh->totpoly);
+ }
+
+ uint32_t *flags_data = (uint32_t *)(GPU_vertbuf_get_data(cache->extra_coarse_face_data));
+
+ if (cache->bm) {
+ BMesh *bm = cache->bm;
+ BMFace *f;
+ BMIter iter;
+
+ /* Ensure all current elements follow new customdata layout. */
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ const int index = BM_elem_index_get(f);
+ uint32_t flag = 0;
+ if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
+ flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH;
+ }
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ flag |= SUBDIV_COARSE_FACE_FLAG_SELECT;
+ }
+ if (f == bm->act_face) {
+ flag |= SUBDIV_COARSE_FACE_FLAG_ACTIVE;
+ }
+ const int loopstart = BM_elem_index_get(f->l_first);
+ flags_data[index] = (uint)(loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);
+ }
+ }
+ else {
+ for (int i = 0; i < mesh->totpoly; i++) {
+ uint32_t flag = 0;
+ if ((mesh->mpoly[i].flag & ME_SMOOTH) != 0) {
+ flag = SUBDIV_COARSE_FACE_FLAG_SMOOTH;
+ }
+ flags_data[i] = (uint)(mesh->mpoly[i].loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);
+ }
+ }
+
+ /* Make sure updated data is re-uploaded. */
+ GPU_vertbuf_tag_dirty(cache->extra_coarse_face_data);
+}
+
+static DRWSubdivCache *mesh_batch_cache_ensure_subdiv_cache(MeshBatchCache *mbc)
+{
+ DRWSubdivCache *subdiv_cache = mbc->subdiv_cache;
+ if (subdiv_cache == nullptr) {
+ subdiv_cache = static_cast<DRWSubdivCache *>(
+ MEM_callocN(sizeof(DRWSubdivCache), "DRWSubdivCache"));
+ }
+ mbc->subdiv_cache = subdiv_cache;
+ return subdiv_cache;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Subdivision grid traversal.
+ *
+ * Traverse the uniform subdivision grid over coarse faces and gather useful information for
+ * building the draw buffers on the GPU. We primarily gather the patch coordinates for all
+ * subdivision faces, as well as the original coarse indices for each subdivision element (vertex,
+ * face, or edge) which directly maps to its coarse counterpart (note that all subdivision faces
+ * map to a coarse face). This information will then be cached in #DRWSubdivCache for subsequent
+ * reevaluations, as long as the topology does not change.
+ * \{ */
+
+struct DRWCacheBuildingContext {
+ const Mesh *coarse_mesh;
+ const SubdivToMeshSettings *settings;
+
+ DRWSubdivCache *cache;
+
+ /* Pointers into DRWSubdivCache buffers for easier access during traversal. */
+ CompressedPatchCoord *patch_coords;
+ int *subdiv_loop_vert_index;
+ int *subdiv_loop_subdiv_vert_index;
+ int *subdiv_loop_edge_index;
+ int *subdiv_loop_poly_index;
+ int *point_indices;
+
+ /* Temporary buffers used during traversal. */
+ int *vert_origindex_map;
+ int *edge_origindex_map;
+
+ /* Origindex layers from the mesh to directly look up during traversal the origindex from the
+ * base mesh for edit data so that we do not have to handle yet another GPU buffer and do this in
+ * the shaders. */
+ int *v_origindex;
+ int *e_origindex;
+};
+
+static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_context,
+ const int num_vertices,
+ const int num_edges,
+ const int num_loops,
+ const int num_polygons,
+ const int *subdiv_polygon_offset)
+{
+ if (num_loops == 0) {
+ return false;
+ }
+
+ DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
+ DRWSubdivCache *cache = ctx->cache;
+
+ /* Set topology information. */
+ cache->num_subdiv_edges = (uint)num_edges;
+ cache->num_subdiv_loops = (uint)num_loops;
+ cache->num_subdiv_verts = (uint)num_vertices;
+ cache->num_subdiv_quads = (uint)num_polygons;
+ cache->subdiv_polygon_offset = static_cast<int *>(MEM_dupallocN(subdiv_polygon_offset));
+
+ /* Initialize cache buffers, prefer dynamic usage so we can reuse memory on the host even after
+ * it was sent to the device, since we may use the data while building other buffers on the CPU
+ * side. */
+ cache->patch_coords = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(
+ cache->patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(cache->patch_coords, cache->num_subdiv_loops);
+
+ cache->verts_orig_index = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(
+ cache->verts_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(cache->verts_orig_index, cache->num_subdiv_loops);
+
+ cache->edges_orig_index = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format_ex(
+ cache->edges_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC);
+ GPU_vertbuf_data_alloc(cache->edges_orig_index, cache->num_subdiv_loops);
+
+ cache->subdiv_loop_subdiv_vert_index = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_subdiv_vert_index"));
+
+ cache->subdiv_loop_poly_index = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_poly_index"));
+
+ cache->point_indices = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_verts * sizeof(int), "point_indices"));
+ for (int i = 0; i < num_vertices; i++) {
+ cache->point_indices[i] = -1;
+ }
+
+ /* Initialize context pointers and temporary buffers. */
+ ctx->patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data(cache->patch_coords);
+ ctx->subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(cache->verts_orig_index);
+ ctx->subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(cache->edges_orig_index);
+ ctx->subdiv_loop_subdiv_vert_index = cache->subdiv_loop_subdiv_vert_index;
+ ctx->subdiv_loop_poly_index = cache->subdiv_loop_poly_index;
+ ctx->point_indices = cache->point_indices;
+
+ ctx->v_origindex = static_cast<int *>(
+ CustomData_get_layer(&ctx->coarse_mesh->vdata, CD_ORIGINDEX));
+
+ ctx->e_origindex = static_cast<int *>(
+ CustomData_get_layer(&ctx->coarse_mesh->edata, CD_ORIGINDEX));
+
+ ctx->vert_origindex_map = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_verts * sizeof(int), "subdiv_vert_origindex_map"));
+ for (int i = 0; i < num_vertices; i++) {
+ ctx->vert_origindex_map[i] = -1;
+ }
+
+ ctx->edge_origindex_map = static_cast<int *>(
+ MEM_mallocN(cache->num_subdiv_edges * sizeof(int), "subdiv_edge_origindex_map"));
+ for (int i = 0; i < num_edges; i++) {
+ ctx->edge_origindex_map[i] = -1;
+ }
+
+ return true;
+}
+
+static void draw_subdiv_vertex_corner_cb(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int UNUSED(ptex_face_index),
+ const float UNUSED(u),
+ const float UNUSED(v),
+ const int coarse_vertex_index,
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int subdiv_vertex_index)
+{
+ BLI_assert(coarse_vertex_index != ORIGINDEX_NONE);
+ DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
+ ctx->vert_origindex_map[subdiv_vertex_index] = coarse_vertex_index;
+}
+
+static void draw_subdiv_vertex_edge_cb(const SubdivForeachContext *UNUSED(foreach_context),
+ void *UNUSED(tls_v),
+ const int UNUSED(ptex_face_index),
+ const float UNUSED(u),
+ const float UNUSED(v),
+ const int UNUSED(coarse_edge_index),
+ const int UNUSED(coarse_poly_index),
+ const int UNUSED(coarse_corner),
+ const int UNUSED(subdiv_vertex_index))
+{
+ /* Required if SubdivForeachContext.vertex_corner is also set. */
+}
+
+static void draw_subdiv_edge_cb(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls),
+ const int coarse_edge_index,
+ const int subdiv_edge_index,
+ const int UNUSED(subdiv_v1),
+ const int UNUSED(subdiv_v2))
+{
+ DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
+
+ int coarse_index = coarse_edge_index;
+
+ if (coarse_index != -1) {
+ if (ctx->e_origindex) {
+ coarse_index = ctx->e_origindex[coarse_index];
+ }
+ }
+
+ ctx->edge_origindex_map[subdiv_edge_index] = coarse_index;
+}
+
+static void draw_subdiv_loop_cb(const SubdivForeachContext *foreach_context,
+ void *UNUSED(tls_v),
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ const int UNUSED(coarse_loop_index),
+ const int coarse_poly_index,
+ const int UNUSED(coarse_corner),
+ const int subdiv_loop_index,
+ const int subdiv_vertex_index,
+ const int subdiv_edge_index)
+{
+ DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data);
+ ctx->patch_coords[subdiv_loop_index] = make_patch_coord(ptex_face_index, u, v);
+
+ int coarse_vertex_index = ctx->vert_origindex_map[subdiv_vertex_index];
+
+ if (coarse_vertex_index != -1) {
+ if (ctx->v_origindex) {
+ coarse_vertex_index = ctx->v_origindex[coarse_vertex_index];
+ }
+
+ /* Double check as vorigindex may have modified the index. */
+ if (coarse_vertex_index != -1) {
+ ctx->point_indices[coarse_vertex_index] = subdiv_loop_index;
+ }
+ }
+
+ ctx->subdiv_loop_subdiv_vert_index[subdiv_loop_index] = subdiv_vertex_index;
+ /* For now index the subdiv_edge_index, it will be replaced by the actual coarse edge index
+ * at the end of the traversal as some edges are only then traversed. */
+ ctx->subdiv_loop_edge_index[subdiv_loop_index] = subdiv_edge_index;
+ ctx->subdiv_loop_poly_index[subdiv_loop_index] = coarse_poly_index;
+ ctx->subdiv_loop_vert_index[subdiv_loop_index] = coarse_vertex_index;
+}
+
+static void draw_subdiv_foreach_callbacks(SubdivForeachContext *foreach_context)
+{
+ memset(foreach_context, 0, sizeof(*foreach_context));
+ foreach_context->topology_info = draw_subdiv_topology_info_cb;
+ foreach_context->loop = draw_subdiv_loop_cb;
+ foreach_context->edge = draw_subdiv_edge_cb;
+ foreach_context->vertex_corner = draw_subdiv_vertex_corner_cb;
+ foreach_context->vertex_edge = draw_subdiv_vertex_edge_cb;
+}
+
+static void do_subdiv_traversal(DRWCacheBuildingContext *cache_building_context, Subdiv *subdiv)
+{
+ SubdivForeachContext foreach_context;
+ draw_subdiv_foreach_callbacks(&foreach_context);
+ foreach_context.user_data = cache_building_context;
+
+ BKE_subdiv_foreach_subdiv_geometry(subdiv,
+ &foreach_context,
+ cache_building_context->settings,
+ cache_building_context->coarse_mesh);
+
+ /* Now that traversal is done, we can set up the right original indices for the loop-to-edge map.
+ */
+ for (int i = 0; i < cache_building_context->cache->num_subdiv_loops; i++) {
+ cache_building_context->subdiv_loop_edge_index[i] =
+ cache_building_context
+ ->edge_origindex_map[cache_building_context->subdiv_loop_edge_index[i]];
+ }
+}
+
+static GPUVertBuf *gpu_vertbuf_create_from_format(GPUVertFormat *format, uint len)
+{
+ GPUVertBuf *verts = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format(verts, format);
+ GPU_vertbuf_data_alloc(verts, len);
+ return verts;
+}
+
+/* Build maps to hold enough information to tell which face is adjacent to which vertex; those will
+ * be used for computing normals if limit surfaces are unavailable. */
+static void build_vertex_face_adjacency_maps(DRWSubdivCache *cache)
+{
+ /* +1 so that we do not require a special case for the last vertex, this extra offset will
+ * contain the total number of adjacent faces. */
+ cache->subdiv_vertex_face_adjacency_offsets = gpu_vertbuf_create_from_format(
+ get_origindex_format(), cache->num_subdiv_verts + 1);
+
+ int *vertex_offsets = (int *)GPU_vertbuf_get_data(cache->subdiv_vertex_face_adjacency_offsets);
+ memset(vertex_offsets, 0, sizeof(int) * cache->num_subdiv_verts + 1);
+
+ for (int i = 0; i < cache->num_subdiv_loops; i++) {
+ vertex_offsets[cache->subdiv_loop_subdiv_vert_index[i]]++;
+ }
+
+ int ofs = vertex_offsets[0];
+ vertex_offsets[0] = 0;
+ for (uint i = 1; i < cache->num_subdiv_verts + 1; i++) {
+ int tmp = vertex_offsets[i];
+ vertex_offsets[i] = ofs;
+ ofs += tmp;
+ }
+
+ cache->subdiv_vertex_face_adjacency = gpu_vertbuf_create_from_format(get_origindex_format(),
+ cache->num_subdiv_loops);
+ int *adjacent_faces = (int *)GPU_vertbuf_get_data(cache->subdiv_vertex_face_adjacency);
+ int *tmp_set_faces = static_cast<int *>(
+ MEM_callocN(sizeof(int) * cache->num_subdiv_verts, "tmp subdiv vertex offset"));
+
+ for (int i = 0; i < cache->num_subdiv_loops / 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ const int subdiv_vertex = cache->subdiv_loop_subdiv_vert_index[i * 4 + j];
+ int first_face_offset = vertex_offsets[subdiv_vertex] + tmp_set_faces[subdiv_vertex];
+ adjacent_faces[first_face_offset] = i;
+ tmp_set_faces[subdiv_vertex] += 1;
+ }
+ }
+
+ MEM_freeN(tmp_set_faces);
+}
+
+static bool draw_subdiv_build_cache(DRWSubdivCache *cache,
+ Subdiv *subdiv,
+ Mesh *mesh_eval,
+ const Scene *scene,
+ const SubsurfModifierData *smd,
+ const bool is_final_render)
+{
+ const int level = get_render_subsurf_level(&scene->r, smd->levels, is_final_render);
+ SubdivToMeshSettings to_mesh_settings;
+ to_mesh_settings.resolution = (1 << level) + 1;
+ to_mesh_settings.use_optimal_display = false;
+
+ if (cache->resolution != to_mesh_settings.resolution) {
+ /* Resolution changed, we need to rebuild, free any existing cached data. */
+ draw_subdiv_cache_free(cache);
+ }
+
+ /* If the resolution between the cache and the settings match for some reason, check if the patch
+ * coordinates were not already generated. Those coordinates are specific to the resolution, so
+ * they should be null either after initialization, or after freeing if the resolution (or some
+ * other subdivision setting) changed.
+ */
+ if (cache->patch_coords != nullptr) {
+ return true;
+ }
+
+ DRWCacheBuildingContext cache_building_context;
+ cache_building_context.coarse_mesh = mesh_eval;
+ cache_building_context.settings = &to_mesh_settings;
+ cache_building_context.cache = cache;
+
+ do_subdiv_traversal(&cache_building_context, subdiv);
+ if (cache->num_subdiv_loops == 0) {
+ /* Either the traversal failed, or we have an empty mesh, either way we cannot go any further.
+ * The subdiv_polygon_offset cannot then be reliably stored in the cache, so free it directly.
+ */
+ MEM_SAFE_FREE(cache->subdiv_polygon_offset);
+ return false;
+ }
+
+ /* Build buffers for the PatchMap. */
+ draw_patch_map_build(&cache->gpu_patch_map, subdiv);
+
+ cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
+
+ // Build patch coordinates for all the face dots
+ cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(),
+ mesh_eval->totpoly);
+ CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data(
+ cache->fdots_patch_coords);
+ for (int i = 0; i < mesh_eval->totpoly; i++) {
+ const int ptex_face_index = cache->face_ptex_offset[i];
+ if (mesh_eval->mpoly[i].totloop == 4) {
+ /* For quads, the center coordinate of the coarse face has `u = v = 0.5`. */
+ blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 0.5f, 0.5f);
+ }
+ else {
+ /* For N-gons, since they are split into quads from the center, and since the center is
+ * chosen to be the top right corner of each quad, the center coordinate of the coarse face
+ * is any one of those top right corners with `u = v = 1.0`. */
+ blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 1.0f, 1.0f);
+ }
+ }
+
+ cache->resolution = to_mesh_settings.resolution;
+
+ cache->subdiv_polygon_offset_buffer = draw_subdiv_build_origindex_buffer(
+ cache->subdiv_polygon_offset, mesh_eval->totpoly);
+
+ cache->face_ptex_offset_buffer = draw_subdiv_build_origindex_buffer(cache->face_ptex_offset,
+ mesh_eval->totpoly + 1);
+ cache->num_coarse_poly = mesh_eval->totpoly;
+ cache->point_indices = cache_building_context.point_indices;
+
+ build_vertex_face_adjacency_maps(cache);
+
+ /* Cleanup. */
+ MEM_freeN(cache_building_context.vert_origindex_map);
+ MEM_freeN(cache_building_context.edge_origindex_map);
+
+ return true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DRWSubdivUboStorage.
+ *
+ * Common uniforms for the various shaders.
+ * \{ */
+
+struct DRWSubdivUboStorage {
+ /* Offsets in the buffers data where the source and destination data start. */
+ int src_offset;
+ int dst_offset;
+
+ /* Parameters for the DRWPatchMap. */
+ int min_patch_face;
+ int max_patch_face;
+ int max_depth;
+ int patches_are_triangular;
+
+ /* Coarse topology information. */
+ int coarse_poly_count;
+ uint edge_loose_offset;
+
+ /* Refined topology information. */
+ uint num_subdiv_loops;
+
+ /* Subdivision settings, is int in C but bool in the GLSL code, as there, bools have the same
+ * size as ints, so we should use int in C to ensure that the size of the structure is what GLSL
+ * expects. */
+ int optimal_display;
+
+ /* The sculpt mask data layer may be null. */
+ int has_sculpt_mask;
+
+ /* Masks for the extra coarse face data. */
+ uint coarse_face_select_mask;
+ uint coarse_face_smooth_mask;
+ uint coarse_face_active_mask;
+ uint coarse_face_loopstart_mask;
+
+ /* Number of elements to process in the compute shader (can be the coarse quad count, or the
+ * final vertex count, depending on which compute pass we do). This is used to early out in case
+ * of out of bond accesses as compute dispatch are of fixed size. */
+ uint total_dispatch_size;
+};
+
+static_assert((sizeof(DRWSubdivUboStorage) % 16) == 0,
+ "DRWSubdivUboStorage is not padded to a multiple of the size of vec4");
+
+static void draw_subdiv_init_ubo_storage(const DRWSubdivCache *cache,
+ DRWSubdivUboStorage *ubo,
+ const int src_offset,
+ const int dst_offset,
+ const uint total_dispatch_size,
+ const bool has_sculpt_mask)
+{
+ ubo->src_offset = src_offset;
+ ubo->dst_offset = dst_offset;
+ ubo->min_patch_face = cache->gpu_patch_map.min_patch_face;
+ ubo->max_patch_face = cache->gpu_patch_map.max_patch_face;
+ ubo->max_depth = cache->gpu_patch_map.max_depth;
+ ubo->patches_are_triangular = cache->gpu_patch_map.patches_are_triangular;
+ ubo->coarse_poly_count = cache->num_coarse_poly;
+ ubo->optimal_display = cache->optimal_display;
+ ubo->num_subdiv_loops = cache->num_subdiv_loops;
+ ubo->edge_loose_offset = cache->num_subdiv_loops * 2;
+ ubo->has_sculpt_mask = has_sculpt_mask;
+ ubo->coarse_face_smooth_mask = SUBDIV_COARSE_FACE_FLAG_SMOOTH_MASK;
+ ubo->coarse_face_select_mask = SUBDIV_COARSE_FACE_FLAG_SELECT_MASK;
+ ubo->coarse_face_active_mask = SUBDIV_COARSE_FACE_FLAG_ACTIVE_MASK;
+ ubo->coarse_face_loopstart_mask = SUBDIV_COARSE_FACE_LOOP_START_MASK;
+ ubo->total_dispatch_size = total_dispatch_size;
+}
+
+static void draw_subdiv_ubo_update_and_bind(const DRWSubdivCache *cache,
+ GPUShader *shader,
+ const int src_offset,
+ const int dst_offset,
+ const uint total_dispatch_size,
+ const bool has_sculpt_mask = false)
+{
+ DRWSubdivUboStorage storage;
+ draw_subdiv_init_ubo_storage(
+ cache, &storage, src_offset, dst_offset, total_dispatch_size, has_sculpt_mask);
+
+ if (!cache->ubo) {
+ const_cast<DRWSubdivCache *>(cache)->ubo = GPU_uniformbuf_create_ex(
+ sizeof(DRWSubdivUboStorage), &storage, "DRWSubdivUboStorage");
+ }
+
+ GPU_uniformbuf_update(cache->ubo, &storage);
+
+ const int location = GPU_shader_get_uniform_block(shader, "shader_data");
+ GPU_uniformbuf_bind(cache->ubo, location);
+}
+
+/** \} */
+
+// --------------------------------------------------------
+
+#define SUBDIV_LOCAL_WORK_GROUP_SIZE 64
+static uint get_dispatch_size(uint elements)
+{
+ return divide_ceil_u(elements, SUBDIV_LOCAL_WORK_GROUP_SIZE);
+}
+
+/* Helper to ensure that the UBO is always initalized before dispatching computes and that the same
+ * number of elements that need to be processed is used for the UBO and the dispatch size.
+ * Use this instead of a raw call to #GPU_compute_dispatch. */
+static void drw_subdiv_compute_dispatch(const DRWSubdivCache *cache,
+ GPUShader *shader,
+ const int src_offset,
+ const int dst_offset,
+ uint total_dispatch_size,
+ const bool has_sculpt_mask = false)
+{
+ const uint max_res_x = static_cast<uint>(GPU_max_work_group_count(0));
+
+ const uint dispatch_size = get_dispatch_size(total_dispatch_size);
+ uint dispatch_rx = dispatch_size;
+ uint dispatch_ry = 1u;
+ if (dispatch_rx > max_res_x) {
+ /* Since there are some limitations with regards to the maximum work group size (could be as
+ * low as 64k elements per call), we split the number elements into a "2d" number, with the
+ * final index being computed as `res_x + res_y * max_work_group_size`. Even with a maximum
+ * work group size of 64k, that still leaves us with roughly `64k * 64k = 4` billion elements
+ * total, which should be enough. If not, we could also use the 3rd dimension. */
+ /* TODO(fclem): We could dispatch fewer groups if we compute the prime factorization and
+ * get the smallest rect fitting the requirements. */
+ dispatch_rx = dispatch_ry = ceilf(sqrtf(dispatch_size));
+ /* Avoid a completely empty dispatch line caused by rounding. */
+ if ((dispatch_rx * (dispatch_ry - 1)) >= dispatch_size) {
+ dispatch_ry -= 1;
+ }
+ }
+
+ /* X and Y dimensions may have different limits so the above computation may not be right, but
+ * even with the standard 64k minimum on all dimensions we still have a lot of room. Therefore,
+ * we presume it all fits. */
+ BLI_assert(dispatch_ry < static_cast<uint>(GPU_max_work_group_count(1)));
+
+ draw_subdiv_ubo_update_and_bind(
+ cache, shader, src_offset, dst_offset, total_dispatch_size, has_sculpt_mask);
+
+ GPU_compute_dispatch(shader, dispatch_rx, dispatch_ry, 1);
+}
+
+void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ const bool do_limit_normals)
+{
+ Subdiv *subdiv = cache->subdiv;
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+
+ OpenSubdiv_Buffer src_buffer_interface;
+ GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface,
+ get_subdiv_vertex_format());
+ evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface);
+
+ OpenSubdiv_Buffer patch_arrays_buffer_interface;
+ GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface,
+ get_patch_array_format());
+ evaluator->fillPatchArraysBuffer(evaluator, &patch_arrays_buffer_interface);
+
+ OpenSubdiv_Buffer patch_index_buffer_interface;
+ GPUVertBuf *patch_index_buffer = create_buffer_and_interface(&patch_index_buffer_interface,
+ get_patch_index_format());
+ evaluator->wrapPatchIndexBuffer(evaluator, &patch_index_buffer_interface);
+
+ OpenSubdiv_Buffer patch_param_buffer_interface;
+ GPUVertBuf *patch_param_buffer = create_buffer_and_interface(&patch_param_buffer_interface,
+ get_patch_param_format());
+ evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface);
+
+ GPUShader *shader = get_patch_evaluation_shader(
+ do_limit_normals ? SHADER_PATCH_EVALUATION_LIMIT_NORMALS : 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);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attrib array. We
+ * also need it for subsequent compute shaders, so a barrier on the shader storage is also
+ * needed. */
+ GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+
+ GPU_vertbuf_discard(patch_index_buffer);
+ GPU_vertbuf_discard(patch_param_buffer);
+ GPU_vertbuf_discard(patch_arrays_buffer);
+ GPU_vertbuf_discard(src_buffer);
+}
+
+void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
+ GPUVertBuf *uvs,
+ const int face_varying_channel,
+ const int dst_offset)
+{
+ Subdiv *subdiv = cache->subdiv;
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+
+ OpenSubdiv_Buffer src_buffer_interface;
+ GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface, get_uvs_format());
+ evaluator->wrapFVarSrcBuffer(evaluator, face_varying_channel, &src_buffer_interface);
+
+ OpenSubdiv_Buffer patch_arrays_buffer_interface;
+ GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface,
+ get_patch_array_format());
+ evaluator->fillFVarPatchArraysBuffer(
+ evaluator, face_varying_channel, &patch_arrays_buffer_interface);
+
+ OpenSubdiv_Buffer patch_index_buffer_interface;
+ GPUVertBuf *patch_index_buffer = create_buffer_and_interface(&patch_index_buffer_interface,
+ get_patch_index_format());
+ evaluator->wrapFVarPatchIndexBuffer(
+ evaluator, face_varying_channel, &patch_index_buffer_interface);
+
+ OpenSubdiv_Buffer patch_param_buffer_interface;
+ GPUVertBuf *patch_param_buffer = create_buffer_and_interface(&patch_param_buffer_interface,
+ get_patch_param_format());
+ evaluator->wrapFVarPatchParamBuffer(
+ evaluator, face_varying_channel, &patch_param_buffer_interface);
+
+ 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);
+
+ /* The buffer offset has the stride baked in (which is 2 as we have UVs) so remove the stride by
+ * dividing by 2 */
+ const int src_offset = src_buffer_interface.buffer_offset / 2;
+ drw_subdiv_compute_dispatch(cache, shader, src_offset, dst_offset, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array.
+ * Since it may also be used for computing UV stretches, we also need a barrier on the shader
+ * storage. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY | GPU_BARRIER_SHADER_STORAGE);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+
+ GPU_vertbuf_discard(patch_index_buffer);
+ GPU_vertbuf_discard(patch_param_buffer);
+ GPU_vertbuf_discard(patch_arrays_buffer);
+ GPU_vertbuf_discard(src_buffer);
+}
+
+void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
+ GPUVertBuf *src_data,
+ GPUVertBuf *dst_data,
+ int dimensions,
+ int dst_offset)
+{
+ GPUShader *shader = nullptr;
+
+ if (dimensions == 1) {
+ shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_1D,
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define DIMENSIONS 1\n");
+ }
+ else if (dimensions == 2) {
+ shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_2D,
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define DIMENSIONS 2\n");
+ }
+ else if (dimensions == 3) {
+ shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_3D,
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define DIMENSIONS 3\n");
+ }
+ else if (dimensions == 4) {
+ shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_4D,
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define DIMENSIONS 4\n"
+ "#define GPU_FETCH_U16_TO_FLOAT\n");
+ }
+ else {
+ /* Crash if dimensions are not supported. */
+ }
+
+ GPU_shader_bind(shader);
+
+ /* 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);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, dst_offset, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_sculpt_data_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *mask_vbo,
+ GPUVertBuf *face_set_vbo,
+ GPUVertBuf *sculpt_data)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_SCULPT_DATA, nullptr);
+ GPU_shader_bind(shader);
+
+ 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);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads, mask_vbo != nullptr);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_accumulate_normals(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *face_adjacency_offsets,
+ GPUVertBuf *face_adjacency_lists,
+ GPUVertBuf *vertex_normals)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_NORMALS_ACCUMULATE, nullptr);
+ GPU_shader_bind(shader);
+
+ int binding_point = 0;
+
+ GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(face_adjacency_offsets, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(face_adjacency_lists, binding_point++);
+ GPU_vertbuf_bind_as_ssbo(vertex_normals, binding_point++);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_verts);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attrib array. We
+ * also need it for subsequent compute shaders, so a barrier on the shader storage is also
+ * needed. */
+ GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_finalize_normals(const DRWSubdivCache *cache,
+ GPUVertBuf *vertex_normals,
+ GPUVertBuf *subdiv_loop_subdiv_vert_index,
+ GPUVertBuf *pos_nor)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_NORMALS_FINALIZE, nullptr);
+ GPU_shader_bind(shader);
+
+ int binding_point = 0;
+ 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++);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attrib array. We
+ * also need it for subsequent compute shaders, so a barrier on the shader storage is also
+ * needed. */
+ GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache,
+ GPUIndexBuf *subdiv_tris,
+ const int material_count)
+{
+ const bool do_single_material = material_count <= 1;
+
+ const char *defines = "#define SUBDIV_POLYGON_OFFSET\n";
+ if (do_single_material) {
+ defines =
+ "#define SUBDIV_POLYGON_OFFSET\n"
+ "#define SINGLE_MATERIAL\n";
+ }
+
+ GPUShader *shader = get_subdiv_shader(
+ 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);
+ }
+
+ 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. */
+ GPU_memory_barrier(GPU_BARRIER_ELEMENT_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
+ GPUVertBuf *fdots_pos,
+ GPUVertBuf *fdots_nor,
+ GPUIndexBuf *fdots_indices)
+{
+ Subdiv *subdiv = cache->subdiv;
+ OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
+
+ OpenSubdiv_Buffer src_buffer_interface;
+ GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface,
+ get_subdiv_vertex_format());
+ evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface);
+
+ OpenSubdiv_Buffer patch_arrays_buffer_interface;
+ GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface,
+ get_patch_array_format());
+ opensubdiv_gpu_buffer_init(&patch_arrays_buffer_interface, patch_arrays_buffer);
+ evaluator->fillPatchArraysBuffer(evaluator, &patch_arrays_buffer_interface);
+
+ OpenSubdiv_Buffer patch_index_buffer_interface;
+ GPUVertBuf *patch_index_buffer = create_buffer_and_interface(&patch_index_buffer_interface,
+ get_patch_index_format());
+ evaluator->wrapPatchIndexBuffer(evaluator, &patch_index_buffer_interface);
+
+ OpenSubdiv_Buffer patch_param_buffer_interface;
+ GPUVertBuf *patch_param_buffer = create_buffer_and_interface(&patch_param_buffer_interface,
+ get_patch_param_format());
+ evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface);
+
+ 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);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_coarse_poly);
+
+ /* This generates two vertex buffers and an index buffer, so we need to put a barrier on the
+ * vertex attributes and element arrays. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY | GPU_BARRIER_ELEMENT_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+
+ GPU_vertbuf_discard(patch_index_buffer);
+ GPU_vertbuf_discard(patch_param_buffer);
+ GPU_vertbuf_discard(patch_arrays_buffer);
+ GPU_vertbuf_discard(src_buffer);
+}
+
+void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache, GPUIndexBuf *lines_indices)
+{
+ 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);
+
+ 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. */
+ GPU_memory_barrier(GPU_BARRIER_ELEMENT_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache *cache,
+ GPUIndexBuf *lines_indices,
+ uint num_loose_edges)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LINES_LOOSE, "#define LINES_LOOSE\n");
+ GPU_shader_bind(shader);
+
+ GPU_indexbuf_bind_as_ssbo(lines_indices, 1);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, num_loose_edges);
+
+ /* This generates an index buffer, so we need to put a barrier on the element array. */
+ GPU_memory_barrier(GPU_BARRIER_ELEMENT_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *edge_idx,
+ GPUVertBuf *edge_fac)
+{
+ /* No separate shader for the AMD driver case as we assume that the GPU will not change during
+ * the execution of the program. */
+ const char *defines = GPU_crappy_amd_driver() ? "#define GPU_AMD_DRIVER_BYTE_BUG\n" : nullptr;
+ 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);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *lnor)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LNOR, "#define SUBDIV_POLYGON_OFFSET\n");
+ GPU_shader_bind(shader);
+
+ /* 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);
+
+ /* Outputs */
+ GPU_vertbuf_bind_as_ssbo(lnor, 3);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_edituv_stretch_area_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *coarse_data,
+ GPUVertBuf *subdiv_data)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_UV_STRETCH_AREA,
+ "#define SUBDIV_POLYGON_OFFSET\n");
+ GPU_shader_bind(shader);
+
+ /* 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);
+
+ /* Outputs */
+ GPU_vertbuf_bind_as_ssbo(subdiv_data, 2);
+
+ drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache *cache,
+ GPUVertBuf *pos_nor,
+ GPUVertBuf *uvs,
+ int uvs_offset,
+ GPUVertBuf *stretch_angles)
+{
+ GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_UV_STRETCH_ANGLE, nullptr);
+ GPU_shader_bind(shader);
+
+ /* Inputs */
+ GPU_vertbuf_bind_as_ssbo(pos_nor, 0);
+ GPU_vertbuf_bind_as_ssbo(uvs, 1);
+
+ /* Outputs */
+ GPU_vertbuf_bind_as_ssbo(stretch_angles, 2);
+
+ drw_subdiv_compute_dispatch(cache, shader, uvs_offset, 0, cache->num_subdiv_quads);
+
+ /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */
+ GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+}
+
+/* -------------------------------------------------------------------- */
+
+void draw_subdiv_init_mesh_render_data(DRWSubdivCache *cache,
+ MeshRenderData *mr,
+ const ToolSettings *toolsettings)
+{
+ Mesh *mesh = cache->mesh;
+
+ /* Setup required data for loose geometry. */
+ mr->me = mesh;
+ mr->medge = mesh->medge;
+ mr->mvert = mesh->mvert;
+ mr->mpoly = mesh->mpoly;
+ mr->mloop = mesh->mloop;
+ mr->vert_len = mesh->totvert;
+ mr->edge_len = mesh->totedge;
+ mr->poly_len = mesh->totpoly;
+ mr->loop_len = mesh->totloop;
+ mr->extract_type = MR_EXTRACT_MESH;
+
+ /* MeshRenderData is only used for generating edit mode data here. */
+ if (!cache->bm) {
+ return;
+ }
+
+ BMesh *bm = cache->bm;
+ BM_mesh_elem_table_ensure(bm, BM_EDGE | BM_FACE | BM_VERT);
+
+ mr->bm = bm;
+ mr->toolsettings = toolsettings;
+ mr->eed_act = BM_mesh_active_edge_get(bm);
+ mr->efa_act = BM_mesh_active_face_get(bm, false, true);
+ mr->eve_act = BM_mesh_active_vert_get(bm);
+ mr->crease_ofs = CustomData_get_offset(&bm->edata, CD_CREASE);
+ mr->bweight_ofs = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
+#ifdef WITH_FREESTYLE
+ mr->freestyle_edge_ofs = CustomData_get_offset(&bm->edata, CD_FREESTYLE_EDGE);
+ mr->freestyle_face_ofs = CustomData_get_offset(&bm->pdata, CD_FREESTYLE_FACE);
+#endif
+ mr->v_origindex = static_cast<int *>(CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX));
+ mr->e_origindex = static_cast<int *>(CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX));
+ mr->p_origindex = static_cast<int *>(CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX));
+}
+
+/**
+ * For material assignments we want indices for triangles that share a common material to be laid
+ * out contiguously in memory. To achieve this, we sort the indices based on which material the
+ * coarse polygon was assigned. The sort is performed by offsetting the loops indices so that they
+ * are directly assigned to the right sorted indices.
+ *
+ * \code{.unparsed}
+ * Here is a visual representation, considering four quads:
+ * +---------+---------+---------+---------+
+ * | 3 2 | 7 6 | 11 10 | 15 14 |
+ * | | | | |
+ * | 0 1 | 4 5 | 8 9 | 12 13 |
+ * +---------+---------+---------+---------+
+ *
+ * If the first and third quads have the same material, we should have:
+ * +---------+---------+---------+---------+
+ * | 3 2 | 11 10 | 7 6 | 15 14 |
+ * | | | | |
+ * | 0 1 | 8 9 | 4 5 | 12 13 |
+ * +---------+---------+---------+---------+
+ *
+ * So the offsets would be:
+ * +---------+---------+---------+---------+
+ * | 0 0 | 4 4 | -4 -4 | 0 0 |
+ * | | | | |
+ * | 0 0 | 4 4 | -4 -4 | 0 0 |
+ * +---------+---------+---------+---------+
+ * \endcode
+ *
+ * The offsets are computed not based on the loops indices, but on the number of subdivided
+ * polygons for each coarse polygon. We then only store a single offset for each coarse polygon,
+ * since all sub-faces are contiguous, they all share the same offset.
+ */
+static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache,
+ Mesh *mesh_eval,
+ uint mat_len)
+{
+ draw_subdiv_cache_free_material_data(cache);
+
+ const int number_of_quads = cache->num_subdiv_loops / 4;
+
+ if (mat_len == 1) {
+ cache->mat_start = static_cast<int *>(MEM_callocN(sizeof(int), "subdiv mat_end"));
+ cache->mat_end = static_cast<int *>(MEM_callocN(sizeof(int), "subdiv mat_end"));
+ cache->mat_start[0] = 0;
+ cache->mat_end[0] = number_of_quads;
+ return;
+ }
+
+ /* Count number of subdivided polygons for each material. */
+ int *mat_start = static_cast<int *>(MEM_callocN(sizeof(int) * mat_len, "subdiv mat_start"));
+ int *subdiv_polygon_offset = cache->subdiv_polygon_offset;
+
+ // TODO: parallel_reduce?
+ for (int i = 0; i < mesh_eval->totpoly; i++) {
+ const MPoly *mpoly = &mesh_eval->mpoly[i];
+ const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads :
+ subdiv_polygon_offset[i + 1];
+ const int quad_count = next_offset - subdiv_polygon_offset[i];
+ const int mat_index = mpoly->mat_nr;
+ mat_start[mat_index] += quad_count;
+ }
+
+ /* Accumulate offsets. */
+ int ofs = mat_start[0];
+ mat_start[0] = 0;
+ for (uint i = 1; i < mat_len; i++) {
+ int tmp = mat_start[i];
+ mat_start[i] = ofs;
+ ofs += tmp;
+ }
+
+ /* Compute per polygon offsets. */
+ int *mat_end = static_cast<int *>(MEM_dupallocN(mat_start));
+ int *per_polygon_mat_offset = static_cast<int *>(
+ MEM_mallocN(sizeof(int) * mesh_eval->totpoly, "per_polygon_mat_offset"));
+
+ for (int i = 0; i < mesh_eval->totpoly; i++) {
+ const MPoly *mpoly = &mesh_eval->mpoly[i];
+ const int mat_index = mpoly->mat_nr;
+ const int single_material_index = subdiv_polygon_offset[i];
+ const int material_offset = mat_end[mat_index];
+ const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads :
+ subdiv_polygon_offset[i + 1];
+ const int quad_count = next_offset - subdiv_polygon_offset[i];
+ mat_end[mat_index] += quad_count;
+
+ per_polygon_mat_offset[i] = material_offset - single_material_index;
+ }
+
+ cache->polygon_mat_offset = draw_subdiv_build_origindex_buffer(per_polygon_mat_offset,
+ mesh_eval->totpoly);
+ cache->mat_start = mat_start;
+ cache->mat_end = mat_end;
+
+ MEM_freeN(per_polygon_mat_offset);
+}
+
+static bool draw_subdiv_create_requested_buffers(const Scene *scene,
+ Object *ob,
+ Mesh *mesh,
+ struct MeshBatchCache *batch_cache,
+ MeshBufferCache *mbc,
+ const ToolSettings *toolsettings,
+ OpenSubdiv_EvaluatorCache *evaluator_cache)
+{
+ SubsurfModifierData *smd = BKE_object_get_last_subsurf_modifier(ob);
+ BLI_assert(smd);
+
+ const bool is_final_render = DRW_state_is_scene_render();
+
+ SubdivSettings settings;
+ BKE_subsurf_modifier_subdiv_settings_init(&settings, smd, is_final_render);
+
+ if (settings.level == 0) {
+ return false;
+ }
+
+ Mesh *mesh_eval = mesh;
+ BMesh *bm = nullptr;
+ if (mesh->edit_mesh) {
+ mesh_eval = mesh->edit_mesh->mesh_eval_final;
+ bm = mesh->edit_mesh->bm;
+ }
+
+ BKE_subsurf_modifier_ensure_runtime(smd);
+
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &settings, mesh_eval, true);
+ if (!subdiv) {
+ return false;
+ }
+
+ if (!BKE_subdiv_eval_begin_from_mesh(
+ subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) {
+ return false;
+ }
+
+ DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache);
+ if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, scene, smd, is_final_render)) {
+ return false;
+ }
+
+ const bool optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges);
+
+ draw_cache->bm = bm;
+ draw_cache->mesh = mesh_eval;
+ draw_cache->subdiv = subdiv;
+ draw_cache->optimal_display = optimal_display;
+ draw_cache->num_subdiv_triangles = tris_count_from_number_of_loops(draw_cache->num_subdiv_loops);
+ /* We can only evaluate limit normals if the patches are adaptive. */
+ draw_cache->do_limit_normals = settings.is_adaptive;
+
+ if (DRW_ibo_requested(mbc->buff.ibo.tris)) {
+ draw_subdiv_cache_ensure_mat_offsets(draw_cache, mesh_eval, batch_cache->mat_len);
+ }
+
+ draw_subdiv_cache_update_extra_coarse_face_data(draw_cache, mesh_eval);
+
+ mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, toolsettings);
+
+ return true;
+}
+
+static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr;
+
+void DRW_create_subdivision(const Scene *scene,
+ Object *ob,
+ Mesh *mesh,
+ struct MeshBatchCache *batch_cache,
+ MeshBufferCache *mbc,
+ const ToolSettings *toolsettings)
+{
+ if (g_evaluator_cache == nullptr) {
+ g_evaluator_cache = openSubdiv_createEvaluatorCache(OPENSUBDIV_EVALUATOR_GLSL_COMPUTE);
+ }
+
+#undef TIME_SUBDIV
+
+#ifdef TIME_SUBDIV
+ const double begin_time = PIL_check_seconds_timer();
+#endif
+
+ if (!draw_subdiv_create_requested_buffers(
+ scene, ob, mesh, batch_cache, mbc, toolsettings, g_evaluator_cache)) {
+ return;
+ }
+
+#ifdef TIME_SUBDIV
+ const double end_time = PIL_check_seconds_timer();
+ fprintf(stderr, "Time to update subdivision: %f\n", end_time - begin_time);
+ fprintf(stderr, "Maximum FPS: %f\n", 1.0 / (end_time - begin_time));
+#endif
+}
+
+void DRW_subdiv_free()
+{
+ for (int i = 0; i < NUM_SHADERS; ++i) {
+ GPU_shader_free(g_subdiv_shaders[i]);
+ }
+
+ DRW_cache_free_old_subdiv();
+
+ if (g_evaluator_cache) {
+ openSubdiv_deleteEvaluatorCache(g_evaluator_cache);
+ g_evaluator_cache = nullptr;
+ }
+}
+
+static LinkNode *gpu_subdiv_free_queue = nullptr;
+static ThreadMutex gpu_subdiv_queue_mutex = BLI_MUTEX_INITIALIZER;
+
+void DRW_subdiv_cache_free(Subdiv *subdiv)
+{
+ BLI_mutex_lock(&gpu_subdiv_queue_mutex);
+ BLI_linklist_prepend(&gpu_subdiv_free_queue, subdiv);
+ BLI_mutex_unlock(&gpu_subdiv_queue_mutex);
+}
+
+void DRW_cache_free_old_subdiv()
+{
+ if (gpu_subdiv_free_queue == nullptr) {
+ return;
+ }
+
+ BLI_mutex_lock(&gpu_subdiv_queue_mutex);
+
+ while (gpu_subdiv_free_queue != nullptr) {
+ Subdiv *subdiv = static_cast<Subdiv *>(BLI_linklist_pop(&gpu_subdiv_free_queue));
+ /* Set the type to CPU so that we do actually free the cache. */
+ subdiv->evaluator->type = OPENSUBDIV_EVALUATOR_CPU;
+ BKE_subdiv_free(subdiv);
+ }
+
+ BLI_mutex_unlock(&gpu_subdiv_queue_mutex);
+}
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 930fb6eabef..0bf6468f7cc 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -52,6 +52,7 @@
#include "BKE_pointcache.h"
#include "BKE_pointcloud.h"
#include "BKE_screen.h"
+#include "BKE_subdiv_modifier.h"
#include "BKE_volume.h"
#include "DNA_camera_types.h"
@@ -90,6 +91,7 @@
#include "draw_manager_testing.h"
#include "draw_manager_text.h"
#include "draw_shader.h"
+#include "draw_subdivision.h"
#include "draw_texture_pool.h"
/* only for callbacks */
@@ -2975,6 +2977,8 @@ void DRW_engines_register(void)
BKE_volume_batch_cache_dirty_tag_cb = DRW_volume_batch_cache_dirty_tag;
BKE_volume_batch_cache_free_cb = DRW_volume_batch_cache_free;
+
+ BKE_subsurf_modifier_free_gpu_cache_cb = DRW_subdiv_cache_free;
}
}
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index e71a1298812..f1c13bc039a 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -1364,14 +1364,15 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial
if (tex->ima) {
/* Image */
GPUTexture *gputex;
+ ImageUser *iuser = tex->iuser_available ? &tex->iuser : NULL;
if (tex->tiled_mapping_name[0]) {
- gputex = BKE_image_get_gpu_tiles(tex->ima, tex->iuser, NULL);
+ gputex = BKE_image_get_gpu_tiles(tex->ima, iuser, NULL);
drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state);
- gputex = BKE_image_get_gpu_tilemap(tex->ima, tex->iuser, NULL);
+ gputex = BKE_image_get_gpu_tilemap(tex->ima, iuser, NULL);
drw_shgroup_material_texture(grp, gputex, tex->tiled_mapping_name, tex->sampler_state);
}
else {
- gputex = BKE_image_get_gpu_texture(tex->ima, tex->iuser, NULL);
+ gputex = BKE_image_get_gpu_texture(tex->ima, iuser, NULL);
drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state);
}
}
diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h
new file mode 100644
index 00000000000..d36bfe87689
--- /dev/null
+++ b/source/blender/draw/intern/draw_subdivision.h
@@ -0,0 +1,231 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2021, Blender Foundation.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_sys_types.h"
+
+struct BMesh;
+struct GPUIndexBuf;
+struct GPUUniformBuf;
+struct GPUVertBuf;
+struct Mesh;
+struct MeshBatchCache;
+struct MeshBufferCache;
+struct MeshRenderData;
+struct Object;
+struct Scene;
+struct Subdiv;
+struct ToolSettings;
+
+/* -------------------------------------------------------------------- */
+/** \name DRWPatchMap
+ *
+ * This is a GPU version of the OpenSubDiv PatchMap. The quad tree and the patch handles are copied
+ * to GPU buffers in order to lookup the right patch for a given set of patch coordinates.
+ * \{ */
+
+typedef struct DRWPatchMap {
+ struct GPUVertBuf *patch_map_handles;
+ struct GPUVertBuf *patch_map_quadtree;
+ int min_patch_face;
+ int max_patch_face;
+ int max_depth;
+ int patches_are_triangular;
+} DRWPatchMap;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name DRWSubdivCache
+ *
+ * This holds the various buffers used to evaluate and render subdivision through OpenGL.
+ * \{ */
+
+typedef struct DRWSubdivCache {
+ struct Mesh *mesh;
+ struct BMesh *bm;
+ struct Subdiv *subdiv;
+ bool optimal_display;
+ bool do_limit_normals;
+
+ /* Coordinates used to evaluate patches for UVs, positions, and normals. */
+ struct GPUVertBuf *patch_coords;
+ /* Coordinates used to evaluate patches for the face centers (or face dots) in edit-mode. */
+ struct GPUVertBuf *fdots_patch_coords;
+
+ /* Resolution used to generate the patch coordinates. */
+ int resolution;
+
+ /* Number of subdivided loops, also the number of patch coordinates since we have one coordinate
+ * but quad corner/vertex. */
+ uint num_subdiv_loops;
+ uint num_subdiv_edges;
+ uint num_subdiv_triangles;
+ uint num_subdiv_verts;
+ uint num_subdiv_quads;
+
+ /* Number of polygons in the coarse mesh, notably used to compute a coarse polygon index given a
+ * subdivision loop index. */
+ int num_coarse_poly;
+
+ /* Maps subdivision loop to subdivided vertex index. */
+ int *subdiv_loop_subdiv_vert_index;
+ /* Maps subdivision loop to original coarse poly index. */
+ int *subdiv_loop_poly_index;
+
+ /* Indices of faces adjacent to the vertices, ordered by vertex index, with no particular
+ * winding. */
+ struct GPUVertBuf *subdiv_vertex_face_adjacency;
+ /* The difference between value (i + 1) and (i) gives the number of faces adjacent to vertex (i).
+ */
+ struct GPUVertBuf *subdiv_vertex_face_adjacency_offsets;
+
+ /* Maps subdivision loop to original coarse vertex index, only really useful for edit mode. */
+ struct GPUVertBuf *verts_orig_index;
+ /* Maps subdivision loop to original coarse edge index, only really useful for edit mode. */
+ struct GPUVertBuf *edges_orig_index;
+
+ /* Owned by #Subdiv. Indexed by coarse polygon index, difference between value (i + 1) and (i)
+ * gives the number of ptex faces for coarse polygon (i). */
+ int *face_ptex_offset;
+ /* Vertex buffer for face_ptex_offset. */
+ struct GPUVertBuf *face_ptex_offset_buffer;
+
+ int *subdiv_polygon_offset;
+ struct GPUVertBuf *subdiv_polygon_offset_buffer;
+
+ /* Contains the start loop index and the smooth flag for each coarse polygon. */
+ struct GPUVertBuf *extra_coarse_face_data;
+
+ /* Computed for ibo.points, one value per subdivided vertex, mapping coarse vertices ->
+ * subdivided loop */
+ int *point_indices;
+
+ /* Material offsets. */
+ int *mat_start;
+ int *mat_end;
+ struct GPUVertBuf *polygon_mat_offset;
+
+ DRWPatchMap gpu_patch_map;
+
+ /* UBO to store settings for the various compute shaders. */
+ struct GPUUniformBuf *ubo;
+} DRWSubdivCache;
+
+/* Only frees the data of the cache, caller is responsible to free the cache itself if necessary.
+ */
+void draw_subdiv_cache_free(DRWSubdivCache *cache);
+
+/** \} */
+
+void DRW_create_subdivision(const struct Scene *scene,
+ struct Object *ob,
+ struct Mesh *mesh,
+ struct MeshBatchCache *batch_cache,
+ struct MeshBufferCache *mbc,
+ const struct ToolSettings *toolsettings);
+
+void DRW_subdiv_cache_free(struct Subdiv *subdiv);
+
+void draw_subdiv_init_mesh_render_data(DRWSubdivCache *cache,
+ struct MeshRenderData *mr,
+ const struct ToolSettings *toolsettings);
+
+void draw_subdiv_init_origindex_buffer(struct GPUVertBuf *buffer,
+ int *vert_origindex,
+ uint num_loops,
+ uint loose_len);
+
+struct GPUVertBuf *draw_subdiv_build_origindex_buffer(int *vert_origindex, uint num_loops);
+
+/* Compute shader functions. */
+
+void draw_subdiv_build_sculpt_data_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *mask_vbo,
+ struct GPUVertBuf *face_set_vbo,
+ struct GPUVertBuf *sculpt_data);
+
+void draw_subdiv_accumulate_normals(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *face_adjacency_offsets,
+ struct GPUVertBuf *face_adjacency_lists,
+ struct GPUVertBuf *vertex_normals);
+
+void draw_subdiv_finalize_normals(const DRWSubdivCache *cache,
+ struct GPUVertBuf *vertex_normals,
+ struct GPUVertBuf *subdiv_loop_subdiv_vert_index,
+ struct GPUVertBuf *pos_nor);
+
+void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ const bool do_limit_normals);
+
+void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache,
+ struct GPUVertBuf *src_data,
+ struct GPUVertBuf *dst_data,
+ int dimensions,
+ int dst_offset);
+
+void draw_subdiv_extract_uvs(const DRWSubdivCache *cache,
+ struct GPUVertBuf *uvs,
+ const int face_varying_channel,
+ const int dst_offset);
+
+void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *edge_idx,
+ struct GPUVertBuf *edge_fac);
+
+void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache,
+ struct GPUIndexBuf *subdiv_tris,
+ const int material_count);
+
+void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache,
+ struct GPUIndexBuf *lines_indices);
+
+void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache *cache,
+ struct GPUIndexBuf *lines_indices,
+ uint num_loose_edges);
+
+void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache,
+ struct GPUVertBuf *fdots_pos,
+ struct GPUVertBuf *fdots_nor,
+ struct GPUIndexBuf *fdots_indices);
+
+void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *lnor);
+
+void draw_subdiv_build_edituv_stretch_area_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *coarse_data,
+ struct GPUVertBuf *subdiv_data);
+
+void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache *cache,
+ struct GPUVertBuf *pos_nor,
+ struct GPUVertBuf *uvs,
+ int uvs_offset,
+ struct GPUVertBuf *stretch_angles);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
index 7d21804c08f..35cc2cf986e 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
@@ -39,6 +39,8 @@
extern "C" {
#endif
+struct DRWSubdivCache;
+
#define MIN_RANGE_LEN 1024
/* ---------------------------------------------------------------------- */
@@ -203,6 +205,11 @@ typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
const MVert *mv,
const int lvert_index,
void *data);
+typedef void(ExtractLooseGeomSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *data);
typedef void(ExtractInitFn)(const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buffer,
@@ -213,6 +220,18 @@ typedef void(ExtractFinishFn)(const MeshRenderData *mr,
void *data);
typedef void(ExtractTaskReduceFn)(void *userdata, void *task_userdata);
+typedef void(ExtractInitSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *data);
+typedef void(ExtractIterSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *data);
+typedef void(ExtractFinishSubdivFn)(const struct DRWSubdivCache *subdiv_cache,
+ void *buf,
+ void *data);
+
typedef struct MeshExtract {
/** Executed on main thread and return user data for iteration functions. */
ExtractInitFn *init;
@@ -225,9 +244,14 @@ typedef struct MeshExtract {
ExtractLEdgeMeshFn *iter_ledge_mesh;
ExtractLVertBMeshFn *iter_lvert_bm;
ExtractLVertMeshFn *iter_lvert_mesh;
+ ExtractLooseGeomSubdivFn *iter_loose_geom_subdiv;
/** Executed on one worker thread after all elements iterations. */
ExtractTaskReduceFn *task_reduce;
ExtractFinishFn *finish;
+ /** Executed on main thread for subdivision evaluation. */
+ ExtractInitSubdivFn *init_subdiv;
+ ExtractIterSubdivFn *iter_subdiv;
+ ExtractFinishSubdivFn *finish_subdiv;
/** Used to request common data. */
eMRDataType data_type;
size_t data_size;
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 4cc9a875f79..6a1691e8634 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
@@ -27,6 +27,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Edit UV Triangles Indices
@@ -94,6 +96,57 @@ static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(&data->elb, ibo);
}
+static void extract_edituv_tris_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *tls_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
+ GPU_indexbuf_init(&data->elb,
+ GPU_PRIM_TRIS,
+ subdiv_cache->num_subdiv_triangles,
+ subdiv_cache->num_subdiv_loops);
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+}
+
+static void extract_edituv_tris_iter_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index;
+
+ for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) {
+ const uint loop_idx = i * 4;
+ const int poly_origindex = subdiv_loop_poly_index[loop_idx];
+ BMFace *efa = bm_original_face_get(mr, poly_origindex);
+
+ edituv_tri_add(data,
+ BM_elem_flag_test(efa, BM_ELEM_HIDDEN) != 0,
+ BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0,
+ loop_idx,
+ loop_idx + 1,
+ loop_idx + 2);
+
+ edituv_tri_add(data,
+ BM_elem_flag_test(efa, BM_ELEM_HIDDEN) != 0,
+ BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0,
+ loop_idx,
+ loop_idx + 2,
+ loop_idx + 3);
+ }
+}
+
+static void extract_edituv_tris_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
+ void *buf,
+ void *_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+}
+
constexpr MeshExtract create_extractor_edituv_tris()
{
MeshExtract extractor = {nullptr};
@@ -101,6 +154,9 @@ constexpr MeshExtract create_extractor_edituv_tris()
extractor.iter_looptri_bm = extract_edituv_tris_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh;
extractor.finish = extract_edituv_tris_finish;
+ extractor.init_subdiv = extract_edituv_tris_init_subdiv;
+ extractor.iter_subdiv = extract_edituv_tris_iter_subdiv;
+ extractor.finish_subdiv = extract_edituv_tris_finish_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
@@ -184,6 +240,56 @@ static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(&data->elb, ibo);
}
+static void extract_edituv_lines_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *tls_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
+ GPU_indexbuf_init(
+ &data->elb, GPU_PRIM_LINES, subdiv_cache->num_subdiv_loops, subdiv_cache->num_subdiv_loops);
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+}
+
+static void extract_edituv_lines_iter_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index;
+ int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index);
+
+ for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) {
+
+ uint start_loop_idx = i * 4;
+ uint end_loop_idx = (i + 1) * 4;
+
+ const int poly_origindex = subdiv_loop_poly_index[start_loop_idx];
+ BMFace *efa = bm_original_face_get(mr, poly_origindex);
+
+ for (uint loop_idx = start_loop_idx; loop_idx < end_loop_idx; loop_idx++) {
+ const int edge_origindex = subdiv_loop_edge_index[loop_idx];
+ const bool real_edge = (edge_origindex != -1 &&
+ mr->e_origindex[edge_origindex] != ORIGINDEX_NONE);
+ edituv_edge_add(data,
+ BM_elem_flag_test_bool(efa, BM_ELEM_HIDDEN) != 0 || !real_edge,
+ BM_elem_flag_test_bool(efa, BM_ELEM_SELECT) != 0,
+ loop_idx,
+ (loop_idx + 1 == end_loop_idx) ? start_loop_idx : (loop_idx + 1));
+ }
+ }
+}
+
+static void extract_edituv_lines_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
+ void *buf,
+ void *_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+}
+
constexpr MeshExtract create_extractor_edituv_lines()
{
MeshExtract extractor = {nullptr};
@@ -191,6 +297,9 @@ constexpr MeshExtract create_extractor_edituv_lines()
extractor.iter_poly_bm = extract_edituv_lines_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_lines_iter_poly_mesh;
extractor.finish = extract_edituv_lines_finish;
+ extractor.init_subdiv = extract_edituv_lines_init_subdiv;
+ extractor.iter_subdiv = extract_edituv_lines_iter_subdiv;
+ extractor.finish_subdiv = extract_edituv_lines_finish_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
@@ -268,6 +377,50 @@ static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(&data->elb, ibo);
}
+static void extract_edituv_points_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *tls_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
+ GPU_indexbuf_init(
+ &data->elb, GPU_PRIM_POINTS, subdiv_cache->num_subdiv_loops, subdiv_cache->num_subdiv_loops);
+ data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
+}
+
+static void extract_edituv_points_iter_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index);
+ int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index;
+
+ for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) {
+ const int vert_origindex = subdiv_loop_vert_index[i];
+ const int poly_origindex = subdiv_loop_poly_index[i];
+ BMFace *efa = bm_original_face_get(mr, poly_origindex);
+
+ 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(efa, BM_ELEM_HIDDEN)) || !real_vert,
+ BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0,
+ i);
+ }
+}
+
+static void extract_edituv_points_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache),
+ void *buf,
+ void *_data)
+{
+ MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+}
+
constexpr MeshExtract create_extractor_edituv_points()
{
MeshExtract extractor = {nullptr};
@@ -275,6 +428,9 @@ constexpr MeshExtract create_extractor_edituv_points()
extractor.iter_poly_bm = extract_edituv_points_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_points_iter_poly_mesh;
extractor.finish = extract_edituv_points_finish;
+ extractor.init_subdiv = extract_edituv_points_init_subdiv;
+ extractor.iter_subdiv = extract_edituv_points_iter_subdiv;
+ extractor.finish_subdiv = extract_edituv_points_finish_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
index 54f5611106f..3d9729dea56 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc
@@ -25,6 +25,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -155,6 +157,33 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(elb, ibo);
}
+static void extract_lines_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
+ GPU_indexbuf_init_build_on_device(ibo,
+ subdiv_cache->num_subdiv_loops * 2 + mr->edge_loose_len * 2);
+
+ draw_subdiv_build_lines_buffer(subdiv_cache, ibo);
+}
+
+static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ if (loose_geom->edge_len == 0) {
+ return;
+ }
+
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
+ draw_subdiv_build_lines_loose_buffer(subdiv_cache, ibo, static_cast<uint>(loose_geom->edge_len));
+}
+
constexpr MeshExtract create_extractor_lines()
{
MeshExtract extractor = {nullptr};
@@ -163,6 +192,8 @@ constexpr MeshExtract create_extractor_lines()
extractor.iter_poly_mesh = extract_lines_iter_poly_mesh;
extractor.iter_ledge_bm = extract_lines_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_lines_iter_ledge_mesh;
+ extractor.init_subdiv = extract_lines_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_lines_loose_geom_subdiv;
extractor.task_reduce = extract_lines_task_reduce;
extractor.finish = extract_lines_finish;
extractor.data_type = MR_DATA_NONE;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
index e7dabfa9ee2..6855feb51ed 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc
@@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -44,6 +45,18 @@ struct MeshExtract_LineAdjacency_Data {
uint *vert_to_loop;
};
+static void line_adjacency_data_init(MeshExtract_LineAdjacency_Data *data,
+ uint vert_len,
+ uint loop_len,
+ uint tess_edge_len)
+{
+ data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * vert_len, __func__));
+
+ GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, loop_len);
+ data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len);
+ data->is_manifold = true;
+}
+
static void extract_lines_adjacency_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
@@ -55,11 +68,7 @@ static void extract_lines_adjacency_init(const MeshRenderData *mr,
uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len;
MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(tls_data);
- data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * mr->vert_len, __func__));
-
- GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, mr->loop_len);
- data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len);
- data->is_manifold = true;
+ line_adjacency_data_init(data, mr->vert_len, mr->loop_len, tess_edge_len);
}
BLI_INLINE void lines_adjacency_triangle(
@@ -171,6 +180,56 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
MEM_freeN(data->vert_to_loop);
}
+static void extract_lines_adjacency_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buf),
+ void *_data)
+{
+ MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data);
+
+ /* For each polygon there is (loop + triangle - 1) edges. Since we only have quads, and a quad
+ * is split into 2 triangles, we have (loop + 2 - 1) = (loop + 1) edges for each quad, or in
+ * total: (number_of_loops + number_of_quads). */
+ const uint tess_len = subdiv_cache->num_subdiv_loops + subdiv_cache->num_subdiv_quads;
+ line_adjacency_data_init(
+ data, tess_len, subdiv_cache->num_subdiv_verts, subdiv_cache->num_subdiv_loops);
+}
+
+static void extract_lines_adjacency_iter_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ void *_data)
+{
+ MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data);
+
+ for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) {
+ const uint loop_index = i * 4;
+ const uint l0 = loop_index + 0;
+ const uint l1 = loop_index + 1;
+ const uint l2 = loop_index + 2;
+ const uint l3 = loop_index + 3;
+
+ const uint v0 = subdiv_cache->subdiv_loop_subdiv_vert_index[l0];
+ const uint v1 = subdiv_cache->subdiv_loop_subdiv_vert_index[l1];
+ const uint v2 = subdiv_cache->subdiv_loop_subdiv_vert_index[l2];
+ const uint v3 = subdiv_cache->subdiv_loop_subdiv_vert_index[l3];
+
+ lines_adjacency_triangle(v0, v1, v2, l0, l1, l2, data);
+ lines_adjacency_triangle(v0, v2, v3, l0, l2, l3, data);
+ }
+}
+
+static void extract_lines_adjacency_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache),
+ void *buf,
+ void *_data)
+{
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
+ MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data);
+ GPU_indexbuf_build_in_place(&data->elb, ibo);
+ BLI_edgehash_free(data->eh, nullptr);
+ MEM_freeN(data->vert_to_loop);
+}
+
#undef NO_EDGE
constexpr MeshExtract create_extractor_lines_adjacency()
@@ -180,6 +239,9 @@ constexpr MeshExtract create_extractor_lines_adjacency()
extractor.iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh;
extractor.finish = extract_lines_adjacency_finish;
+ extractor.init_subdiv = extract_lines_adjacency_init_subdiv;
+ extractor.iter_subdiv = extract_lines_adjacency_iter_subdiv;
+ extractor.finish_subdiv = extract_lines_adjacency_finish_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_LineAdjacency_Data);
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
index 01e14a004ed..19167772a42 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc
@@ -25,6 +25,7 @@
#include "MEM_guardedalloc.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -155,6 +156,74 @@ static void extract_points_finish(const MeshRenderData *UNUSED(mr),
GPU_indexbuf_build_in_place(elb, ibo);
}
+static void extract_points_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *UNUSED(cache),
+ void *UNUSED(buffer),
+ void *data)
+{
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data);
+ /* Copy the points as the data upload will free them. */
+ elb->data = (uint *)MEM_dupallocN(subdiv_cache->point_indices);
+ elb->index_len = subdiv_cache->num_subdiv_verts;
+ elb->index_min = 0;
+ elb->index_max = subdiv_cache->num_subdiv_loops - 1;
+ elb->prim_type = GPU_PRIM_POINTS;
+}
+
+static void extract_points_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *UNUSED(buffer),
+ void *data)
+{
+ const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
+ if (loop_loose_len == 0) {
+ return;
+ }
+
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data);
+
+ elb->data = static_cast<uint32_t *>(
+ MEM_reallocN(elb->data, sizeof(uint) * (subdiv_cache->num_subdiv_loops + loop_loose_len)));
+
+ const Mesh *coarse_mesh = subdiv_cache->mesh;
+ const MEdge *coarse_edges = coarse_mesh->medge;
+
+ uint offset = subdiv_cache->num_subdiv_loops;
+
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
+ if (elb->data[loose_edge->v1] == -1u) {
+ elb->data[loose_edge->v1] = offset;
+ }
+ if (elb->data[loose_edge->v2] == -1u) {
+ elb->data[loose_edge->v2] = offset + 1;
+ }
+ elb->index_max += 2;
+ elb->index_len += 2;
+ offset += 2;
+ }
+
+ for (int i = 0; i < loose_geom->vert_len; i++) {
+ if (elb->data[loose_geom->verts[i]] == -1u) {
+ elb->data[loose_geom->verts[i]] = offset;
+ }
+ elb->index_max += 1;
+ elb->index_len += 1;
+ offset += 1;
+ }
+}
+
+static void extract_points_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache),
+ void *buf,
+ void *_userdata)
+{
+ GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
+ GPU_indexbuf_build_in_place(elb, ibo);
+}
+
constexpr MeshExtract create_extractor_points()
{
MeshExtract extractor = {nullptr};
@@ -167,6 +236,9 @@ constexpr MeshExtract create_extractor_points()
extractor.iter_lvert_mesh = extract_points_iter_lvert_mesh;
extractor.task_reduce = extract_points_task_reduce;
extractor.finish = extract_points_finish;
+ extractor.init_subdiv = extract_points_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_points_loose_geom_subdiv;
+ extractor.finish_subdiv = extract_points_finish_subdiv;
extractor.use_threading = true;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(GPUIndexBufBuilder);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
index 54e733d3d86..b1ace8bc6c9 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc
@@ -25,6 +25,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
static void extract_tris_mat_task_reduce(void *_userdata_to, void *_userdata_from)
@@ -123,10 +125,37 @@ static void extract_tris_finish(const MeshRenderData *mr,
}
}
+static void extract_tris_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer);
+ /* Initialize the index buffer, it was already allocated, it will be filled on the device. */
+ GPU_indexbuf_init_build_on_device(ibo, subdiv_cache->num_subdiv_triangles * 3);
+
+ if (cache->tris_per_mat) {
+ for (int i = 0; i < cache->mat_len; i++) {
+ if (cache->tris_per_mat[i] == nullptr) {
+ cache->tris_per_mat[i] = GPU_indexbuf_calloc();
+ }
+
+ /* Multiply by 6 since we have 2 triangles per quad. */
+ const int start = subdiv_cache->mat_start[i] * 6;
+ const int len = (subdiv_cache->mat_end[i] - subdiv_cache->mat_start[i]) * 6;
+ GPU_indexbuf_create_subrange_in_place(cache->tris_per_mat[i], ibo, start, len);
+ }
+ }
+
+ draw_subdiv_build_tris_buffer(subdiv_cache, ibo, cache->mat_len);
+}
+
constexpr MeshExtract create_extractor_tris()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_tris_init;
+ extractor.init_subdiv = extract_tris_init_subdiv;
extractor.iter_poly_bm = extract_tris_iter_poly_bm;
extractor.iter_poly_mesh = extract_tris_iter_poly_mesh;
extractor.task_reduce = extract_tris_mat_task_reduce;
@@ -214,6 +243,7 @@ constexpr MeshExtract create_extractor_tris_single_mat()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_tris_single_mat_init;
+ extractor.init_subdiv = extract_tris_init_subdiv;
extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_tris_single_mat_iter_looptri_mesh;
extractor.task_reduce = extract_tris_mat_task_reduce;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
index 8a5a8134ca7..ea702e5efdd 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc
@@ -32,6 +32,7 @@
#include "BKE_attribute.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -153,7 +154,9 @@ static GPUVertCompType get_comp_type_for_type(CustomDataType type)
static void init_vbo_for_attribute(const MeshRenderData *mr,
GPUVertBuf *vbo,
- const DRW_AttributeRequest &request)
+ const DRW_AttributeRequest &request,
+ bool build_on_device,
+ uint32_t len)
{
GPUVertCompType comp_type = get_comp_type_for_type(request.cd_type);
GPUVertFetchMode fetch_mode = get_fetch_mode_for_type(request.cd_type);
@@ -184,8 +187,13 @@ static void init_vbo_for_attribute(const MeshRenderData *mr,
}
}
- GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, static_cast<uint32_t>(mr->loop_len));
+ if (build_on_device) {
+ GPU_vertbuf_init_build_on_device(vbo, &format, len);
+ }
+ else {
+ GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_data_alloc(vbo, len);
+ }
}
template<typename AttributeType, typename VBOType>
@@ -309,7 +317,7 @@ static void extract_attr_init(const MeshRenderData *mr,
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
- init_vbo_for_attribute(mr, vbo, request);
+ init_vbo_for_attribute(mr, vbo, request, false, static_cast<uint32_t>(mr->loop_len));
/* TODO(kevindietrich) : float3 is used for scalar attributes as the implicit conversion done by
* OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following the
@@ -346,6 +354,68 @@ static void extract_attr_init(const MeshRenderData *mr,
}
}
+static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(tls_data),
+ int index)
+{
+ const DRW_MeshAttributes *attrs_used = &cache->attr_used;
+ const DRW_AttributeRequest &request = attrs_used->requests[index];
+
+ Mesh *coarse_mesh = subdiv_cache->mesh;
+
+ const uint32_t dimensions = gpu_component_size_for_attribute_type(request.cd_type);
+
+ /* Prepare VBO for coarse data. The compute shader only expects floats. */
+ GPUVertBuf *src_data = GPU_vertbuf_calloc();
+ static GPUVertFormat coarse_format = {0};
+ GPU_vertformat_attr_add(&coarse_format, "data", GPU_COMP_F32, dimensions, GPU_FETCH_FLOAT);
+ GPU_vertbuf_init_with_format_ex(src_data, &coarse_format, GPU_USAGE_STATIC);
+ GPU_vertbuf_data_alloc(src_data, static_cast<uint32_t>(coarse_mesh->totloop));
+
+ switch (request.cd_type) {
+ case CD_PROP_BOOL: {
+ extract_attr_generic<bool, float3>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_INT32: {
+ extract_attr_generic<int32_t, float3>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_FLOAT: {
+ extract_attr_generic<float, float3>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_FLOAT2: {
+ extract_attr_generic<float2>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_FLOAT3: {
+ extract_attr_generic<float3>(mr, src_data, request);
+ break;
+ }
+ case CD_PROP_COLOR: {
+ extract_attr_generic<MPropCol, gpuMeshCol>(mr, src_data, request);
+ break;
+ }
+ default: {
+ BLI_assert(false);
+ }
+ }
+
+ GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
+ init_vbo_for_attribute(mr, dst_buffer, request, true, subdiv_cache->num_subdiv_loops);
+
+ /* Ensure data is uploaded properly. */
+ GPU_vertbuf_tag_dirty(src_data);
+ draw_subdiv_interp_custom_data(
+ subdiv_cache, src_data, dst_buffer, static_cast<int>(dimensions), 0);
+
+ GPU_vertbuf_discard(src_data);
+}
+
/* Wrappers around extract_attr_init so we can pass the index of the attribute that we want to
* extract. The overall API does not allow us to pass this in a convenient way. */
#define EXTRACT_INIT_WRAPPER(index) \
@@ -353,6 +423,14 @@ static void extract_attr_init(const MeshRenderData *mr,
const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf, void *tls_data) \
{ \
extract_attr_init(mr, cache, buf, tls_data, index); \
+ } \
+ static void extract_attr_init_subdiv##index(const DRWSubdivCache *subdiv_cache, \
+ const MeshRenderData *mr, \
+ struct MeshBatchCache *cache, \
+ void *buf, \
+ void *tls_data) \
+ { \
+ extract_attr_init_subdiv(subdiv_cache, mr, cache, buf, tls_data, index); \
}
EXTRACT_INIT_WRAPPER(0)
@@ -371,10 +449,12 @@ EXTRACT_INIT_WRAPPER(12)
EXTRACT_INIT_WRAPPER(13)
EXTRACT_INIT_WRAPPER(14)
-template<int index> constexpr MeshExtract create_extractor_attr(ExtractInitFn fn)
+template<int index>
+constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivFn subdiv_fn)
{
MeshExtract extractor = {nullptr};
extractor.init = fn;
+ extractor.init_subdiv = subdiv_fn;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
@@ -388,7 +468,8 @@ template<int index> constexpr MeshExtract create_extractor_attr(ExtractInitFn fn
extern "C" {
#define CREATE_EXTRACTOR_ATTR(index) \
- blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index)
+ blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index, \
+ blender::draw::extract_attr_init_subdiv##index)
const MeshExtract extract_attr[GPU_MAX_ATTR] = {
CREATE_EXTRACTOR_ATTR(0),
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
index 2e2444a8e3d..5ee34d7fdb2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
@@ -25,6 +25,7 @@
#include "GPU_capabilities.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -216,6 +217,86 @@ static void extract_edge_fac_finish(const MeshRenderData *mr,
MEM_SAFE_FREE(data->edge_loop_count);
}
+/* Different function than the one used for the non-subdivision case, as we directly take care of
+ * the buggy AMD driver case. */
+static GPUVertFormat *get_subdiv_edge_fac_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ if (GPU_crappy_amd_driver()) {
+ GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+ else {
+ GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ }
+ }
+ return &format;
+}
+
+static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *edge_idx = cache->final.buff.vbo.edge_idx;
+ GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ GPU_vertbuf_init_build_on_device(
+ vbo, get_subdiv_edge_fac_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
+
+ /* Create a temporary buffer for the edge original indices if it was not requested. */
+ const bool has_edge_idx = edge_idx != nullptr;
+ GPUVertBuf *loop_edge_idx = nullptr;
+ if (has_edge_idx) {
+ loop_edge_idx = edge_idx;
+ }
+ else {
+ loop_edge_idx = GPU_vertbuf_calloc();
+ draw_subdiv_init_origindex_buffer(
+ loop_edge_idx,
+ static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)),
+ subdiv_cache->num_subdiv_loops,
+ 0);
+ }
+
+ draw_subdiv_build_edge_fac_buffer(subdiv_cache, pos_nor, loop_edge_idx, vbo);
+
+ if (!has_edge_idx) {
+ GPU_vertbuf_discard(loop_edge_idx);
+ }
+}
+
+static void extract_edge_fac_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ if (loose_geom->edge_len == 0) {
+ return;
+ }
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+
+ /* Make sure buffer is active for sending loose data. */
+ GPU_vertbuf_use(vbo);
+
+ uint offset = subdiv_cache->num_subdiv_loops;
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ if (GPU_crappy_amd_driver()) {
+ float loose_edge_fac[2] = {1.0f, 1.0f};
+ GPU_vertbuf_update_sub(vbo, offset * sizeof(float), sizeof(loose_edge_fac), loose_edge_fac);
+ }
+ else {
+ char loose_edge_fac[2] = {255, 255};
+ GPU_vertbuf_update_sub(vbo, offset * sizeof(char), sizeof(loose_edge_fac), loose_edge_fac);
+ }
+
+ offset += 2;
+ }
+}
+
constexpr MeshExtract create_extractor_edge_fac()
{
MeshExtract extractor = {nullptr};
@@ -224,6 +305,8 @@ constexpr MeshExtract create_extractor_edge_fac()
extractor.iter_poly_mesh = extract_edge_fac_iter_poly_mesh;
extractor.iter_ledge_bm = extract_edge_fac_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh;
+ extractor.init_subdiv = extract_edge_fac_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_edge_fac_loose_geom_subdiv;
extractor.finish = extract_edge_fac_finish;
extractor.data_type = MR_DATA_POLY_NOR;
extractor.data_size = sizeof(MeshExtract_EdgeFac_Data);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
index 5232346e51e..0b4172dfb28 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc
@@ -25,6 +25,8 @@
#include "draw_cache_impl.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -107,19 +109,25 @@ static void mesh_render_data_vert_flag(const MeshRenderData *mr,
}
}
-static void extract_edit_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf,
- void *tls_data)
+static GPUVertFormat *get_edit_data_format()
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* WARNING: Adjust #EditLoopData struct accordingly. */
GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT);
GPU_vertformat_alias_add(&format, "flag");
}
- GPU_vertbuf_init_with_format(vbo, &format);
+ return &format;
+}
+
+static void extract_edit_data_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPUVertFormat *format = get_edit_data_format();
+ GPU_vertbuf_init_with_format(vbo, format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len);
EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
*(EditLoopData **)tls_data = vbo_data;
@@ -240,6 +248,80 @@ static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr,
}
}
+static void extract_edit_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPU_vertbuf_init_with_format(vbo, get_edit_data_format());
+ GPU_vertbuf_data_alloc(vbo, subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
+ EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
+ *(EditLoopData **)data = vbo_data;
+}
+
+static void extract_edit_data_iter_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data)
+{
+ EditLoopData *vbo_data = *(EditLoopData **)_data;
+ int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index);
+ int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index);
+ int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index;
+
+ for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) {
+ const int vert_origindex = subdiv_loop_vert_index[i];
+ const int edge_origindex = subdiv_loop_edge_index[i];
+ const int poly_origindex = subdiv_loop_poly_index[i];
+
+ EditLoopData *edit_loop_data = &vbo_data[i];
+ memset(edit_loop_data, 0, sizeof(EditLoopData));
+
+ if (vert_origindex != -1) {
+ const BMVert *eve = bm_original_vert_get(mr, vert_origindex);
+ if (eve) {
+ mesh_render_data_vert_flag(mr, eve, edit_loop_data);
+ }
+ }
+
+ if (edge_origindex != -1) {
+ const BMEdge *eed = bm_original_edge_get(mr, edge_origindex);
+ if (eed) {
+ mesh_render_data_edge_flag(mr, eed, edit_loop_data);
+ }
+ }
+
+ BMFace *efa = bm_original_face_get(mr, poly_origindex);
+ /* The -1 parameter is for edit_uvs, which we don't do here. */
+ mesh_render_data_face_flag(mr, efa, -1, edit_loop_data);
+ }
+}
+
+static void extract_edit_data_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ const MeshExtractLooseGeom *loose_geom,
+ void *UNUSED(buffer),
+ void *_data)
+{
+ if (loose_geom->edge_len == 0) {
+ return;
+ }
+
+ EditLoopData *vbo_data = *(EditLoopData **)_data;
+
+ for (int ledge_index = 0; ledge_index < loose_geom->edge_len; ledge_index++) {
+ const int offset = subdiv_cache->num_subdiv_loops + ledge_index * 2;
+ EditLoopData *data = &vbo_data[offset];
+ memset(data, 0, sizeof(EditLoopData));
+ BMEdge *eed = bm_original_edge_get(mr, loose_geom->edges[ledge_index]);
+ mesh_render_data_edge_flag(mr, eed, &data[0]);
+ data[1] = data[0];
+ mesh_render_data_vert_flag(mr, eed->v1, &data[0]);
+ mesh_render_data_vert_flag(mr, eed->v2, &data[1]);
+ }
+}
+
constexpr MeshExtract create_extractor_edit_data()
{
MeshExtract extractor = {nullptr};
@@ -250,6 +332,9 @@ constexpr MeshExtract create_extractor_edit_data()
extractor.iter_ledge_mesh = extract_edit_data_iter_ledge_mesh;
extractor.iter_lvert_bm = extract_edit_data_iter_lvert_bm;
extractor.iter_lvert_mesh = extract_edit_data_iter_lvert_mesh;
+ extractor.init_subdiv = extract_edit_data_init_subdiv;
+ extractor.iter_subdiv = extract_edit_data_iter_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_edit_data_loose_geom_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(EditLoopData *);
extractor.use_threading = true;
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 b8494428eed..067d482bc2b 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
@@ -25,6 +25,8 @@
#include "draw_cache_impl.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -36,12 +38,11 @@ struct MeshExtract_EditUVData_Data {
int cd_ofs;
};
-static void extract_edituv_data_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf,
- void *tls_data)
+static void extract_edituv_data_init_common(const MeshRenderData *mr,
+ GPUVertBuf *vbo,
+ MeshExtract_EditUVData_Data *data,
+ uint loop_len)
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* WARNING: Adjust #EditLoopData struct accordingly. */
@@ -50,15 +51,23 @@ static void extract_edituv_data_init(const MeshRenderData *mr,
}
GPU_vertbuf_init_with_format(vbo, &format);
- GPU_vertbuf_data_alloc(vbo, mr->loop_len);
+ GPU_vertbuf_data_alloc(vbo, loop_len);
CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
-
- MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data);
data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
data->cd_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV);
}
+static void extract_edituv_data_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data);
+ extract_edituv_data_init_common(mr, vbo, data, mr->loop_len);
+}
+
static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr,
const BMFace *f,
const int UNUSED(f_index),
@@ -119,12 +128,54 @@ static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr,
}
}
+static void extract_edituv_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data);
+ extract_edituv_data_init_common(mr, vbo, data, subdiv_cache->num_subdiv_loops);
+}
+
+static void extract_edituv_data_iter_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ void *_data)
+{
+ MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(_data);
+ int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index);
+ int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index);
+ int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index;
+
+ for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) {
+ const int vert_origindex = subdiv_loop_vert_index[i];
+ const int edge_origindex = subdiv_loop_edge_index[i];
+ const int poly_origindex = subdiv_loop_poly_index[i];
+
+ EditLoopData *edit_loop_data = &data->vbo_data[i];
+ memset(edit_loop_data, 0, sizeof(EditLoopData));
+
+ BMFace *efa = bm_original_face_get(mr, poly_origindex);
+
+ if (vert_origindex != -1 && edge_origindex != -1) {
+ BMEdge *eed = bm_original_edge_get(mr, edge_origindex);
+ /* Loop on an edge endpoint. */
+ BMLoop *l = BM_face_edge_share_loop(efa, eed);
+ 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);
+ }
+ }
+}
+
constexpr MeshExtract create_extractor_edituv_data()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_data_init;
extractor.iter_poly_bm = extract_edituv_data_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_data_iter_poly_mesh;
+ extractor.init_subdiv = extract_edituv_data_init_subdiv;
+ extractor.iter_subdiv = extract_edituv_data_iter_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUVData_Data);
extractor.use_threading = true;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
index a947d98f955..0ea4ef5d5db 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc
@@ -27,6 +27,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -213,12 +215,69 @@ static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr
}
}
+static GPUVertFormat *get_edituv_stretch_angle_format_subdiv()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ /* Waning: adjust #UVStretchAngle struct accordingly. */
+ GPU_vertformat_attr_add(&format, "angle", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
+static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(tls_data))
+{
+ GPUVertBuf *refined_vbo = static_cast<GPUVertBuf *>(buffer);
+
+ GPU_vertbuf_init_build_on_device(
+ refined_vbo, get_edituv_stretch_angle_format_subdiv(), subdiv_cache->num_subdiv_loops);
+
+ GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
+ GPUVertBuf *uvs = cache->final.buff.vbo.uv;
+
+ /* UVs are stored contiguouly so we need to compute the offset in the UVs buffer for the active
+ * UV layer. */
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_MESH) ? &mr->me->ldata : &mr->bm->ldata;
+
+ uint32_t uv_layers = cache->cd_used.uv;
+ /* HACK to fix T68857 */
+ if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) {
+ int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
+ if (layer != -1) {
+ uv_layers |= (1 << layer);
+ }
+ }
+
+ int uvs_offset = 0;
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (uv_layers & (1 << i)) {
+ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
+ break;
+ }
+
+ uvs_offset += 1;
+ }
+ }
+
+ /* The data is at `offset * num loops`, and we have 2 values per index. */
+ uvs_offset *= subdiv_cache->num_subdiv_loops * 2;
+
+ draw_subdiv_build_edituv_stretch_angle_buffer(
+ subdiv_cache, pos_nor, uvs, uvs_offset, refined_vbo);
+}
+
constexpr MeshExtract create_extractor_edituv_edituv_stretch_angle()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_stretch_angle_init;
extractor.iter_poly_bm = extract_edituv_stretch_angle_iter_poly_bm;
extractor.iter_poly_mesh = extract_edituv_stretch_angle_iter_poly_mesh;
+ extractor.init_subdiv = extract_edituv_stretch_angle_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_StretchAngle_Data);
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc
index 3db8cd79af5..3b40b3115f5 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc
@@ -27,6 +27,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -63,14 +65,12 @@ BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_t
return (ratio > 1.0f) ? (1.0f / ratio) : ratio;
}
-static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf,
- void *UNUSED(data))
+static void compute_area_ratio(const MeshRenderData *mr,
+ float *r_area_ratio,
+ float &r_tot_area,
+ float &r_tot_uv_area)
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
float tot_area = 0.0f, tot_uv_area = 0.0f;
- float *area_ratio = static_cast<float *>(MEM_mallocN(sizeof(float) * mr->poly_len, __func__));
if (mr->extract_type == MR_EXTRACT_BMESH) {
CustomData *cd_ldata = &mr->bm->ldata;
@@ -84,7 +84,7 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
float uvarea = BM_face_calc_area_uv(efa, uv_ofs);
tot_area += area;
tot_uv_area += uvarea;
- area_ratio[f] = area_ratio_get(area, uvarea);
+ r_area_ratio[f] = area_ratio_get(area, uvarea);
}
}
else {
@@ -96,12 +96,22 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
float uvarea = BKE_mesh_calc_poly_uv_area(mp, uv_data);
tot_area += area;
tot_uv_area += uvarea;
- area_ratio[mp_index] = area_ratio_get(area, uvarea);
+ r_area_ratio[mp_index] = area_ratio_get(area, uvarea);
}
}
- cache->tot_area = tot_area;
- cache->tot_uv_area = tot_uv_area;
+ r_tot_area = tot_area;
+ r_tot_uv_area = tot_uv_area;
+}
+
+static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ float *area_ratio = static_cast<float *>(MEM_mallocN(sizeof(float) * mr->poly_len, __func__));
+ compute_area_ratio(mr, area_ratio, cache->tot_area, cache->tot_uv_area);
/* Convert in place to avoid an extra allocation */
uint16_t *poly_stretch = (uint16_t *)area_ratio;
@@ -135,11 +145,46 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr,
MEM_freeN(area_ratio);
}
+static void extract_edituv_stretch_area_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+
+ /* Initialise final buffer. */
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+
+ GPU_vertbuf_init_build_on_device(vbo, &format, subdiv_cache->num_subdiv_loops);
+
+ /* Initialize coarse data buffer. */
+
+ GPUVertBuf *coarse_data = GPU_vertbuf_calloc();
+
+ /* We use the same format as we just copy data around. */
+ GPU_vertbuf_init_with_format(coarse_data, &format);
+ GPU_vertbuf_data_alloc(coarse_data, mr->loop_len);
+
+ compute_area_ratio(mr,
+ static_cast<float *>(GPU_vertbuf_get_data(coarse_data)),
+ cache->tot_area,
+ cache->tot_uv_area);
+
+ draw_subdiv_build_edituv_stretch_area_buffer(subdiv_cache, coarse_data, vbo);
+
+ GPU_vertbuf_discard(coarse_data);
+}
+
constexpr MeshExtract create_extractor_edituv_stretch_area()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_stretch_area_init;
extractor.finish = extract_edituv_stretch_area_finish;
+ extractor.init_subdiv = extract_edituv_stretch_area_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
index 33f9180e122..f65159f9b95 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc
@@ -23,24 +23,40 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Face-dots positions
* \{ */
-static void extract_fdots_pos_init(const MeshRenderData *mr,
- struct MeshBatchCache *UNUSED(cache),
- void *buf,
- void *tls_data)
+static GPUVertFormat *get_fdots_pos_format()
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
}
+ return &format;
+}
+
+static GPUVertFormat *get_fdots_nor_format_subdiv()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
- GPU_vertbuf_init_with_format(vbo, &format);
+static void extract_fdots_pos_init(const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *tls_data)
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPUVertFormat *format = get_fdots_pos_format();
+ GPU_vertbuf_init_with_format(vbo, format);
GPU_vertbuf_data_alloc(vbo, mr->poly_len);
void *vbo_data = GPU_vertbuf_get_data(vbo);
*(float(**)[3])tls_data = static_cast<float(*)[3]>(vbo_data);
@@ -97,10 +113,30 @@ static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr,
}
}
+static void extract_fdots_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ /* We "extract" positions, normals, and indices at once. */
+ GPUVertBuf *fdots_pos_vbo = static_cast<GPUVertBuf *>(buffer);
+ GPUVertBuf *fdots_nor_vbo = cache->final.buff.vbo.fdots_nor;
+ GPUIndexBuf *fdots_pos_ibo = cache->final.buff.ibo.fdots;
+
+ GPU_vertbuf_init_build_on_device(
+ fdots_nor_vbo, get_fdots_nor_format_subdiv(), subdiv_cache->num_coarse_poly);
+ GPU_vertbuf_init_build_on_device(
+ fdots_pos_vbo, get_fdots_pos_format(), subdiv_cache->num_coarse_poly);
+ GPU_indexbuf_init_build_on_device(fdots_pos_ibo, subdiv_cache->num_coarse_poly);
+ draw_subdiv_build_fdots_buffers(subdiv_cache, fdots_pos_vbo, fdots_nor_vbo, fdots_pos_ibo);
+}
+
constexpr MeshExtract create_extractor_fdots_pos()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_fdots_pos_init;
+ extractor.init_subdiv = extract_fdots_init_subdiv;
extractor.iter_poly_bm = extract_fdots_pos_iter_poly_bm;
extractor.iter_poly_mesh = extract_fdots_pos_iter_poly_mesh;
extractor.data_type = MR_DATA_NONE;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
index 3c3ac7a7a0a..d30c38ef050 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
@@ -23,6 +23,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -107,10 +109,34 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr,
}
}
+static GPUVertFormat *get_subdiv_lnor_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "lnor");
+ }
+ return &format;
+}
+
+static void extract_lnor_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
+ BLI_assert(pos_nor);
+ GPU_vertbuf_init_build_on_device(vbo, get_subdiv_lnor_format(), subdiv_cache->num_subdiv_loops);
+ draw_subdiv_build_lnor_buffer(subdiv_cache, pos_nor, vbo);
+}
+
constexpr MeshExtract create_extractor_lnor()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_lnor_init;
+ extractor.init_subdiv = extract_lnor_init_subdiv;
extractor.iter_poly_bm = extract_lnor_iter_poly_bm;
extractor.iter_poly_mesh = extract_lnor_iter_poly_mesh;
extractor.data_type = MR_DATA_LOOP_NOR;
@@ -210,6 +236,7 @@ constexpr MeshExtract create_extractor_lnor_hq()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_lnor_hq_init;
+ extractor.init_subdiv = extract_lnor_init_subdiv;
extractor.iter_poly_bm = extract_lnor_hq_iter_poly_bm;
extractor.iter_poly_mesh = extract_lnor_hq_iter_poly_mesh;
extractor.data_type = MR_DATA_LOOP_NOR;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
index eb9a138590c..00ed4ca6359 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
@@ -25,6 +25,8 @@
#include "extract_mesh.h"
+#include "draw_subdivision.h"
+
namespace blender::draw {
/* ---------------------------------------------------------------------- */
@@ -194,6 +196,123 @@ static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr),
MEM_freeN(data->normals);
}
+static GPUVertFormat *get_pos_nor_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "vnor");
+ }
+ return &format;
+}
+
+static GPUVertFormat *get_normals_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "lnor");
+ }
+ return &format;
+}
+
+static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ const bool do_limit_normals = subdiv_cache->do_limit_normals;
+
+ /* Initialize the vertex buffer, it was already allocated. */
+ GPU_vertbuf_init_build_on_device(
+ vbo, get_pos_nor_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len);
+
+ draw_subdiv_extract_pos_nor(subdiv_cache, vbo, do_limit_normals);
+
+ if (!do_limit_normals) {
+ /* We cannot evaluate vertex normals using the limit surface, so compute them manually. */
+ GPUVertBuf *subdiv_loop_subdiv_vert_index = draw_subdiv_build_origindex_buffer(
+ subdiv_cache->subdiv_loop_subdiv_vert_index, subdiv_cache->num_subdiv_loops);
+
+ GPUVertBuf *vertex_normals = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_build_on_device(
+ vertex_normals, get_normals_format(), subdiv_cache->num_subdiv_verts);
+
+ draw_subdiv_accumulate_normals(subdiv_cache,
+ vbo,
+ subdiv_cache->subdiv_vertex_face_adjacency_offsets,
+ subdiv_cache->subdiv_vertex_face_adjacency,
+ vertex_normals);
+
+ draw_subdiv_finalize_normals(subdiv_cache, vertex_normals, subdiv_loop_subdiv_vert_index, vbo);
+
+ GPU_vertbuf_discard(vertex_normals);
+ GPU_vertbuf_discard(subdiv_loop_subdiv_vert_index);
+ }
+}
+
+static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
+ if (loop_loose_len == 0) {
+ return;
+ }
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ const Mesh *coarse_mesh = subdiv_cache->mesh;
+ const MEdge *coarse_edges = coarse_mesh->medge;
+ const MVert *coarse_verts = coarse_mesh->mvert;
+ uint offset = subdiv_cache->num_subdiv_loops;
+
+ /* TODO(kevindietrich) : replace this when compressed normals are supported. */
+ struct SubdivPosNorLoop {
+ float pos[3];
+ float nor[3];
+ float flag;
+ };
+
+ SubdivPosNorLoop edge_data[2];
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
+ const MVert *loose_vert1 = &coarse_verts[loose_edge->v1];
+ const MVert *loose_vert2 = &coarse_verts[loose_edge->v2];
+
+ copy_v3_v3(edge_data[0].pos, loose_vert1->co);
+ normal_short_to_float_v3(edge_data[0].nor, loose_vert1->no);
+ edge_data[0].flag = 0.0f;
+
+ copy_v3_v3(edge_data[1].pos, loose_vert2->co);
+ normal_short_to_float_v3(edge_data[1].nor, loose_vert2->no);
+ edge_data[1].flag = 0.0f;
+
+ GPU_vertbuf_update_sub(
+ vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop) * 2, &edge_data);
+
+ offset += 2;
+ }
+
+ SubdivPosNorLoop vert_data;
+ vert_data.flag = 0.0f;
+ for (int i = 0; i < loose_geom->vert_len; i++) {
+ const MVert *loose_vertex = &coarse_verts[loose_geom->verts[i]];
+
+ copy_v3_v3(vert_data.pos, loose_vertex->co);
+ normal_short_to_float_v3(vert_data.nor, loose_vertex->no);
+
+ GPU_vertbuf_update_sub(
+ vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop), &vert_data);
+
+ offset += 1;
+ }
+}
+
constexpr MeshExtract create_extractor_pos_nor()
{
MeshExtract extractor = {nullptr};
@@ -205,6 +324,8 @@ constexpr MeshExtract create_extractor_pos_nor()
extractor.iter_lvert_bm = extract_pos_nor_iter_lvert_bm;
extractor.iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh;
extractor.finish = extract_pos_nor_finish;
+ extractor.init_subdiv = extract_pos_nor_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_pos_nor_loose_geom_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_PosNor_Data);
extractor.use_threading = true;
@@ -391,6 +512,7 @@ constexpr MeshExtract create_extractor_pos_nor_hq()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_pos_nor_hq_init;
+ extractor.init_subdiv = extract_pos_nor_init_subdiv;
extractor.iter_poly_bm = extract_pos_nor_hq_iter_poly_bm;
extractor.iter_poly_mesh = extract_pos_nor_hq_iter_poly_mesh;
extractor.iter_ledge_bm = extract_pos_nor_hq_iter_ledge_bm;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
index fd91bc5258f..753fbe7e0e2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc
@@ -27,6 +27,7 @@
#include "BKE_paint.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -35,13 +36,23 @@ namespace blender::draw {
/** \name Extract Sculpt Data
* \{ */
+static GPUVertFormat *get_sculpt_data_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+ return &format;
+}
+
static void extract_sculpt_data_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *buf,
void *UNUSED(tls_data))
{
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
- GPUVertFormat format = {0};
+ GPUVertFormat *format = get_sculpt_data_format();
CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
@@ -50,12 +61,7 @@ static void extract_sculpt_data_init(const MeshRenderData *mr,
float *cd_mask = (float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
int *cd_face_set = (int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS);
- if (format.attr_len == 0) {
- GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
- GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- }
-
- GPU_vertbuf_init_with_format(vbo, &format);
+ GPU_vertbuf_init_with_format(vbo, format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
struct gpuSculptData {
@@ -121,10 +127,99 @@ static void extract_sculpt_data_init(const MeshRenderData *mr,
}
}
+static void extract_sculpt_data_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ struct MeshBatchCache *UNUSED(cache),
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+
+ Mesh *coarse_mesh = mr->me;
+ CustomData *cd_vdata = &coarse_mesh->vdata;
+ CustomData *cd_pdata = &coarse_mesh->pdata;
+
+ /* First, interpolate mask if available. */
+ GPUVertBuf *mask_vbo = nullptr;
+ GPUVertBuf *subdiv_mask_vbo = nullptr;
+ float *cd_mask = (float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK);
+
+ if (cd_mask) {
+ GPUVertFormat mask_format = {0};
+ GPU_vertformat_attr_add(&mask_format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+
+ mask_vbo = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format(mask_vbo, &mask_format);
+ GPU_vertbuf_data_alloc(mask_vbo, coarse_mesh->totloop);
+ float *v_mask = static_cast<float *>(GPU_vertbuf_get_data(mask_vbo));
+
+ for (int i = 0; i < coarse_mesh->totpoly; i++) {
+ const MPoly *mpoly = &coarse_mesh->mpoly[i];
+
+ for (int loop_index = mpoly->loopstart; loop_index < mpoly->loopstart + mpoly->totloop;
+ loop_index++) {
+ const MLoop *ml = &coarse_mesh->mloop[loop_index];
+ *v_mask++ = cd_mask[ml->v];
+ }
+ }
+
+ subdiv_mask_vbo = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_build_on_device(
+ subdiv_mask_vbo, &mask_format, subdiv_cache->num_subdiv_loops);
+
+ draw_subdiv_interp_custom_data(subdiv_cache, mask_vbo, subdiv_mask_vbo, 1, 0);
+ }
+
+ /* Then, gather face sets. */
+ GPUVertFormat face_set_format = {0};
+ GPU_vertformat_attr_add(&face_set_format, "msk", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+
+ GPUVertBuf *face_set_vbo = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format(face_set_vbo, &face_set_format);
+ GPU_vertbuf_data_alloc(face_set_vbo, subdiv_cache->num_subdiv_loops);
+
+ struct gpuFaceSet {
+ uint8_t color[4];
+ };
+
+ gpuFaceSet *face_sets = (gpuFaceSet *)GPU_vertbuf_get_data(face_set_vbo);
+ int *cd_face_set = (int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS);
+
+ GPUVertFormat *format = get_sculpt_data_format();
+ GPU_vertbuf_init_build_on_device(vbo, format, subdiv_cache->num_subdiv_loops);
+ int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index;
+
+ for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) {
+ const int mp_index = subdiv_loop_poly_index[i];
+
+ uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
+ if (cd_face_set) {
+ const int face_set_id = cd_face_set[mp_index];
+ /* Skip for the default color Face Set to render it white. */
+ if (face_set_id != coarse_mesh->face_sets_color_default) {
+ BKE_paint_face_set_overlay_color_get(
+ face_set_id, coarse_mesh->face_sets_color_seed, face_set_color);
+ }
+ }
+ copy_v3_v3_uchar(face_sets->color, face_set_color);
+ face_sets++;
+ }
+
+ /* Finally, interleave mask and face sets. */
+ draw_subdiv_build_sculpt_data_buffer(subdiv_cache, subdiv_mask_vbo, face_set_vbo, vbo);
+
+ if (mask_vbo) {
+ GPU_vertbuf_discard(mask_vbo);
+ GPU_vertbuf_discard(subdiv_mask_vbo);
+ }
+ GPU_vertbuf_discard(face_set_vbo);
+}
+
constexpr MeshExtract create_extractor_sculpt_data()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_sculpt_data_init;
+ extractor.init_subdiv = extract_sculpt_data_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
index 5ac30dd3be9..33c27b45627 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc
@@ -21,6 +21,7 @@
* \ingroup draw
*/
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -196,12 +197,104 @@ static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr,
(*(uint32_t **)data)[offset + lvert_index] = v_orig;
}
+static void extract_vert_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ /* Each element points to an element in the ibo.points. */
+ draw_subdiv_init_origindex_buffer(vbo,
+ subdiv_cache->subdiv_loop_subdiv_vert_index,
+ subdiv_cache->num_subdiv_loops,
+ mr->loop_loose_len);
+}
+
+static void extract_vert_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
+ if (loop_loose_len == 0) {
+ return;
+ }
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo);
+ const Mesh *coarse_mesh = subdiv_cache->mesh;
+ const MEdge *coarse_edges = coarse_mesh->medge;
+ uint offset = subdiv_cache->num_subdiv_loops;
+
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]];
+ vert_idx_data[offset] = loose_edge->v1;
+ vert_idx_data[offset + 1] = loose_edge->v2;
+ offset += 2;
+ }
+
+ for (int i = 0; i < loose_geom->vert_len; i++) {
+ vert_idx_data[offset] = loose_geom->verts[i];
+ offset += 1;
+ }
+}
+
+static void extract_edge_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *mr,
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ draw_subdiv_init_origindex_buffer(
+ vbo,
+ static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)),
+ subdiv_cache->num_subdiv_loops,
+ mr->edge_loose_len * 2);
+}
+
+static void extract_edge_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ const MeshExtractLooseGeom *loose_geom,
+ void *buffer,
+ void *UNUSED(data))
+{
+ const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len;
+ if (loop_loose_len == 0) {
+ return;
+ }
+
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo);
+ uint offset = subdiv_cache->num_subdiv_loops;
+
+ for (int i = 0; i < loose_geom->edge_len; i++) {
+ vert_idx_data[offset] = loose_geom->edges[i];
+ vert_idx_data[offset + 1] = loose_geom->edges[i];
+ offset += 2;
+ }
+}
+
+static void extract_poly_idx_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ MeshBatchCache *UNUSED(cache),
+ void *buf,
+ void *UNUSED(data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ draw_subdiv_init_origindex_buffer(
+ vbo, subdiv_cache->subdiv_loop_poly_index, subdiv_cache->num_subdiv_loops, 0);
+}
+
constexpr MeshExtract create_extractor_poly_idx()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_select_idx_init;
extractor.iter_poly_bm = extract_poly_idx_iter_poly_bm;
extractor.iter_poly_mesh = extract_poly_idx_iter_poly_mesh;
+ extractor.init_subdiv = extract_poly_idx_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(uint32_t *);
extractor.use_threading = true;
@@ -217,6 +310,8 @@ constexpr MeshExtract create_extractor_edge_idx()
extractor.iter_poly_mesh = extract_edge_idx_iter_poly_mesh;
extractor.iter_ledge_bm = extract_edge_idx_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_edge_idx_iter_ledge_mesh;
+ extractor.init_subdiv = extract_edge_idx_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_edge_idx_loose_geom_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(uint32_t *);
extractor.use_threading = true;
@@ -234,6 +329,8 @@ constexpr MeshExtract create_extractor_vert_idx()
extractor.iter_ledge_mesh = extract_vert_idx_iter_ledge_mesh;
extractor.iter_lvert_bm = extract_vert_idx_iter_lvert_bm;
extractor.iter_lvert_mesh = extract_vert_idx_iter_lvert_mesh;
+ extractor.init_subdiv = extract_vert_idx_init_subdiv;
+ extractor.iter_loose_geom_subdiv = extract_vert_idx_loose_geom_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(uint32_t *);
extractor.use_threading = true;
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 af279b08a59..6e9d8ef6926 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
@@ -23,6 +23,7 @@
#include "BLI_string.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -31,25 +32,27 @@ namespace blender::draw {
/** \name Extract UV layers
* \{ */
-static void extract_uv_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf,
- void *UNUSED(tls_data))
+/* Initialize the vertex format to be used for UVs. Return true if any UV layer is
+ * found, false otherwise. */
+static bool mesh_extract_uv_format_init(GPUVertFormat *format,
+ struct MeshBatchCache *cache,
+ CustomData *cd_ldata,
+ eMRExtractType extract_type,
+ uint32_t &r_uv_layers)
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
- GPUVertFormat format = {0};
- GPU_vertformat_deinterleave(&format);
+ GPU_vertformat_deinterleave(format);
- CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
uint32_t uv_layers = cache->cd_used.uv;
/* HACK to fix T68857 */
- if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) {
+ if (extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) {
int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV);
if (layer != -1) {
uv_layers |= (1 << layer);
}
}
+ r_uv_layers = uv_layers;
+
for (int i = 0; i < MAX_MTFACE; i++) {
if (uv_layers & (1 << i)) {
char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
@@ -58,30 +61,47 @@ static void extract_uv_init(const MeshRenderData *mr,
GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
/* UV layer name. */
BLI_snprintf(attr_name, sizeof(attr_name), "u%s", attr_safe_name);
- GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPU_vertformat_attr_add(format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
/* Auto layer name. */
BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
- GPU_vertformat_alias_add(&format, attr_name);
+ GPU_vertformat_alias_add(format, attr_name);
/* Active render layer name. */
if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) {
- GPU_vertformat_alias_add(&format, "u");
+ GPU_vertformat_alias_add(format, "u");
}
/* Active display layer name. */
if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
- GPU_vertformat_alias_add(&format, "au");
+ GPU_vertformat_alias_add(format, "au");
/* Alias to `pos` for edit uvs. */
- GPU_vertformat_alias_add(&format, "pos");
+ GPU_vertformat_alias_add(format, "pos");
}
/* Stencil mask uv layer name. */
if (i == CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV)) {
- GPU_vertformat_alias_add(&format, "mu");
+ GPU_vertformat_alias_add(format, "mu");
}
}
}
+ if (format->attr_len == 0) {
+ GPU_vertformat_attr_add(format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ return false;
+ }
+
+ return true;
+}
+
+static void extract_uv_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(tls_data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPUVertFormat format = {0};
+
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
int v_len = mr->loop_len;
- if (format.attr_len == 0) {
- GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint32_t uv_layers = cache->cd_used.uv;
+ if (!mesh_extract_uv_format_init(&format, cache, cd_ldata, mr->extract_type, uv_layers)) {
/* VBO will not be used, only allocate minimum of memory. */
v_len = 1;
}
@@ -116,10 +136,45 @@ static void extract_uv_init(const MeshRenderData *mr,
}
}
+static void extract_uv_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ Mesh *coarse_mesh = subdiv_cache->mesh;
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+ GPUVertFormat format = {0};
+
+ uint v_len = subdiv_cache->num_subdiv_loops;
+ 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.
+ v_len = 1;
+ }
+
+ GPU_vertbuf_init_build_on_device(vbo, &format, v_len);
+
+ if (uv_layers == 0) {
+ return;
+ }
+
+ /* Index of the UV layer in the compact buffer. Used UV layers are stored in a single buffer. */
+ int pack_layer_index = 0;
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (uv_layers & (1 << i)) {
+ const int offset = (int)subdiv_cache->num_subdiv_loops * pack_layer_index++;
+ draw_subdiv_extract_uvs(subdiv_cache, vbo, i, offset);
+ }
+ }
+}
+
constexpr MeshExtract create_extractor_uv()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_uv_init;
+ extractor.init_subdiv = extract_uv_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
index f8878eb2617..a0307b9b2cd 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc
@@ -25,6 +25,7 @@
#include "BLI_string.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -33,17 +34,14 @@ namespace blender::draw {
/** \name Extract VCol
* \{ */
-static void extract_vcol_init(const MeshRenderData *mr,
- struct MeshBatchCache *cache,
- void *buf,
- void *UNUSED(tls_data))
+/* Initialize the common vertex format for vcol for coarse and subdivided meshes. */
+static void init_vcol_format(GPUVertFormat *format,
+ const MeshBatchCache *cache,
+ CustomData *cd_ldata)
{
- GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
- GPUVertFormat format = {0};
- GPU_vertformat_deinterleave(&format);
+ GPU_vertformat_deinterleave(format);
- CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
- uint32_t vcol_layers = cache->cd_used.vcol;
+ const uint32_t vcol_layers = cache->cd_used.vcol;
for (int i = 0; i < MAX_MCOL; i++) {
if (vcol_layers & (1 << i)) {
@@ -52,31 +50,56 @@ static void extract_vcol_init(const MeshRenderData *mr,
GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name);
- GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ GPU_vertformat_attr_add(format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) {
- GPU_vertformat_alias_add(&format, "c");
+ GPU_vertformat_alias_add(format, "c");
}
if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) {
- GPU_vertformat_alias_add(&format, "ac");
+ GPU_vertformat_alias_add(format, "ac");
}
/* Gather number of auto layers. */
/* We only do `vcols` that are not overridden by `uvs`. */
if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) {
BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name);
- GPU_vertformat_alias_add(&format, attr_name);
+ GPU_vertformat_alias_add(format, attr_name);
}
}
}
+}
+
+/* Vertex format for vertex colors, only used during the coarse data upload for the subdivision
+ * case. */
+static GPUVertFormat *get_coarse_vcol_format()
+{
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "cCol", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPU_vertformat_alias_add(&format, "c");
+ GPU_vertformat_alias_add(&format, "ac");
+ }
+ return &format;
+}
+
+using gpuMeshVcol = struct gpuMeshVcol {
+ ushort r, g, b, a;
+};
+
+static void extract_vcol_init(const MeshRenderData *mr,
+ struct MeshBatchCache *cache,
+ void *buf,
+ void *UNUSED(tls_data))
+{
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
+ GPUVertFormat format = {0};
+ CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
+ const uint32_t vcol_layers = cache->cd_used.vcol;
+ init_vcol_format(&format, cache, cd_ldata);
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr->loop_len);
- using gpuMeshVcol = struct gpuMeshVcol {
- ushort r, g, b, a;
- };
-
gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo);
for (int i = 0; i < MAX_MCOL; i++) {
@@ -111,10 +134,64 @@ static void extract_vcol_init(const MeshRenderData *mr,
}
}
+static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
+ Mesh *coarse_mesh = subdiv_cache->mesh;
+
+ GPUVertFormat format = {0};
+ init_vcol_format(&format, cache, &coarse_mesh->ldata);
+
+ GPU_vertbuf_init_build_on_device(dst_buffer, &format, subdiv_cache->num_subdiv_loops);
+
+ GPUVertBuf *src_data = GPU_vertbuf_calloc();
+ /* Dynamic as we upload and interpolate layers one at a time. */
+ GPU_vertbuf_init_with_format_ex(src_data, get_coarse_vcol_format(), GPU_USAGE_DYNAMIC);
+
+ GPU_vertbuf_data_alloc(src_data, coarse_mesh->totloop);
+
+ gpuMeshVcol *mesh_vcol = (gpuMeshVcol *)GPU_vertbuf_get_data(src_data);
+
+ const CustomData *cd_ldata = &coarse_mesh->ldata;
+
+ const uint vcol_layers = cache->cd_used.vcol;
+
+ /* Index of the vertex color layer in the compact buffer. Used vertex color layers are stored in
+ * a single buffer. */
+ int pack_layer_index = 0;
+ for (int i = 0; i < MAX_MTFACE; i++) {
+ if (vcol_layers & (1 << i)) {
+ /* Include stride in offset, we use a stride of 2 since colors are packed into 2 uints. */
+ const int dst_offset = (int)subdiv_cache->num_subdiv_loops * 2 * pack_layer_index++;
+ const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i);
+
+ gpuMeshVcol *vcol = mesh_vcol;
+
+ for (int ml_index = 0; ml_index < coarse_mesh->totloop; ml_index++, vcol++, mloopcol++) {
+ vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]);
+ vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]);
+ vcol->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]);
+ vcol->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f));
+ }
+
+ /* Ensure data is uploaded properly. */
+ GPU_vertbuf_tag_dirty(src_data);
+ draw_subdiv_interp_custom_data(subdiv_cache, src_data, dst_buffer, 4, dst_offset);
+ }
+ }
+
+ GPU_vertbuf_discard(src_data);
+}
+
constexpr MeshExtract create_extractor_vcol()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_vcol_init;
+ extractor.init_subdiv = extract_vcol_init_subdiv;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc
index bdb1410a755..bb8853b8154 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc
@@ -25,6 +25,7 @@
#include "BKE_deform.h"
+#include "draw_subdivision.h"
#include "extract_mesh.h"
namespace blender::draw {
@@ -167,10 +168,57 @@ static void extract_weights_iter_poly_mesh(const MeshRenderData *mr,
}
}
+static void extract_weights_init_subdiv(const DRWSubdivCache *subdiv_cache,
+ const MeshRenderData *UNUSED(mr),
+ struct MeshBatchCache *cache,
+ void *buffer,
+ void *UNUSED(data))
+{
+ Mesh *coarse_mesh = subdiv_cache->mesh;
+ GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
+
+ static GPUVertFormat format = {0};
+ if (format.attr_len == 0) {
+ GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ }
+ GPU_vertbuf_init_build_on_device(vbo, &format, subdiv_cache->num_subdiv_loops);
+
+ GPUVertBuf *coarse_weights = GPU_vertbuf_calloc();
+ GPU_vertbuf_init_with_format(coarse_weights, &format);
+ GPU_vertbuf_data_alloc(coarse_weights, coarse_mesh->totloop);
+ float *coarse_weights_data = static_cast<float *>(GPU_vertbuf_get_data(coarse_weights));
+
+ const DRW_MeshWeightState *wstate = &cache->weight_state;
+ const MDeformVert *dverts = static_cast<const MDeformVert *>(
+ CustomData_get_layer(&coarse_mesh->vdata, CD_MDEFORMVERT));
+
+ for (int i = 0; i < coarse_mesh->totpoly; i++) {
+ const MPoly *mpoly = &coarse_mesh->mpoly[i];
+
+ for (int loop_index = mpoly->loopstart; loop_index < mpoly->loopstart + mpoly->totloop;
+ loop_index++) {
+ const MLoop *ml = &coarse_mesh->mloop[loop_index];
+
+ if (dverts != nullptr) {
+ const MDeformVert *dvert = &dverts[ml->v];
+ coarse_weights_data[loop_index] = evaluate_vertex_weight(dvert, wstate);
+ }
+ else {
+ coarse_weights_data[loop_index] = evaluate_vertex_weight(nullptr, wstate);
+ }
+ }
+ }
+
+ draw_subdiv_interp_custom_data(subdiv_cache, coarse_weights, vbo, 1, 0);
+
+ GPU_vertbuf_discard(coarse_weights);
+}
+
constexpr MeshExtract create_extractor_weights()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_weights_init;
+ extractor.init_subdiv = extract_weights_init_subdiv;
extractor.iter_poly_bm = extract_weights_iter_poly_bm;
extractor.iter_poly_mesh = extract_weights_iter_poly_mesh;
extractor.data_type = MR_DATA_NONE;
diff --git a/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl
new file mode 100644
index 00000000000..36c3970d9a0
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl
@@ -0,0 +1,230 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 1) readonly restrict buffer sourceBuffer
+{
+#ifdef GPU_FETCH_U16_TO_FLOAT
+ uint src_data[];
+#else
+ float src_data[];
+#endif
+};
+
+layout(std430, binding = 2) readonly restrict buffer facePTexOffset
+{
+ uint face_ptex_offset[];
+};
+
+layout(std430, binding = 3) readonly restrict buffer patchCoords
+{
+ BlenderPatchCoord patch_coords[];
+};
+
+layout(std430, binding = 4) readonly restrict buffer extraCoarseFaceData
+{
+ uint extra_coarse_face_data[];
+};
+
+layout(std430, binding = 5) writeonly restrict buffer destBuffer
+{
+#ifdef GPU_FETCH_U16_TO_FLOAT
+ uint dst_data[];
+#else
+ float dst_data[];
+#endif
+};
+
+struct Vertex {
+ float vertex_data[DIMENSIONS];
+};
+
+void clear(inout Vertex v)
+{
+ for (int i = 0; i < DIMENSIONS; i++) {
+ v.vertex_data[i] = 0.0;
+ }
+}
+
+Vertex read_vertex(uint index)
+{
+ Vertex result;
+#ifdef GPU_FETCH_U16_TO_FLOAT
+ uint base_index = index * 2;
+ if (DIMENSIONS == 4) {
+ uint xy = src_data[base_index];
+ uint zw = src_data[base_index + 1];
+
+ float x = float((xy >> 16) & 0xffff) / 65535.0;
+ float y = float(xy & 0xffff) / 65535.0;
+ float z = float((zw >> 16) & 0xffff) / 65535.0;
+ float w = float(zw & 0xffff) / 65535.0;
+
+ result.vertex_data[0] = x;
+ result.vertex_data[1] = y;
+ result.vertex_data[2] = z;
+ result.vertex_data[3] = w;
+ }
+ else {
+ /* This case is unsupported for now. */
+ clear(result);
+ }
+#else
+ uint base_index = index * DIMENSIONS;
+ for (int i = 0; i < DIMENSIONS; i++) {
+ result.vertex_data[i] = src_data[base_index + i];
+ }
+#endif
+ return result;
+}
+
+void write_vertex(uint index, Vertex v)
+{
+#ifdef GPU_FETCH_U16_TO_FLOAT
+ uint base_index = dst_offset + index * 2;
+ if (DIMENSIONS == 4) {
+ uint x = uint(v.vertex_data[0] * 65535.0);
+ uint y = uint(v.vertex_data[1] * 65535.0);
+ uint z = uint(v.vertex_data[2] * 65535.0);
+ uint w = uint(v.vertex_data[3] * 65535.0);
+
+ uint xy = x << 16 | y;
+ uint zw = z << 16 | w;
+
+ dst_data[base_index] = xy;
+ dst_data[base_index + 1] = zw;
+ }
+ else {
+ /* This case is unsupported for now. */
+ dst_data[base_index] = 0;
+ }
+#else
+ uint base_index = dst_offset + index * DIMENSIONS;
+ for (int i = 0; i < DIMENSIONS; i++) {
+ dst_data[base_index + i] = v.vertex_data[i];
+ }
+#endif
+}
+
+Vertex interp_vertex(Vertex v0, Vertex v1, Vertex v2, Vertex v3, vec2 uv)
+{
+ Vertex result;
+ for (int i = 0; i < DIMENSIONS; i++) {
+ float e = mix(v0.vertex_data[i], v1.vertex_data[i], uv.x);
+ float f = mix(v2.vertex_data[i], v3.vertex_data[i], uv.x);
+ result.vertex_data[i] = mix(e, f, uv.y);
+ }
+ return result;
+}
+
+void add_with_weight(inout Vertex v0, Vertex v1, float weight)
+{
+ for (int i = 0; i < DIMENSIONS; i++) {
+ v0.vertex_data[i] += v1.vertex_data[i] * weight;
+ }
+}
+
+Vertex average(Vertex v0, Vertex v1)
+{
+ Vertex result;
+ for (int i = 0; i < DIMENSIONS; i++) {
+ result.vertex_data[i] = (v0.vertex_data[i] + v1.vertex_data[i]) * 0.5;
+ }
+ return result;
+}
+
+uint get_vertex_count(uint coarse_polygon)
+{
+ uint number_of_patches = face_ptex_offset[coarse_polygon + 1] - face_ptex_offset[coarse_polygon];
+ if (number_of_patches == 1) {
+ /* If there is only one patch for the current coarse polygon, then it is a quad. */
+ return 4;
+ }
+ /* Otherwise, the number of patches is the number of vertices. */
+ return number_of_patches;
+}
+
+uint get_polygon_corner_index(uint coarse_polygon, uint patch_index)
+{
+ uint patch_offset = face_ptex_offset[coarse_polygon];
+ return patch_index - patch_offset;
+}
+
+uint get_loop_start(uint coarse_polygon)
+{
+ return extra_coarse_face_data[coarse_polygon] & coarse_face_loopstart_mask;
+}
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ /* Find which coarse polygon we came from. */
+ uint coarse_polygon = coarse_polygon_index_from_subdiv_quad_index(quad_index, coarse_poly_count);
+ uint loop_start = get_loop_start(coarse_polygon);
+
+ /* Find the number of vertices for the coarse polygon. */
+ Vertex v0, v1, v2, v3;
+ clear(v0);
+ clear(v1);
+ clear(v2);
+ clear(v3);
+
+ uint number_of_vertices = get_vertex_count(coarse_polygon);
+ if (number_of_vertices == 4) {
+ /* Interpolate the src data. */
+ v0 = read_vertex(loop_start + 0);
+ v1 = read_vertex(loop_start + 1);
+ v2 = read_vertex(loop_start + 2);
+ v3 = read_vertex(loop_start + 3);
+ }
+ else {
+ /* Interpolate the src data for the center. */
+ uint loop_end = loop_start + number_of_vertices - 1;
+ Vertex center_value;
+ clear(center_value);
+
+ float weight = 1.0 / float(number_of_vertices);
+
+ for (uint l = loop_start; l < loop_end; l++) {
+ add_with_weight(center_value, read_vertex(l), weight);
+ }
+
+ /* Interpolate between the previous and next corner for the middle values for the edges. */
+ uint patch_index = uint(patch_coords[start_loop_index].patch_index);
+ uint current_coarse_corner = get_polygon_corner_index(coarse_polygon, patch_index);
+ uint next_coarse_corner = (current_coarse_corner + 1) % number_of_vertices;
+ uint prev_coarse_corner = (current_coarse_corner + number_of_vertices - 1) %
+ number_of_vertices;
+
+ v0 = read_vertex(loop_start);
+ v1 = average(v0, read_vertex(loop_start + next_coarse_corner));
+ v3 = average(v0, read_vertex(loop_start + prev_coarse_corner));
+
+ /* Interpolate between the current value, and the ones for the center and mid-edges. */
+ v2 = center_value;
+ }
+
+ /* Do a linear interpolation of the data based on the UVs for each loop of this subdivided quad.
+ */
+ for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
+ BlenderPatchCoord co = patch_coords[loop_index];
+ vec2 uv = decode_uv(co.encoded_uv);
+ /* NOTE: v2 and v3 are reversed to stay consistent with the interpolation weight on the x-axis:
+ *
+ * v3 +-----+ v2
+ * | |
+ * | |
+ * v0 +-----+ v1
+ *
+ * otherwise, weight would be `1.0 - uv.x` for `v2 <-> v3`, but `uv.x` for `v0 <-> v1`.
+ */
+ Vertex result = interp_vertex(v0, v1, v3, v2, uv);
+ write_vertex(loop_index, result);
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl
new file mode 100644
index 00000000000..f11c0f6427e
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl
@@ -0,0 +1,57 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputEdgeOrigIndex
+{
+ int input_origindex[];
+};
+
+layout(std430, binding = 1) writeonly buffer outputLinesIndices
+{
+ uint output_lines[];
+};
+
+#ifndef LINES_LOOSE
+void emit_line(uint line_offset, uint start_loop_index, uint corner_index)
+{
+ uint vertex_index = start_loop_index + corner_index;
+
+ if (input_origindex[vertex_index] == ORIGINDEX_NONE && optimal_display) {
+ output_lines[line_offset + 0] = 0xffffffff;
+ output_lines[line_offset + 1] = 0xffffffff;
+ }
+ else {
+ /* Mod 4 so we loop back at the first vertex on the last loop index (3). */
+ uint next_vertex_index = start_loop_index + (corner_index + 1) % 4;
+
+ output_lines[line_offset + 0] = vertex_index;
+ output_lines[line_offset + 1] = next_vertex_index;
+ }
+}
+#endif
+
+void main()
+{
+ uint index = get_global_invocation_index();
+ if (index >= total_dispatch_size) {
+ return;
+ }
+
+#ifdef LINES_LOOSE
+ /* In the loose lines case, we execute for each line, with two vertices per line. */
+ uint line_offset = edge_loose_offset + index * 2;
+ uint loop_index = num_subdiv_loops + index * 2;
+ output_lines[line_offset] = loop_index;
+ output_lines[line_offset + 1] = loop_index + 1;
+#else
+ /* We execute for each quad, so the start index of the loop is quad_index * 4. */
+ uint start_loop_index = index * 4;
+ /* We execute for each quad, so the start index of the line is quad_index * 8 (with 2 vertices
+ * per line). */
+ uint start_line_index = index * 8;
+
+ for (int i = 0; i < 4; i++) {
+ emit_line(start_line_index + i * 2, start_loop_index, i);
+ }
+#endif
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl
new file mode 100644
index 00000000000..3257ebdae17
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl
@@ -0,0 +1,43 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+/* Generate triangles from subdivision quads indices. */
+
+layout(std430, binding = 1) writeonly buffer outputTriangles
+{
+ uint output_tris[];
+};
+
+#ifndef SINGLE_MATERIAL
+layout(std430, binding = 2) readonly buffer inputPolygonMatOffset
+{
+ int polygon_mat_offset[];
+};
+#endif
+
+void main()
+{
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint loop_index = quad_index * 4;
+
+#ifdef SINGLE_MATERIAL
+ uint triangle_loop_index = quad_index * 6;
+#else
+ uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
+ coarse_poly_count);
+ int mat_offset = polygon_mat_offset[coarse_quad_index];
+
+ int triangle_loop_index = (int(quad_index) + mat_offset) * 6;
+#endif
+
+ output_tris[triangle_loop_index + 0] = loop_index + 0;
+ output_tris[triangle_loop_index + 1] = loop_index + 1;
+ output_tris[triangle_loop_index + 2] = loop_index + 2;
+ output_tris[triangle_loop_index + 3] = loop_index + 0;
+ output_tris[triangle_loop_index + 4] = loop_index + 2;
+ output_tris[triangle_loop_index + 5] = loop_index + 3;
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
new file mode 100644
index 00000000000..005561964b8
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl
@@ -0,0 +1,176 @@
+
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+
+/* Uniform block for #DRWSubivUboStorage. */
+layout(std140) uniform shader_data
+{
+ /* Offsets in the buffers data where the source and destination data start. */
+ int src_offset;
+ int dst_offset;
+
+ /* Parameters for the DRWPatchMap. */
+ int min_patch_face;
+ int max_patch_face;
+ int max_depth;
+ int patches_are_triangular;
+
+ /* Coarse topology information. */
+ int coarse_poly_count;
+ uint edge_loose_offset;
+
+ /* Subdiv topology information. */
+ uint num_subdiv_loops;
+
+ /* Subdivision settings. */
+ bool optimal_display;
+
+ /* Sculpt data. */
+ bool has_sculpt_mask;
+
+ /* Masks for the extra coarse face data. */
+ uint coarse_face_select_mask;
+ uint coarse_face_smooth_mask;
+ uint coarse_face_active_mask;
+ uint coarse_face_loopstart_mask;
+
+ /* Total number of elements to process. */
+ uint total_dispatch_size;
+};
+
+uint get_global_invocation_index()
+{
+ uint invocations_per_row = gl_WorkGroupSize.x * gl_NumWorkGroups.x;
+ return gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * invocations_per_row;
+}
+
+/* Structure for #CompressedPatchCoord. */
+struct BlenderPatchCoord {
+ int patch_index;
+ uint encoded_uv;
+};
+
+vec2 decode_uv(uint encoded_uv)
+{
+ float u = float((encoded_uv >> 16) & 0xFFFFu) / 65535.0;
+ float v = float(encoded_uv & 0xFFFFu) / 65535.0;
+ return vec2(u, v);
+}
+
+/* This structure is a carbon copy of OpenSubDiv's PatchTable::PatchHandle. */
+struct PatchHandle {
+ int array_index;
+ int patch_index;
+ int vertex_index;
+};
+
+/* This structure is a carbon copy of OpenSubDiv's PatchCoord. */
+struct PatchCoord {
+ int array_index;
+ int patch_index;
+ int vertex_index;
+ float u;
+ float v;
+};
+
+/* This structure is a carbon copy of OpenSubDiv's PatchCoord.QuadNode.
+ * Each child is a bitfield. */
+struct QuadNode {
+ uvec4 child;
+};
+
+bool is_set(uint i)
+{
+ /* QuadNode.Child.isSet is the first bit of the bitfield. */
+ return (i & 0x1u) != 0;
+}
+
+bool is_leaf(uint i)
+{
+ /* QuadNode.Child.isLeaf is the second bit of the bitfield. */
+ return (i & 0x2u) != 0;
+}
+
+uint get_index(uint i)
+{
+ /* QuadNode.Child.index is made of the remaining bits. */
+ return (i >> 2) & 0x3FFFFFFFu;
+}
+
+/* Duplicate of #PosNorLoop from the mesh extract CPU code.
+ * We do not use a vec3 for the position as it will be padded to a vec4 which is incompatible with
+ * the format. */
+struct PosNorLoop {
+ float x, y, z;
+ /* TODO(kevindietrich) : figure how to compress properly as GLSL does not have char/short types,
+ * bit operations get tricky. */
+ float nx, ny, nz;
+ float flag;
+};
+
+vec3 get_vertex_pos(PosNorLoop vertex_data)
+{
+ return vec3(vertex_data.x, vertex_data.y, vertex_data.z);
+}
+
+vec3 get_vertex_nor(PosNorLoop vertex_data)
+{
+ return vec3(vertex_data.nx, vertex_data.ny, vertex_data.nz);
+}
+
+void set_vertex_pos(inout PosNorLoop vertex_data, vec3 pos)
+{
+ vertex_data.x = pos.x;
+ vertex_data.y = pos.y;
+ vertex_data.z = pos.z;
+}
+
+void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor, uint flag)
+{
+ vertex_data.nx = nor.x;
+ vertex_data.ny = nor.y;
+ vertex_data.nz = nor.z;
+ vertex_data.flag = float(flag);
+}
+
+/* Set the vertex normal but preserve the existing flag. This is for when we compute manually the
+ * vertex normals when we cannot use the limit surface, in which case the flag and the normal are
+ * set by two separate compute pass. */
+void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor)
+{
+ set_vertex_nor(vertex_data, nor, 0);
+}
+
+#define ORIGINDEX_NONE -1
+
+#ifdef SUBDIV_POLYGON_OFFSET
+layout(std430, binding = 0) readonly buffer inputSubdivPolygonOffset
+{
+ uint subdiv_polygon_offset[];
+};
+
+/* Given the index of the subdivision quad, return the index of the corresponding coarse polygon.
+ * This uses subdiv_polygon_offset and since it is a growing list of offsets, we can use binary
+ * search to locate the right index. */
+uint coarse_polygon_index_from_subdiv_quad_index(uint subdiv_quad_index, uint coarse_poly_count)
+{
+ uint first = 0;
+ uint last = coarse_poly_count;
+
+ while (first != last) {
+ uint middle = (first + last) / 2;
+
+ if (subdiv_polygon_offset[middle] < subdiv_quad_index) {
+ first = middle + 1;
+ }
+ else {
+ last = middle;
+ }
+ }
+
+ if (subdiv_polygon_offset[first] == subdiv_quad_index) {
+ return first;
+ }
+
+ return first - 1;
+}
+#endif
diff --git a/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl
new file mode 100644
index 00000000000..575090472b1
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl
@@ -0,0 +1,56 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputVertexData
+{
+ PosNorLoop pos_nor[];
+};
+
+layout(std430, binding = 1) readonly buffer faceAdjacencyOffsets
+{
+ uint face_adjacency_offsets[];
+};
+
+layout(std430, binding = 2) readonly buffer faceAdjacencyLists
+{
+ uint face_adjacency_lists[];
+};
+
+layout(std430, binding = 3) writeonly buffer vertexNormals
+{
+ vec3 normals[];
+};
+
+void main()
+{
+ uint vertex_index = get_global_invocation_index();
+ if (vertex_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint first_adjacent_face_offset = face_adjacency_offsets[vertex_index];
+ uint number_of_adjacent_faces = face_adjacency_offsets[vertex_index + 1] -
+ first_adjacent_face_offset;
+
+ vec3 accumulated_normal = vec3(0.0);
+
+ /* For each adjacent face. */
+ for (uint i = 0; i < number_of_adjacent_faces; i++) {
+ uint adjacent_face = face_adjacency_lists[first_adjacent_face_offset + i];
+ uint start_loop_index = adjacent_face * 4;
+
+ /* Compute face normal. */
+ vec3 adjacent_verts[3];
+ for (uint j = 0; j < 3; j++) {
+ adjacent_verts[j] = get_vertex_pos(pos_nor[start_loop_index + j]);
+ }
+
+ vec3 face_normal = normalize(
+ cross(adjacent_verts[1] - adjacent_verts[0], adjacent_verts[2] - adjacent_verts[0]));
+ accumulated_normal += face_normal;
+ }
+
+ float weight = 1.0 / float(number_of_adjacent_faces);
+ vec3 normal = normalize(accumulated_normal);
+ normals[vertex_index] = normal;
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl
new file mode 100644
index 00000000000..84cd65d4161
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl
@@ -0,0 +1,34 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputNormals
+{
+ vec3 vertex_normals[];
+};
+
+layout(std430, binding = 1) readonly buffer inputSubdivVertLoopMap
+{
+ uint vert_loop_map[];
+};
+
+layout(std430, binding = 2) buffer outputPosNor
+{
+ PosNorLoop pos_nor[];
+};
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (int i = 0; i < 4; i++) {
+ uint subdiv_vert_index = vert_loop_map[start_loop_index + i];
+ vec3 nor = vertex_normals[subdiv_vert_index];
+ set_vertex_nor(pos_nor[start_loop_index + i], nor);
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
new file mode 100644
index 00000000000..5dd7decf663
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl
@@ -0,0 +1,416 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+/* Source buffer. */
+layout(std430, binding = 0) buffer src_buffer
+{
+ float srcVertexBuffer[];
+};
+
+/* #DRWPatchMap */
+layout(std430, binding = 1) readonly buffer inputPatchHandles
+{
+ PatchHandle input_patch_handles[];
+};
+
+layout(std430, binding = 2) readonly buffer inputQuadNodes
+{
+ QuadNode quad_nodes[];
+};
+
+layout(std430, binding = 3) readonly buffer inputPatchCoords
+{
+ BlenderPatchCoord patch_coords[];
+};
+
+layout(std430, binding = 4) readonly buffer inputVertOrigIndices
+{
+ int input_vert_origindex[];
+};
+
+/* Patch buffers. */
+layout(std430, binding = 5) buffer patchArray_buffer
+{
+ OsdPatchArray patchArrayBuffer[];
+};
+
+layout(std430, binding = 6) buffer patchIndex_buffer
+{
+ int patchIndexBuffer[];
+};
+
+layout(std430, binding = 7) buffer patchParam_buffer
+{
+ OsdPatchParam patchParamBuffer[];
+};
+
+ /* Output buffer(s). */
+
+#if defined(FVAR_EVALUATION)
+layout(std430, binding = 8) writeonly buffer outputFVarData
+{
+ vec2 output_fvar[];
+};
+#elif defined(FDOTS_EVALUATION)
+/* For face dots, we build the position, normals, and index buffers in one go. */
+
+/* vec3 is padded to vec4, but the format used for fdots does not have any padding. */
+struct FDotVert {
+ float x, y, z;
+};
+
+/* Same here, do not use vec3. */
+struct FDotNor {
+ float x, y, z;
+ float flag;
+};
+
+layout(std430, binding = 8) writeonly buffer outputVertices
+{
+ FDotVert output_verts[];
+};
+
+layout(std430, binding = 9) writeonly buffer outputNormals
+{
+ FDotNor output_nors[];
+};
+
+layout(std430, binding = 10) writeonly buffer outputFdotsIndices
+{
+ uint output_indices[];
+};
+
+layout(std430, binding = 11) readonly buffer extraCoarseFaceData
+{
+ uint extra_coarse_face_data[];
+};
+#else
+layout(std430, binding = 8) writeonly buffer outputVertexData
+{
+ PosNorLoop output_verts[];
+};
+#endif
+
+vec2 read_vec2(int index)
+{
+ vec2 result;
+ result.x = srcVertexBuffer[index * 2];
+ result.y = srcVertexBuffer[index * 2 + 1];
+ return result;
+}
+
+vec3 read_vec3(int index)
+{
+ vec3 result;
+ result.x = srcVertexBuffer[index * 3];
+ result.y = srcVertexBuffer[index * 3 + 1];
+ result.z = srcVertexBuffer[index * 3 + 2];
+ return result;
+}
+
+OsdPatchArray GetPatchArray(int arrayIndex)
+{
+ return patchArrayBuffer[arrayIndex];
+}
+
+OsdPatchParam GetPatchParam(int patchIndex)
+{
+ return patchParamBuffer[patchIndex];
+}
+
+/* ------------------------------------------------------------------------------
+ * Patch Coordinate lookup. Return an OsdPatchCoord for the given patch_index and uvs.
+ * This code is a port of the OpenSubdiv PatchMap lookup code.
+ */
+
+PatchHandle bogus_patch_handle()
+{
+ PatchHandle ret;
+ ret.array_index = -1;
+ ret.vertex_index = -1;
+ ret.patch_index = -1;
+ return ret;
+}
+
+int transformUVToQuadQuadrant(float median, inout float u, inout float v)
+{
+ int uHalf = (u >= median) ? 1 : 0;
+ if (uHalf != 0)
+ u -= median;
+
+ int vHalf = (v >= median) ? 1 : 0;
+ if (vHalf != 0)
+ v -= median;
+
+ return (vHalf << 1) | uHalf;
+}
+
+int transformUVToTriQuadrant(float median, inout float u, inout float v, inout bool rotated)
+{
+
+ if (!rotated) {
+ if (u >= median) {
+ u -= median;
+ return 1;
+ }
+ if (v >= median) {
+ v -= median;
+ return 2;
+ }
+ if ((u + v) >= median) {
+ rotated = true;
+ return 3;
+ }
+ return 0;
+ }
+ else {
+ if (u < median) {
+ v -= median;
+ return 1;
+ }
+ if (v < median) {
+ u -= median;
+ return 2;
+ }
+ u -= median;
+ v -= median;
+ if ((u + v) < median) {
+ rotated = false;
+ return 3;
+ }
+ return 0;
+ }
+}
+
+PatchHandle find_patch(int face_index, float u, float v)
+{
+ if (face_index < min_patch_face || face_index > max_patch_face) {
+ return bogus_patch_handle();
+ }
+
+ QuadNode node = quad_nodes[face_index - min_patch_face];
+
+ if (!is_set(node.child[0])) {
+ return bogus_patch_handle();
+ }
+
+ float median = 0.5;
+ bool tri_rotated = false;
+
+ for (int depth = 0; depth <= max_depth; ++depth, median *= 0.5) {
+ int quadrant = (patches_are_triangular != 0) ?
+ transformUVToTriQuadrant(median, u, v, tri_rotated) :
+ transformUVToQuadQuadrant(median, u, v);
+
+ if (is_leaf(node.child[quadrant])) {
+ return input_patch_handles[get_index(node.child[quadrant])];
+ }
+
+ node = quad_nodes[get_index(node.child[quadrant])];
+ }
+}
+
+OsdPatchCoord bogus_patch_coord(int face_index, float u, float v)
+{
+ OsdPatchCoord coord;
+ coord.arrayIndex = 0;
+ coord.patchIndex = face_index;
+ coord.vertIndex = 0;
+ coord.s = u;
+ coord.t = v;
+ return coord;
+}
+
+OsdPatchCoord GetPatchCoord(int face_index, float u, float v)
+{
+ PatchHandle patch_handle = find_patch(face_index, u, v);
+
+ if (patch_handle.array_index == -1) {
+ return bogus_patch_coord(face_index, u, v);
+ }
+
+ OsdPatchCoord coord;
+ coord.arrayIndex = patch_handle.array_index;
+ coord.patchIndex = patch_handle.patch_index;
+ coord.vertIndex = patch_handle.vertex_index;
+ coord.s = u;
+ coord.t = v;
+ return coord;
+}
+
+/* ------------------------------------------------------------------------------
+ * Patch evaluation. Note that the 1st and 2nd derivatives are always computed, although we
+ * only return and use the 1st derivatives if adaptive patches are used. This could
+ * perhaps be optimized.
+ */
+
+#if defined(FVAR_EVALUATION)
+void evaluate_patches_limits(int patch_index, float u, float v, inout vec2 dst)
+{
+ OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
+ OsdPatchArray array = GetPatchArray(coord.arrayIndex);
+ OsdPatchParam param = GetPatchParam(coord.patchIndex);
+
+ int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
+
+ float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
+ int nPoints = OsdEvaluatePatchBasis(
+ patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
+
+ int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);
+
+ for (int cv = 0; cv < nPoints; ++cv) {
+ int index = patchIndexBuffer[indexBase + cv];
+ vec2 src_fvar = read_vec2(src_offset + index);
+ dst += src_fvar * wP[cv];
+ }
+}
+#else
+void evaluate_patches_limits(
+ int patch_index, float u, float v, inout vec3 dst, inout vec3 du, inout vec3 dv)
+{
+ OsdPatchCoord coord = GetPatchCoord(patch_index, u, v);
+ OsdPatchArray array = GetPatchArray(coord.arrayIndex);
+ OsdPatchParam param = GetPatchParam(coord.patchIndex);
+
+ int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
+
+ float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
+ int nPoints = OsdEvaluatePatchBasis(
+ patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
+
+ int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase);
+
+ for (int cv = 0; cv < nPoints; ++cv) {
+ int index = patchIndexBuffer[indexBase + cv];
+ vec3 src_vertex = read_vec3(index);
+
+ dst += src_vertex * wP[cv];
+ du += src_vertex * wDu[cv];
+ dv += src_vertex * wDv[cv];
+ }
+}
+#endif
+
+/* ------------------------------------------------------------------------------
+ * Entry point.
+ */
+
+#if defined(FVAR_EVALUATION)
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
+ vec2 fvar = vec2(0.0);
+
+ BlenderPatchCoord patch_co = patch_coords[loop_index];
+ vec2 uv = decode_uv(patch_co.encoded_uv);
+
+ evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, fvar);
+ output_fvar[dst_offset + loop_index] = fvar;
+ }
+}
+#elif defined(FDOTS_EVALUATION)
+bool is_face_selected(uint coarse_quad_index)
+{
+ return (extra_coarse_face_data[coarse_quad_index] & coarse_face_select_mask) != 0;
+}
+
+bool is_face_active(uint coarse_quad_index)
+{
+ return (extra_coarse_face_data[coarse_quad_index] & coarse_face_active_mask) != 0;
+}
+
+float get_face_flag(uint coarse_quad_index)
+{
+ if (is_face_active(coarse_quad_index)) {
+ return -1.0;
+ }
+
+ if (is_face_selected(coarse_quad_index)) {
+ return 1.0;
+ }
+
+ return 0.0;
+}
+
+void main()
+{
+ /* We execute for each coarse quad. */
+ uint coarse_quad_index = get_global_invocation_index();
+ if (coarse_quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ BlenderPatchCoord patch_co = patch_coords[coarse_quad_index];
+ vec2 uv = decode_uv(patch_co.encoded_uv);
+
+ vec3 pos = vec3(0.0);
+ vec3 du = vec3(0.0);
+ vec3 dv = vec3(0.0);
+ evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv);
+ vec3 nor = normalize(cross(du, dv));
+
+ FDotVert vert;
+ vert.x = pos.x;
+ vert.y = pos.y;
+ vert.z = pos.z;
+
+ FDotNor fnor;
+ fnor.x = nor.x;
+ fnor.y = nor.y;
+ fnor.z = nor.z;
+ fnor.flag = get_face_flag(coarse_quad_index);
+
+ output_verts[coarse_quad_index] = vert;
+ output_nors[coarse_quad_index] = fnor;
+ output_indices[coarse_quad_index] = coarse_quad_index;
+}
+#else
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
+ vec3 pos = vec3(0.0);
+ vec3 du = vec3(0.0);
+ vec3 dv = vec3(0.0);
+
+ BlenderPatchCoord patch_co = patch_coords[loop_index];
+ vec2 uv = decode_uv(patch_co.encoded_uv);
+
+ evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv);
+
+# if defined(LIMIT_NORMALS)
+ vec3 nor = normalize(cross(du, dv));
+# else
+ /* This will be computed later. */
+ vec3 nor = vec3(0.0);
+# endif
+
+ int origindex = input_vert_origindex[loop_index];
+ uint flag = 0;
+ if (origindex == -1) {
+ flag = -1;
+ }
+
+ PosNorLoop vertex_data;
+ set_vertex_pos(vertex_data, pos);
+ set_vertex_nor(vertex_data, nor, flag);
+ output_verts[loop_index] = vertex_data;
+ }
+}
+#endif
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl
new file mode 100644
index 00000000000..6c76cd41ca4
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl
@@ -0,0 +1,97 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputVertexData
+{
+ PosNorLoop pos_nor[];
+};
+
+layout(std430, binding = 1) readonly buffer inputEdgeIndex
+{
+ uint input_edge_index[];
+};
+
+layout(std430, binding = 2) writeonly buffer outputEdgeFactors
+{
+#ifdef GPU_AMD_DRIVER_BYTE_BUG
+ float output_edge_fac[];
+#else
+ uint output_edge_fac[];
+#endif
+};
+
+void write_vec4(uint index, vec4 edge_facs)
+{
+#ifdef GPU_AMD_DRIVER_BYTE_BUG
+ for (uint i = 0; i < 4; i++) {
+ output_edge_fac[index + i] = edge_facs[i];
+ }
+#else
+ /* Use same scaling as in extract_edge_fac_iter_poly_mesh. */
+ uint a = uint(clamp(edge_facs.x * 253.0 + 1.0, 0.0, 255.0));
+ uint b = uint(clamp(edge_facs.y * 253.0 + 1.0, 0.0, 255.0));
+ uint c = uint(clamp(edge_facs.z * 253.0 + 1.0, 0.0, 255.0));
+ uint d = uint(clamp(edge_facs.w * 253.0 + 1.0, 0.0, 255.0));
+ uint packed_edge_fac = a << 24 | b << 16 | c << 8 | d;
+ output_edge_fac[index] = packed_edge_fac;
+#endif
+}
+
+/* From extract_mesh_vbo_edge_fac.cc, keep in sync! */
+float loop_edge_factor_get(vec3 f_no, vec3 v_co, vec3 v_no, vec3 v_next_co)
+{
+ vec3 evec = v_next_co - v_co;
+ vec3 enor = normalize(cross(v_no, evec));
+ float d = abs(dot(enor, f_no));
+ /* Re-scale to the slider range. */
+ d *= (1.0 / 0.065);
+ return clamp(d, 0.0, 1.0);
+}
+
+float compute_line_factor(uint start_loop_index, uint corner_index, vec3 face_normal)
+{
+ uint vertex_index = start_loop_index + corner_index;
+ uint edge_index = input_edge_index[vertex_index];
+
+ if (edge_index == -1 && optimal_display) {
+ return 0.0;
+ }
+
+ /* Mod 4 so we loop back at the first vertex on the last loop index (3), but only the corner
+ * index needs to be wrapped. */
+ uint next_vertex_index = start_loop_index + (corner_index + 1) % 4;
+ vec3 vertex_pos = get_vertex_pos(pos_nor[vertex_index]);
+ vec3 vertex_nor = get_vertex_nor(pos_nor[vertex_index]);
+ vec3 next_vertex_pos = get_vertex_pos(pos_nor[next_vertex_index]);
+ return loop_edge_factor_get(face_normal, vertex_pos, vertex_nor, next_vertex_pos);
+}
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ /* The start index of the loop is quad_index * 4. */
+ uint start_loop_index = quad_index * 4;
+
+ /* First compute the face normal, we need it to compute the bihedral edge angle. */
+ vec3 v0 = get_vertex_pos(pos_nor[start_loop_index + 0]);
+ vec3 v1 = get_vertex_pos(pos_nor[start_loop_index + 1]);
+ vec3 v2 = get_vertex_pos(pos_nor[start_loop_index + 2]);
+ vec3 face_normal = normalize(cross(v1 - v0, v2 - v0));
+
+ vec4 edge_facs = vec4(0.0);
+ for (int i = 0; i < 4; i++) {
+ edge_facs[i] = compute_line_factor(start_loop_index, i, face_normal);
+ }
+
+#ifdef GPU_AMD_DRIVER_BYTE_BUG
+ write_vec4(start_loop_index, edge_facs);
+#else
+ /* When packed into bytes, the index is the same as for the quad. */
+ write_vec4(quad_index, edge_facs);
+#endif
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl
new file mode 100644
index 00000000000..ea73b9482d3
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl
@@ -0,0 +1,80 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 0) readonly buffer inputVerts
+{
+ PosNorLoop pos_nor[];
+};
+
+layout(std430, binding = 1) readonly buffer inputUVs
+{
+ vec2 uvs[];
+};
+
+/* Mirror of #UVStretchAngle in the C++ code, but using floats until proper data compression
+ * is implemented for all subdivision data. */
+struct UVStretchAngle {
+ float angle;
+ float uv_angle0;
+ float uv_angle1;
+};
+
+layout(std430, binding = 2) writeonly buffer outputStretchAngles
+{
+ UVStretchAngle uv_stretches[];
+};
+
+#define M_PI 3.1415926535897932
+#define M_1_PI 0.31830988618379067154
+
+/* Adapted from BLI_math_vector.h */
+float angle_normalized_v3v3(vec3 v1, vec3 v2)
+{
+ /* this is the same as acos(dot_v3v3(v1, v2)), but more accurate */
+ bool q = (dot(v1, v2) >= 0.0);
+ vec3 v = (q) ? (v1 - v2) : (v1 + v2);
+ float a = 2.0 * asin(length(v) / 2.0);
+ return (q) ? a : M_PI - a;
+}
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (uint i = 0; i < 4; i++) {
+ uint cur_loop_index = start_loop_index + i;
+ uint next_loop_index = start_loop_index + (i + 1) % 4;
+ uint prev_loop_index = start_loop_index + (i + 3) % 4;
+
+ /* Compute 2d edge vectors from UVs. */
+ vec2 cur_uv = uvs[src_offset + cur_loop_index];
+ vec2 next_uv = uvs[src_offset + next_loop_index];
+ vec2 prev_uv = uvs[src_offset + prev_loop_index];
+
+ vec2 norm_uv_edge0 = normalize(prev_uv - cur_uv);
+ vec2 norm_uv_edge1 = normalize(cur_uv - next_uv);
+
+ /* Compute 3d edge vectors from positions. */
+ vec3 cur_pos = get_vertex_pos(pos_nor[cur_loop_index]);
+ vec3 next_pos = get_vertex_pos(pos_nor[next_loop_index]);
+ vec3 prev_pos = get_vertex_pos(pos_nor[prev_loop_index]);
+
+ vec3 norm_pos_edge0 = normalize(prev_pos - cur_pos);
+ vec3 norm_pos_edge1 = normalize(cur_pos - next_pos);
+
+ /* Compute stretches, this logic is adapted from #edituv_get_edituv_stretch_angle.
+ * Keep in sync! */
+ UVStretchAngle stretch;
+ stretch.uv_angle0 = atan(norm_uv_edge0.y, norm_uv_edge0.x) * M_1_PI;
+ stretch.uv_angle1 = atan(norm_uv_edge1.y, norm_uv_edge1.x) * M_1_PI;
+ stretch.angle = angle_normalized_v3v3(norm_pos_edge0, norm_pos_edge1) * M_1_PI;
+
+ uv_stretches[cur_loop_index] = stretch;
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl
new file mode 100644
index 00000000000..e897fb3f3c0
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl
@@ -0,0 +1,31 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 1) readonly buffer inputCoarseData
+{
+ float coarse_stretch_area[];
+};
+
+layout(std430, binding = 2) writeonly buffer outputSubdivData
+{
+ float subdiv_stretch_area[];
+};
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ /* The start index of the loop is quad_index * 4. */
+ uint start_loop_index = quad_index * 4;
+
+ uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
+ coarse_poly_count);
+
+ for (int i = 0; i < 4; i++) {
+ subdiv_stretch_area[start_loop_index + i] = coarse_stretch_area[coarse_quad_index];
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl
new file mode 100644
index 00000000000..41a8df3cf82
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl
@@ -0,0 +1,52 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+layout(std430, binding = 1) readonly buffer inputVertexData
+{
+ PosNorLoop pos_nor[];
+};
+
+layout(std430, binding = 2) readonly buffer extraCoarseFaceData
+{
+ uint extra_coarse_face_data[];
+};
+
+layout(std430, binding = 3) writeonly buffer outputLoopNormals
+{
+ vec3 output_lnor[];
+};
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ /* The start index of the loop is quad_index * 4. */
+ uint start_loop_index = quad_index * 4;
+
+ uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index,
+ coarse_poly_count);
+
+ if ((extra_coarse_face_data[coarse_quad_index] & coarse_face_smooth_mask) != 0) {
+ /* Face is smooth, use vertex normals. */
+ for (int i = 0; i < 4; i++) {
+ PosNorLoop pos_nor_loop = pos_nor[start_loop_index + i];
+ output_lnor[start_loop_index + i] = get_vertex_nor(pos_nor_loop);
+ }
+ }
+ else {
+ /* Face is flat shaded, compute flat face normal from an inscribed triangle. */
+ vec3 verts[3];
+ for (int i = 0; i < 3; i++) {
+ verts[i] = get_vertex_pos(pos_nor[start_loop_index + i]);
+ }
+
+ vec3 face_normal = normalize(cross(verts[1] - verts[0], verts[2] - verts[0]));
+ for (int i = 0; i < 4; i++) {
+ output_lnor[start_loop_index + i] = face_normal;
+ }
+ }
+}
diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl
new file mode 100644
index 00000000000..7182ce57ad3
--- /dev/null
+++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl
@@ -0,0 +1,47 @@
+
+/* To be compile with common_subdiv_lib.glsl */
+
+struct SculptData {
+ uint face_set_color;
+ float mask;
+};
+
+layout(std430, binding = 0) readonly restrict buffer sculptMask
+{
+ float sculpt_mask[];
+};
+
+layout(std430, binding = 1) readonly restrict buffer faceSetColor
+{
+ uint face_set_color[];
+};
+
+layout(std430, binding = 2) writeonly restrict buffer sculptData
+{
+ SculptData sculpt_data[];
+};
+
+void main()
+{
+ /* We execute for each quad. */
+ uint quad_index = get_global_invocation_index();
+ if (quad_index >= total_dispatch_size) {
+ return;
+ }
+
+ uint start_loop_index = quad_index * 4;
+
+ for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) {
+ SculptData data;
+ data.face_set_color = face_set_color[loop_index];
+
+ if (has_sculpt_mask) {
+ data.mask = sculpt_mask[loop_index];
+ }
+ else {
+ data.mask = 0.0;
+ }
+
+ sculpt_data[loop_index] = data;
+ }
+}
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index f509898f2ee..bdcbac80699 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -879,10 +879,10 @@ EnumPropertyItem prop_driver_create_mapping_types[] = {
};
/* Filtering callback for driver mapping types enum */
-static const EnumPropertyItem *driver_mapping_type_itemsf(bContext *C,
- PointerRNA *UNUSED(owner_ptr),
- PropertyRNA *UNUSED(owner_prop),
- bool *r_free)
+static const EnumPropertyItem *driver_mapping_type_itemf(bContext *C,
+ PointerRNA *UNUSED(owner_ptr),
+ PropertyRNA *UNUSED(owner_prop),
+ bool *r_free)
{
EnumPropertyItem *input = prop_driver_create_mapping_types;
EnumPropertyItem *item = NULL;
@@ -961,7 +961,7 @@ static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_typ
}
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
if (path) {
@@ -1039,7 +1039,7 @@ static void UNUSED_FUNCTION(ANIM_OT_driver_button_add_menu)(wmOperatorType *ot)
0,
"Mapping Type",
"Method used to match target and driven properties");
- RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf);
+ RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemf);
}
/* Add Driver Button Operator ------------------------ */
@@ -1055,7 +1055,7 @@ static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent *
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
/* 1) Create a new "empty" driver for this property */
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
bool changed = false;
@@ -1115,7 +1115,7 @@ static int remove_driver_button_exec(bContext *C, wmOperator *op)
}
if (ptr.owner_id && ptr.data && prop) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
changed = ANIM_remove_driver(op->reports, ptr.owner_id, path, index, 0);
@@ -1200,7 +1200,7 @@ static int copy_driver_button_exec(bContext *C, wmOperator *op)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
/* only copy the driver for the button that this was involved for */
@@ -1244,7 +1244,7 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op)
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
+ char *path = RNA_path_from_ID_to_property(&ptr, prop);
if (path) {
/* only copy the driver for the button that this was involved for */
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index dc5d71b5a1e..8aac1e9b779 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -345,6 +345,71 @@ static bool find_fcurve_segment(FCurve *fcu,
return in_segment;
}
+/* Return a list of FCurveSegment with a start index and a length.
+ * A segment is a continuous selection of keyframes.
+ * Keys that have BEZT_FLAG_IGNORE_TAG set are treated as unselected.
+ * The caller is responsible for freeing the memory. */
+ListBase find_fcurve_segments(FCurve *fcu)
+{
+ ListBase segments = {NULL, NULL};
+ int segment_start_idx = 0;
+ int segment_len = 0;
+ int current_index = 0;
+
+ while (find_fcurve_segment(fcu, current_index, &segment_start_idx, &segment_len)) {
+ FCurveSegment *segment;
+ segment = MEM_callocN(sizeof(*segment), "FCurveSegment");
+ segment->start_index = segment_start_idx;
+ segment->length = segment_len;
+ BLI_addtail(&segments, segment);
+ current_index = segment_start_idx + segment_len;
+ }
+ return segments;
+}
+
+static BezTriple fcurve_segment_start_get(FCurve *fcu, int index)
+{
+ BezTriple start_bezt = index - 1 >= 0 ? fcu->bezt[index - 1] : fcu->bezt[index];
+ return start_bezt;
+}
+
+static BezTriple fcurve_segment_end_get(FCurve *fcu, int index)
+{
+ BezTriple end_bezt = index < fcu->totvert ? fcu->bezt[index] : fcu->bezt[index - 1];
+ return end_bezt;
+}
+
+/* ---------------- */
+
+void blend_to_neighbor_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
+{
+ const float blend_factor = fabs(factor * 2 - 1);
+ BezTriple target_bezt;
+ /* Find which key to blend towards. */
+ if (factor < 0.5f) {
+ target_bezt = fcurve_segment_start_get(fcu, segment->start_index);
+ }
+ else {
+ target_bezt = fcurve_segment_end_get(fcu, segment->start_index + segment->length);
+ }
+ /* Blend each key individually. */
+ for (int i = segment->start_index; i < segment->start_index + segment->length; i++) {
+ fcu->bezt[i].vec[1][1] = interpf(target_bezt.vec[1][1], fcu->bezt[i].vec[1][1], blend_factor);
+ }
+}
+
+/* ---------------- */
+
+void breakdown_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
+{
+ BezTriple left_bezt = fcurve_segment_start_get(fcu, segment->start_index);
+ BezTriple right_bezt = fcurve_segment_end_get(fcu, segment->start_index + segment->length);
+
+ for (int i = segment->start_index; i < segment->start_index + segment->length; i++) {
+ fcu->bezt[i].vec[1][1] = interpf(right_bezt.vec[1][1], left_bezt.vec[1][1], factor);
+ }
+}
+
/* ---------------- */
/* Check if the keyframe interpolation type is supported */
@@ -440,15 +505,12 @@ bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max)
fcu->bezt[i].f2 &= ~BEZT_FLAG_TEMP_TAG;
}
- /* Only decimate the individual selected curve segments. */
- int segment_start_idx = 0;
- int segment_len = 0;
- int current_index = 0;
-
- while (find_fcurve_segment(fcu, current_index, &segment_start_idx, &segment_len)) {
- decimate_fcurve_segment(fcu, segment_start_idx, segment_len, remove_ratio, error_sq_max);
- current_index = segment_start_idx + segment_len;
+ ListBase segments = find_fcurve_segments(fcu);
+ LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
+ decimate_fcurve_segment(
+ fcu, segment->start_index, segment->length, remove_ratio, error_sq_max);
}
+ BLI_freelistN(&segments);
uint old_totvert = fcu->totvert;
fcu->bezt = NULL;
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 772fe8f3196..8bd6c9f54fd 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -160,7 +160,7 @@ static bool pose_has_protected_selected(Object *ob, short warn)
bArmature *arm = ob->data;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone && (pchan->bone->layer & arm->layer)) {
+ if (pchan->bone && BKE_pose_is_layer_visible(arm, pchan)) {
if (pchan->bone->layer & arm->layer_protected) {
if (pchan->bone->flag & BONE_SELECTED) {
break;
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 646356e7a45..dc96c777be0 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -1070,7 +1070,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld,
else if (pchan->bone) {
/* only ok if bone is visible and selected */
if ((pchan->bone->flag & BONE_SELECTED) && (pchan->bone->flag & BONE_HIDDEN_P) == 0 &&
- (pchan->bone->layer & arm->layer)) {
+ BKE_pose_is_layer_visible(arm, pchan)) {
ok = 1;
}
}
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 17347aa57fe..0b889149f9d 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -746,7 +746,7 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
bool changed = false;
- pchan_act = BKE_pose_channel_active(ob);
+ pchan_act = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan_act == NULL) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/asset/intern/asset_indexer.cc b/source/blender/editors/asset/intern/asset_indexer.cc
index 4107d28b5e3..a9c6e3798c9 100644
--- a/source/blender/editors/asset/intern/asset_indexer.cc
+++ b/source/blender/editors/asset/intern/asset_indexer.cc
@@ -145,7 +145,7 @@ struct AssetEntryReader {
/**
* \brief Lookup table containing the elements of the entry.
*/
- ObjectValue::Lookup lookup;
+ DictionaryValue::Lookup lookup;
StringRefNull get_name_with_idcode() const
{
@@ -153,7 +153,7 @@ struct AssetEntryReader {
}
public:
- AssetEntryReader(const ObjectValue &entry) : lookup(entry.create_lookup())
+ AssetEntryReader(const DictionaryValue &entry) : lookup(entry.create_lookup())
{
}
@@ -204,7 +204,7 @@ struct AssetEntryReader {
void add_tags_to_meta_data(AssetMetaData *asset_data) const
{
- const ObjectValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS);
+ const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS);
if (value_ptr == nullptr) {
return;
}
@@ -220,10 +220,10 @@ struct AssetEntryReader {
struct AssetEntryWriter {
private:
- ObjectValue::Items &attributes;
+ DictionaryValue::Items &attributes;
public:
- AssetEntryWriter(ObjectValue &entry) : attributes(entry.elements())
+ AssetEntryWriter(DictionaryValue &entry) : attributes(entry.elements())
{
}
@@ -301,7 +301,7 @@ static void init_value_from_file_indexer_entry(AssetEntryWriter &result,
/* TODO: asset_data.IDProperties */
}
-static void init_value_from_file_indexer_entries(ObjectValue &result,
+static void init_value_from_file_indexer_entries(DictionaryValue &result,
const FileIndexerEntries &indexer_entries)
{
ArrayValue *entries = new ArrayValue();
@@ -313,7 +313,7 @@ static void init_value_from_file_indexer_entries(ObjectValue &result,
if (indexer_entry->datablock_info.asset_data == nullptr) {
continue;
}
- ObjectValue *entry_value = new ObjectValue();
+ DictionaryValue *entry_value = new DictionaryValue();
AssetEntryWriter entry(*entry_value);
init_value_from_file_indexer_entry(entry, indexer_entry);
items.append_as(entry_value);
@@ -326,7 +326,7 @@ static void init_value_from_file_indexer_entries(ObjectValue &result,
return;
}
- ObjectValue::Items &attributes = result.elements();
+ DictionaryValue::Items &attributes = result.elements();
attributes.append_as(std::pair(ATTRIBUTE_ENTRIES, entries));
}
@@ -366,10 +366,10 @@ static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry,
}
static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries,
- const ObjectValue &value)
+ const DictionaryValue &value)
{
- const ObjectValue::Lookup attributes = value.create_lookup();
- const ObjectValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES);
+ const DictionaryValue::Lookup attributes = value.create_lookup();
+ const DictionaryValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES);
BLI_assert(entries_value != nullptr);
if (entries_value == nullptr) {
@@ -379,7 +379,7 @@ static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries,
int num_entries_read = 0;
const ArrayValue::Items elements = (*entries_value)->as_array_value()->elements();
for (ArrayValue::Item element : elements) {
- const AssetEntryReader asset_entry(*element->as_object_value());
+ const AssetEntryReader asset_entry(*element->as_dictionary_value());
FileIndexerEntry *entry = static_cast<FileIndexerEntry *>(
MEM_callocN(sizeof(FileIndexerEntry), __func__));
@@ -534,9 +534,9 @@ struct AssetIndex {
/**
* `blender::io::serialize::Value` representing the contents of an index file.
*
- * Value is used over #ObjectValue as the contents of the index could be corrupted and doesn't
- * represent an object. In case corrupted files are detected the `get_version` would return
- * `UNKNOWN_VERSION`.
+ * Value is used over #DictionaryValue as the contents of the index could be corrupted and
+ * doesn't represent an object. In case corrupted files are detected the `get_version` would
+ * return `UNKNOWN_VERSION`.
*/
std::unique_ptr<Value> contents;
@@ -546,8 +546,8 @@ struct AssetIndex {
*/
AssetIndex(const FileIndexerEntries &indexer_entries)
{
- std::unique_ptr<ObjectValue> root = std::make_unique<ObjectValue>();
- ObjectValue::Items &root_attributes = root->elements();
+ std::unique_ptr<DictionaryValue> root = std::make_unique<DictionaryValue>();
+ DictionaryValue::Items &root_attributes = root->elements();
root_attributes.append_as(std::pair(ATTRIBUTE_VERSION, new IntValue(CURRENT_VERSION)));
init_value_from_file_indexer_entries(*root, indexer_entries);
@@ -564,12 +564,12 @@ struct AssetIndex {
int get_version() const
{
- const ObjectValue *root = contents->as_object_value();
+ const DictionaryValue *root = contents->as_dictionary_value();
if (root == nullptr) {
return UNKNOWN_VERSION;
}
- const ObjectValue::Lookup attributes = root->create_lookup();
- const ObjectValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION);
+ const DictionaryValue::Lookup attributes = root->create_lookup();
+ const DictionaryValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION);
if (version_value == nullptr) {
return UNKNOWN_VERSION;
}
@@ -588,7 +588,7 @@ struct AssetIndex {
*/
int extract_into(FileIndexerEntries &indexer_entries) const
{
- const ObjectValue *root = contents->as_object_value();
+ const DictionaryValue *root = contents->as_dictionary_value();
const int num_entries_read = init_indexer_entries_from_value(indexer_entries, *root);
return num_entries_read;
}
@@ -742,16 +742,15 @@ static void update_index(const char *filename, FileIndexerEntries *entries, void
static void *init_user_data(const char *root_directory, size_t root_directory_maxlen)
{
- AssetLibraryIndex *library_index = OBJECT_GUARDED_NEW(
- AssetLibraryIndex,
- StringRef(root_directory, BLI_strnlen(root_directory, root_directory_maxlen)));
+ AssetLibraryIndex *library_index = MEM_new<AssetLibraryIndex>(
+ __func__, StringRef(root_directory, BLI_strnlen(root_directory, root_directory_maxlen)));
library_index->init_unused_index_files();
return library_index;
}
static void free_user_data(void *user_data)
{
- OBJECT_GUARDED_DELETE(user_data, AssetLibraryIndex);
+ MEM_delete((AssetLibraryIndex *)user_data);
}
static void filelist_finished(void *user_data)
diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc
index e4edff19a21..f7755aa9fea 100644
--- a/source/blender/editors/asset/intern/asset_ops.cc
+++ b/source/blender/editors/asset/intern/asset_ops.cc
@@ -934,10 +934,10 @@ static bool has_external_files(Main *bmain, struct ReportList *reports)
BKE_reportf(
callback_info.reports,
RPT_ERROR,
- "Unable to copy bundle due to %ld external dependencies; more details on the console",
- callback_info.external_files.size());
- printf("Unable to copy bundle due to %ld external dependencies:\n",
- callback_info.external_files.size());
+ "Unable to copy bundle due to %zu external dependencies; more details on the console",
+ (size_t)callback_info.external_files.size());
+ printf("Unable to copy bundle due to %zu external dependencies:\n",
+ (size_t)callback_info.external_files.size());
for (const std::string &path : callback_info.external_files) {
printf(" \"%s\"\n", path.c_str());
}
diff --git a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
index f136c08f129..8790c907f05 100644
--- a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
+++ b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc
@@ -88,12 +88,13 @@ AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle)
}
BLI_assert(handle->file_data->asset_data != nullptr);
return reinterpret_cast<AssetTempIDConsumer *>(
- OBJECT_GUARDED_NEW(AssetTemporaryIDConsumer, *handle));
+ MEM_new<AssetTemporaryIDConsumer>(__func__, *handle));
}
void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer)
{
- OBJECT_GUARDED_SAFE_DELETE(*consumer, AssetTemporaryIDConsumer);
+ MEM_delete(reinterpret_cast<AssetTemporaryIDConsumer *>(*consumer));
+ *consumer = nullptr;
}
ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer_,
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index 3705ea38e11..ae00fc41f40 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -165,7 +165,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
immUniformColor3fvAlpha(ink, ink[3]);
immBegin(GPU_PRIM_POINTS, 1);
- immVertex2fv(pos, &pt->x);
+ immVertex2fv(pos, pt->m_xy);
}
else {
float oldpressure = points[0].pressure;
@@ -191,7 +191,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
if (fabsf(pt->pressure - oldpressure) > 0.2f) {
/* need to have 2 points to avoid immEnd assert error */
if (draw_points < 2) {
- immVertex2fv(pos, &(pt - 1)->x);
+ immVertex2fv(pos, (pt - 1)->m_xy);
}
immEnd();
@@ -202,7 +202,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
/* need to roll-back one point to ensure that there are no gaps in the stroke */
if (i != 0) {
- immVertex2fv(pos, &(pt - 1)->x);
+ immVertex2fv(pos, (pt - 1)->m_xy);
draw_points++;
}
@@ -210,12 +210,12 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
}
/* now the point we want */
- immVertex2fv(pos, &pt->x);
+ immVertex2fv(pos, pt->m_xy);
draw_points++;
}
/* need to have 2 points to avoid immEnd assert error */
if (draw_points < 2) {
- immVertex2fv(pos, &(pt - 1)->x);
+ immVertex2fv(pos, (pt - 1)->m_xy);
}
}
@@ -227,14 +227,14 @@ static void annotation_draw_stroke_buffer(bGPdata *gps,
if ((sflag & GP_STROKE_USE_ARROW_END) &&
(runtime.arrow_end_style != GP_STROKE_ARROWSTYLE_NONE)) {
float end[2];
- copy_v2_fl2(end, points[1].x, points[1].y);
+ copy_v2_v2(end, points[1].m_xy);
annotation_draw_stroke_arrow_buffer(pos, end, runtime.arrow_end, runtime.arrow_end_style);
}
/* Draw starting arrow stroke. */
if ((sflag & GP_STROKE_USE_ARROW_START) &&
(runtime.arrow_start_style != GP_STROKE_ARROWSTYLE_NONE)) {
float start[2];
- copy_v2_fl2(start, points[0].x, points[0].y);
+ copy_v2_v2(start, points[0].m_xy);
annotation_draw_stroke_arrow_buffer(
pos, start, runtime.arrow_start, runtime.arrow_start_style);
}
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index fbc44ed58d8..196cd1028ea 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -426,25 +426,25 @@ static void annotation_smooth_buffer(tGPsdata *p, float inf, int idx)
/* Compute smoothed coordinate by taking the ones nearby */
if (pta) {
- copy_v2_v2(a, &pta->x);
+ copy_v2_v2(a, pta->m_xy);
madd_v2_v2fl(sco, a, average_fac);
}
if (ptb) {
- copy_v2_v2(b, &ptb->x);
+ copy_v2_v2(b, ptb->m_xy);
madd_v2_v2fl(sco, b, average_fac);
}
if (ptc) {
- copy_v2_v2(c, &ptc->x);
+ copy_v2_v2(c, ptc->m_xy);
madd_v2_v2fl(sco, c, average_fac);
}
if (ptd) {
- copy_v2_v2(d, &ptd->x);
+ copy_v2_v2(d, ptd->m_xy);
madd_v2_v2fl(sco, d, average_fac);
}
/* Based on influence factor, blend between original and optimal smoothed coordinate */
interp_v2_v2v2(c, c, sco, inf);
- copy_v2_v2(&ptc->x, c);
+ copy_v2_v2(ptc->m_xy, c);
}
static void annotation_stroke_arrow_calc_points_segment(float stroke_points[8],
@@ -492,8 +492,8 @@ static void annotation_stroke_arrow_calc_points(tGPspoint *point,
case GP_STROKE_ARROWSTYLE_CLOSED:
mul_v2_fl(norm_dir, arrow_length);
if (point != NULL) {
- add_v2_v2(&point->x, norm_dir);
- copy_v2_v2(corner, &point->x);
+ add_v2_v2(point->m_xy, norm_dir);
+ copy_v2_v2(corner, point->m_xy);
}
annotation_stroke_arrow_calc_points_segment(stroke_points,
corner,
@@ -507,8 +507,8 @@ static void annotation_stroke_arrow_calc_points(tGPspoint *point,
case GP_STROKE_ARROWSTYLE_SQUARE:
mul_v2_fl(norm_dir, arrow_length * 1.5f);
if (point != NULL) {
- add_v2_v2(&point->x, norm_dir);
- copy_v2_v2(corner, &point->x);
+ add_v2_v2(point->m_xy, norm_dir);
+ copy_v2_v2(corner, point->m_xy);
}
annotation_stroke_arrow_calc_points_segment(stroke_points,
corner,
@@ -544,7 +544,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = (tGPspoint *)(gpd->runtime.sbuffer);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -560,7 +560,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -573,10 +573,10 @@ static short annotation_stroke_addpoint(tGPsdata *p,
if (gpd->runtime.sbuffer_sflag & (GP_STROKE_USE_ARROW_START | GP_STROKE_USE_ARROW_END)) {
/* Store start and end point coords for arrows. */
float end[2];
- copy_v2_v2(end, &pt->x);
+ copy_v2_v2(end, pt->m_xy);
pt = ((tGPspoint *)(gpd->runtime.sbuffer));
float start[2];
- copy_v2_v2(start, &pt->x);
+ copy_v2_v2(start, pt->m_xy);
/* Arrow end corner. */
if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) {
@@ -609,7 +609,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
pt->pressure = pressure;
/* Unused for annotations, but initialize for easier conversions to GP Object. */
pt->strength = 1.0f;
@@ -636,7 +636,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
pt = (tGPspoint *)gpd->runtime.sbuffer;
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -678,7 +678,7 @@ static short annotation_stroke_addpoint(tGPsdata *p,
}
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
+ annotation_stroke_convertcoords(p, pt->m_xy, &pts->x, NULL);
/* copy pressure and time */
pts->pressure = pt->pressure;
@@ -717,8 +717,8 @@ static void annotation_stroke_arrow_init_point(
{
/* NOTE: provided co_idx should be always pair number as it's [x1, y1, x2, y2, x3, y3]. */
const float real_co[2] = {co[co_idx], co[co_idx + 1]};
- copy_v2_v2(&ptc->x, real_co);
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ copy_v2_v2(ptc->m_xy, real_co);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
annotation_stroke_arrow_init_point_default(pt);
}
@@ -885,7 +885,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
@@ -903,7 +903,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1);
/* Convert screen-coordinates to appropriate coordinates (and store them). */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* Copy pressure and time. */
pt->pressure = ptc->pressure;
@@ -926,7 +926,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
/* End point. */
ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1);
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
annotation_stroke_arrow_init_point_default(pt);
/* Fill and convert arrow points to create arrow shape. */
@@ -947,7 +947,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
/* Start point. */
ptc = runtime.sbuffer;
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
annotation_stroke_arrow_init_point_default(pt);
/* Fill and convert arrow points to create arrow shape. */
@@ -961,7 +961,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
@@ -981,7 +981,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
const ViewDepths *depths = p->depths;
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) {
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) &&
(i && (ED_view3d_depth_read_cached_seg(
@@ -1041,7 +1041,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p)
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc;
i++, ptc++, pt++) {
/* convert screen-coordinates to appropriate coordinates (and store them) */
- annotation_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
+ annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, depth_arr ? depth_arr + i : NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
@@ -1811,7 +1811,7 @@ static void annotation_draw_stabilizer(bContext *C, int x, int y, void *p_ptr)
/* Rope Simple. */
immUniformColor4f(color[0], color[1], color[2], 0.8f);
immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, pt->x + region->winrct.xmin, pt->y + region->winrct.ymin);
+ immVertex2f(pos, pt->m_xy[0] + region->winrct.xmin, pt->m_xy[1] + region->winrct.ymin);
immVertex2f(pos, x, y);
immEnd();
@@ -2575,8 +2575,7 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve
*/
if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) {
/* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(
- p->area, RGN_TYPE_ANY, event->xy[0], event->xy[1]);
+ ARegion *current_region = BKE_area_find_region_xy(p->area, RGN_TYPE_ANY, event->xy);
if (current_region) {
/* Assume that since we found the cursor in here, it is in bounds
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index bea8126cfcc..916aa8184aa 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -1468,6 +1468,10 @@ static int gpencil_layer_change_invoke(bContext *C, wmOperator *op, const wmEven
static int gpencil_layer_change_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = CTX_data_gpencil_data(C);
+ if (gpd == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
bGPDlayer *gpl = NULL;
int layer_num = RNA_enum_get(op->ptr, "layer");
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index c3af28d4382..541b6673cb6 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1072,7 +1072,7 @@ static void gpencil_erase_processed_area(tGPDfill *tgpf)
/* First set in blue the perimeter. */
for (int i = 0; i < tgpf->sbuffer_used && point2D; i++, point2D++) {
- int image_idx = ibuf->x * (int)point2D->y + (int)point2D->x;
+ int image_idx = ibuf->x * (int)point2D->m_xy[1] + (int)point2D->m_xy[0];
set_pixel(ibuf, image_idx, blue_col);
}
@@ -1393,7 +1393,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf)
for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) {
int mval_i[2];
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, tgpf->depth_arr + i) == 0) &&
(i && (ED_view3d_depth_read_cached_seg(
@@ -1437,9 +1437,9 @@ static int gpencil_points_from_stack(tGPDfill *tgpf)
while (!BLI_stack_is_empty(tgpf->stack)) {
int v[2];
BLI_stack_pop(tgpf->stack, &v);
- copy_v2fl_v2i(&point2D->x, v);
+ copy_v2fl_v2i(point2D->m_xy, v);
/* shift points to center of pixel */
- add_v2_fl(&point2D->x, 0.5f);
+ add_v2_fl(point2D->m_xy, 0.5f);
point2D->pressure = 1.0f;
point2D->strength = 1.0f;
point2D->time = 0.0f;
@@ -2108,8 +2108,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* first time the event is not enabled to show help lines. */
if ((tgpf->oldkey != -1) || (!help_lines)) {
- ARegion *region = BKE_area_find_region_xy(
- CTX_wm_area(C), RGN_TYPE_ANY, event->xy[0], event->xy[1]);
+ ARegion *region = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->xy);
if (region) {
bool in_bounds = false;
/* Perform bounds check */
@@ -2126,7 +2125,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
tgpf->gps_mouse = BKE_gpencil_stroke_new(0, 1, 10.0f);
tGPspoint point2D;
bGPDspoint *pt = &tgpf->gps_mouse->points[0];
- copy_v2fl_v2i(&point2D.x, tgpf->mouse);
+ copy_v2fl_v2i(point2D.m_xy, tgpf->mouse);
gpencil_stroke_convertcoords_tpoint(
tgpf->scene, tgpf->region, tgpf->ob, &point2D, NULL, &pt->x);
diff --git a/source/blender/editors/gpencil/gpencil_mesh.c b/source/blender/editors/gpencil/gpencil_mesh.c
index 11e02b9832f..efe29e852f2 100644
--- a/source/blender/editors/gpencil/gpencil_mesh.c
+++ b/source/blender/editors/gpencil/gpencil_mesh.c
@@ -142,6 +142,9 @@ static bool gpencil_bake_ob_list(bContext *C, Depsgraph *depsgraph, Scene *scene
/* Add active object. In some files this could not be in selected array. */
Object *obact = CTX_data_active_object(C);
+ if (obact == NULL) {
+ return false;
+ }
if (obact->type == OB_MESH) {
elem = MEM_callocN(sizeof(GpBakeOb), __func__);
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index dabe2050b28..b52d4a410ec 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -493,7 +493,7 @@ static void gpencil_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplit
/* Mouse movement in ints -> floats. */
if (gpd->runtime.sbuffer_used > 1) {
tGPspoint *pt_prev = pt - 1;
- sub_v2_v2v2(mvec, &pt->x, &pt_prev->x);
+ sub_v2_v2v2(mvec, pt->m_xy, pt_prev->m_xy);
normalize_v2(mvec);
/* Rotate mvec by 90 degrees... */
float angle = angle_v2v2(mvec, axis);
@@ -502,7 +502,7 @@ static void gpencil_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplit
mvec[1] *= sin(angle);
/* Scale by displacement amount, and apply. */
- madd_v2_v2fl(&pt->x, mvec, amplitude * 10.0f);
+ madd_v2_v2fl(pt->m_xy, mvec, amplitude * 10.0f);
}
}
@@ -520,8 +520,7 @@ static void gpencil_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const
/* Apply to first point (only if there are 2 points because before no data to do it ) */
if (gpd->runtime.sbuffer_used == 1) {
- mvec[0] = (mval[0] - (pt - 1)->x);
- mvec[1] = (mval[1] - (pt - 1)->y);
+ sub_v2_v2v2(mvec, mval, (pt - 1)->m_xy);
normalize_v2(mvec);
/* uses > 1.0f to get a smooth transition in first point */
@@ -533,8 +532,7 @@ static void gpencil_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const
/* apply from second point */
if (gpd->runtime.sbuffer_used >= 1) {
- mvec[0] = (mval[0] - (pt - 1)->x);
- mvec[1] = (mval[1] - (pt - 1)->y);
+ sub_v2_v2v2(mvec, mval, (pt - 1)->m_xy);
normalize_v2(mvec);
fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
@@ -581,25 +579,25 @@ static void gpencil_smooth_buffer(tGPsdata *p, float inf, int idx)
/* Compute smoothed coordinate by taking the ones nearby */
if (pta) {
- copy_v2_v2(a, &pta->x);
+ copy_v2_v2(a, pta->m_xy);
madd_v2_v2fl(sco, a, average_fac);
pressure += pta->pressure * average_fac;
strength += pta->strength * average_fac;
}
if (ptb) {
- copy_v2_v2(b, &ptb->x);
+ copy_v2_v2(b, ptb->m_xy);
madd_v2_v2fl(sco, b, average_fac);
pressure += ptb->pressure * average_fac;
strength += ptb->strength * average_fac;
}
if (ptc) {
- copy_v2_v2(c, &ptc->x);
+ copy_v2_v2(c, ptc->m_xy);
madd_v2_v2fl(sco, c, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
}
if (ptd) {
- copy_v2_v2(d, &ptd->x);
+ copy_v2_v2(d, ptd->m_xy);
madd_v2_v2fl(sco, d, average_fac);
pressure += ptd->pressure * average_fac;
strength += ptd->strength * average_fac;
@@ -609,7 +607,7 @@ static void gpencil_smooth_buffer(tGPsdata *p, float inf, int idx)
* for Guide mode. */
if (!guide->use_guide) {
interp_v2_v2v2(c, c, sco, inf);
- copy_v2_v2(&ptc->x, c);
+ copy_v2_v2(ptc->m_xy, c);
}
/* Interpolate pressure. */
ptc->pressure = interpf(ptc->pressure, pressure, inf);
@@ -646,37 +644,37 @@ static void gpencil_smooth_segment(bGPdata *gpd, const float inf, int from_idx,
/* Compute smoothed coordinate by taking the ones nearby */
if (pta) {
- madd_v2_v2fl(sco, &pta->x, average_fac);
+ madd_v2_v2fl(sco, pta->m_xy, average_fac);
pressure += pta->pressure * average_fac;
strength += pta->strength * average_fac;
}
else {
- madd_v2_v2fl(sco, &ptc->x, average_fac);
+ madd_v2_v2fl(sco, ptc->m_xy, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
}
if (ptb) {
- madd_v2_v2fl(sco, &ptb->x, average_fac);
+ madd_v2_v2fl(sco, ptb->m_xy, average_fac);
pressure += ptb->pressure * average_fac;
strength += ptb->strength * average_fac;
}
else {
- madd_v2_v2fl(sco, &ptc->x, average_fac);
+ madd_v2_v2fl(sco, ptc->m_xy, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
}
- madd_v2_v2fl(sco, &ptc->x, average_fac);
+ madd_v2_v2fl(sco, ptc->m_xy, average_fac);
pressure += ptc->pressure * average_fac;
strength += ptc->strength * average_fac;
- madd_v2_v2fl(sco, &ptd->x, average_fac);
+ madd_v2_v2fl(sco, ptd->m_xy, average_fac);
pressure += ptd->pressure * average_fac;
strength += ptd->strength * average_fac;
/* Based on influence factor, blend between original and optimal smoothed coordinate. */
- interp_v2_v2v2(&ptc->x, &ptc->x, sco, inf);
+ interp_v2_v2v2(ptc->m_xy, ptc->m_xy, sco, inf);
/* Interpolate pressure. */
ptc->pressure = interpf(ptc->pressure, pressure, inf);
@@ -738,7 +736,8 @@ static void gpencil_apply_randomness(tGPsdata *p,
/* Apply randomness to uv texture rotation. */
if ((brush_settings->uv_random > 0.0f) && (uv)) {
if ((brush_settings->flag2 & GP_BRUSH_USE_UV_AT_STROKE) == 0) {
- float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->x, gpd->runtime.sbuffer_used)) * 2.0f -
+ float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->m_xy[0], gpd->runtime.sbuffer_used)) *
+ 2.0f -
1.0f;
value = rand * M_PI_2 * brush_settings->uv_random;
}
@@ -778,7 +777,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
pt = (tGPspoint *)(gpd->runtime.sbuffer);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -794,7 +793,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
/* store settings */
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* T44932 - Pressure vals are unreliable, so ignore for now */
pt->pressure = 1.0f;
pt->strength = 1.0f;
@@ -825,7 +824,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p,
pt->strength = brush_settings->draw_strength;
pt->pressure = 1.0f;
pt->uv_rot = 0.0f;
- copy_v2_v2(&pt->x, mval);
+ copy_v2_v2(pt->m_xy, mval);
/* pressure */
if (brush_settings->flag & GP_BRUSH_USE_PRESSURE) {
@@ -1013,7 +1012,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
ptc = gpd->runtime.sbuffer;
/* convert screen-coordinates to appropriate coordinates (and store them) */
- gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
@@ -1047,7 +1046,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_used - 1);
/* convert screen-coordinates to appropriate coordinates (and store them) */
- gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
@@ -1100,7 +1099,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
int i;
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) {
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) &&
(i && (ED_view3d_depth_read_cached_seg(
@@ -1171,7 +1170,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc;
i++, ptc++, pt++) {
/* convert screen-coordinates to appropriate coordinates (and store them) */
- gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
+ gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, depth_arr ? depth_arr + i : NULL);
/* copy pressure and time */
pt->pressure = ptc->pressure;
@@ -1283,7 +1282,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
/* Join with existing strokes. */
if (ts->gpencil_flags & GP_TOOL_FLAG_AUTOMERGE_STROKE) {
- if (gps->prev != NULL) {
+ if ((gps->prev != NULL) || (gps->next != NULL)) {
BKE_gpencil_stroke_boundingbox_calc(gps);
float diff_mat[4][4], ctrl1[2], ctrl2[2];
BKE_gpencil_layer_transform_matrix_get(depsgraph, p->ob, gpl, diff_mat);
@@ -1567,6 +1566,12 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
}
bGPDspoint npt;
+ gpencil_point_to_parent_space(pt1, p->diff_mat, &npt);
+ gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
+
+ gpencil_point_to_parent_space(pt2, p->diff_mat, &npt);
+ gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
+
if (pt0) {
gpencil_point_to_parent_space(pt0, p->diff_mat, &npt);
gpencil_point_to_xy(&p->gsc, gps, &npt, &pc0[0], &pc0[1]);
@@ -1576,12 +1581,6 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p,
copy_v2_v2_int(pc0, pc1);
}
- gpencil_point_to_parent_space(pt1, p->diff_mat, &npt);
- gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]);
-
- gpencil_point_to_parent_space(pt2, p->diff_mat, &npt);
- gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]);
-
/* Check that point segment of the boundbox of the eraser stroke */
if (((!ELEM(V2D_IS_CLIPPED, pc0[0], pc0[1])) && BLI_rcti_isect_pt(rect, pc0[0], pc0[1])) ||
((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
@@ -2798,14 +2797,14 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra
pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
if (p->paintmode != GP_PAINTMODE_ERASER) {
- ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
+ ED_gpencil_toggle_brush_cursor(C, true, pt->m_xy);
}
}
else if ((p->brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) &&
(gpd->runtime.sbuffer_used > 0)) {
pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
if (p->paintmode != GP_PAINTMODE_ERASER) {
- ED_gpencil_toggle_brush_cursor(C, true, &pt->x);
+ ED_gpencil_toggle_brush_cursor(C, true, pt->m_xy);
}
}
}
@@ -3303,8 +3302,7 @@ static void gpencil_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoi
/* angle vector of the brush with full thickness */
const float v0[2] = {cos(angle), sin(angle)};
- mvec[0] = pt->x - pt_prev->x;
- mvec[1] = pt->y - pt_prev->y;
+ sub_v2_v2v2(mvec, pt->m_xy, pt_prev->m_xy);
normalize_v2(mvec);
fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
/* interpolate with previous point for smoother transitions */
@@ -3355,11 +3353,11 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment
* for arc curve.
*/
float v_prev[2], v_cur[2], v_half[2];
- sub_v2_v2v2(v_cur, mval, &pt_prev->x);
+ sub_v2_v2v2(v_cur, mval, pt_prev->m_xy);
- sub_v2_v2v2(v_prev, &pt_prev->x, &pt_before->x);
- interp_v2_v2v2(v_half, &pt_prev->x, mval, 0.5f);
- sub_v2_v2(v_half, &pt_prev->x);
+ sub_v2_v2v2(v_prev, pt_prev->m_xy, pt_before->m_xy);
+ interp_v2_v2v2(v_half, pt_prev->m_xy, mval, 0.5f);
+ sub_v2_v2(v_half, pt_prev->m_xy);
/* If angle is too sharp undo all changes and return. */
const float min_angle = DEG2RADF(120.0f);
@@ -3378,14 +3376,14 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment
/* Calc the position of the control point. */
float ctl[2];
- add_v2_v2v2(ctl, &pt_prev->x, v_prev);
+ add_v2_v2v2(ctl, pt_prev->m_xy, v_prev);
float step = M_PI_2 / (float)(segments + 1);
float a = step;
float midpoint[2], start[2], end[2], cp1[2], corner[2];
- mid_v2_v2v2(midpoint, &pt_prev->x, mval);
- copy_v2_v2(start, &pt_prev->x);
+ mid_v2_v2v2(midpoint, pt_prev->m_xy, mval);
+ copy_v2_v2(start, pt_prev->m_xy);
copy_v2_v2(end, mval);
copy_v2_v2(cp1, ctl);
@@ -3396,8 +3394,8 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment
tGPspoint *pt_step = pt_prev;
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
- pt->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
- pt->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
+ pt->m_xy[0] = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
+ pt->m_xy[1] = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
/* Set pressure and strength equals to previous. It will be smoothed later. */
pt->pressure = pt_prev->pressure;
@@ -3460,8 +3458,8 @@ static void gpencil_add_guide_points(const tGPsdata *p,
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
- gpencil_rotate_v2_v2v2fl(&pt->x, start, p->guide.origin, -a);
- gpencil_snap_to_guide(p, guide, &pt->x);
+ gpencil_rotate_v2_v2v2fl(pt->m_xy, start, p->guide.origin, -a);
+ gpencil_snap_to_guide(p, guide, pt->m_xy);
a += step;
/* Set pressure and strength equals to previous. It will be smoothed later. */
@@ -3477,8 +3475,8 @@ static void gpencil_add_guide_points(const tGPsdata *p,
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
- interp_v2_v2v2(&pt->x, start, end, a);
- gpencil_snap_to_guide(p, guide, &pt->x);
+ interp_v2_v2v2(pt->m_xy, start, end, a);
+ gpencil_snap_to_guide(p, guide, pt->m_xy);
a += step;
/* Set pressure and strength equals to previous. It will be smoothed later. */
@@ -3681,8 +3679,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
*/
if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) {
/* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(
- p->area, RGN_TYPE_ANY, event->xy[0], event->xy[1]);
+ ARegion *current_region = BKE_area_find_region_xy(p->area, RGN_TYPE_ANY, event->xy);
if (current_region) {
/* Assume that since we found the cursor in here, it is in bounds
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 8157e9d8fe7..2715491414a 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -423,6 +423,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
Scene *scene = tgpi->scene;
char status_str[UI_MAX_DRAW_STR];
char msg_str[UI_MAX_DRAW_STR];
+ const int cur_subdiv = tgpi->type == GP_STROKE_BOX ? tgpi->tot_edges - 1 : tgpi->tot_edges - 2;
if (tgpi->type == GP_STROKE_LINE) {
BLI_strncpy(msg_str,
@@ -480,7 +481,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
sizeof(status_str),
"%s: %d (%d, %d) (%d, %d)",
msg_str,
- tgpi->tot_edges,
+ cur_subdiv,
(int)tgpi->start[0],
(int)tgpi->start[1],
(int)tgpi->end[0],
@@ -491,7 +492,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
sizeof(status_str),
"%s: %d (%d, %d)",
msg_str,
- tgpi->tot_edges,
+ cur_subdiv,
(int)tgpi->end[0],
(int)tgpi->end[1]);
}
@@ -503,7 +504,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
sizeof(status_str),
"%s: %d (%d, %d) (%d, %d)",
msg_str,
- tgpi->tot_edges,
+ cur_subdiv,
(int)tgpi->start[0],
(int)tgpi->start[1],
(int)tgpi->end[0],
@@ -540,7 +541,7 @@ static void gpencil_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D
if (tgpi->tot_edges == 1) {
for (int j = 0; j < 4; j++) {
tGPspoint *p2d = &points2D[j];
- copy_v2_v2(&p2d->x, coords[j]);
+ copy_v2_v2(p2d->m_xy, coords[j]);
}
}
else {
@@ -550,7 +551,7 @@ static void gpencil_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D
float a = 0.0f;
for (int k = 0; k < tgpi->tot_edges; k++) {
tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2(&p2d->x, coords[j], coords[j + 1], a);
+ interp_v2_v2v2(p2d->m_xy, coords[j], coords[j + 1], a);
a += step;
i++;
}
@@ -581,7 +582,7 @@ static void gpencil_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D, boo
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2(&p2d->x, tgpi->start, tgpi->end, a);
+ interp_v2_v2v2(p2d->m_xy, tgpi->start, tgpi->end, a);
a += step;
}
@@ -627,8 +628,8 @@ static void gpencil_primitive_arc(tGPDprimitive *tgpi, tGPspoint *points2D)
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- p2d->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
- p2d->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
+ p2d->m_xy[0] = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
+ p2d->m_xy[1] = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a);
a += step;
}
float color[4];
@@ -663,7 +664,7 @@ static void gpencil_primitive_bezier(tGPDprimitive *tgpi, tGPspoint *points2D)
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- interp_v2_v2v2v2v2_cubic(&p2d->x, bcp1, bcp2, bcp3, bcp4, a);
+ interp_v2_v2v2v2v2_cubic(p2d->m_xy, bcp1, bcp2, bcp3, bcp4, a);
a += step;
}
float color[4];
@@ -697,8 +698,8 @@ static void gpencil_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D)
for (int i = tgpi->tot_stored_edges; i < totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- p2d->x = (center[0] + cosf(a) * radius[0]);
- p2d->y = (center[1] + sinf(a) * radius[1]);
+ p2d->m_xy[0] = (center[0] + cosf(a) * radius[0]);
+ p2d->m_xy[1] = (center[1] + sinf(a) * radius[1]);
a += step;
}
float color[4];
@@ -726,7 +727,6 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
const bool is_camera = is_lock_axis_view && (tgpi->rv3d->persp == RV3D_CAMOB) && (!is_depth);
if (tgpi->type == GP_STROKE_BOX) {
- tgpi->tot_edges--;
gps->totpoints = (tgpi->tot_edges * 4 + tgpi->tot_stored_edges);
}
else {
@@ -801,7 +801,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
const ViewDepths *depths = tgpi->depths;
tGPspoint *ptc = &points2D[0];
for (int i = 0; i < gps->totpoints; i++, ptc++) {
- round_v2i_v2fl(mval_i, &ptc->x);
+ round_v2i_v2fl(mval_i, ptc->m_xy);
if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) &&
(i && (ED_view3d_depth_read_cached_seg(
depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) {
@@ -894,7 +894,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* Store original points */
float tmp_xyp[2];
- copy_v2_v2(tmp_xyp, &p2d->x);
+ copy_v2_v2(tmp_xyp, p2d->m_xy);
/* calc pressure */
float curve_pressure = 1.0;
@@ -926,8 +926,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* vector */
float mvec[2], svec[2];
if (i > 0) {
- mvec[0] = (p2d->x - (p2d - 1)->x);
- mvec[1] = (p2d->y - (p2d - 1)->y);
+ sub_v2_v2v2(mvec, p2d->m_xy, (p2d - 1)->m_xy);
normalize_v2(mvec);
}
else {
@@ -942,7 +941,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
else {
mul_v2_fl(svec, fac);
}
- add_v2_v2(&p2d->x, svec);
+ add_v2_v2(p2d->m_xy, svec);
}
/* color strength */
@@ -992,7 +991,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
}
- copy_v2_v2(&tpt->x, &p2d->x);
+ copy_v2_v2(tpt->m_xy, p2d->m_xy);
tpt->pressure = pressure;
tpt->strength = strength;
@@ -1064,7 +1063,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
/* Restore original points */
- copy_v2_v2(&p2d->x, tmp_xyp);
+ copy_v2_v2(p2d->m_xy, tmp_xyp);
}
/* store cps and convert coords */
@@ -1254,7 +1253,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
tgpi->tot_stored_edges = 0;
tgpi->subdiv = RNA_int_get(op->ptr, "subdivision");
- RNA_int_set(op->ptr, "edges", tgpi->subdiv + 2);
+ RNA_int_set(op->ptr, "edges", tgpi->type == GP_STROKE_BOX ? tgpi->subdiv + 1 : tgpi->subdiv + 2);
tgpi->tot_edges = RNA_int_get(op->ptr, "edges");
tgpi->flag = IDLE;
tgpi->lock_axis = ts->gp_sculpt.lock_axis;
@@ -1617,7 +1616,7 @@ static void gpencil_primitive_move(tGPDprimitive *tgpi, bool reset)
for (int i = 0; i < gps->totpoints; i++) {
tGPspoint *p2d = &points2D[i];
- add_v2_v2(&p2d->x, move);
+ add_v2_v2(p2d->m_xy, move);
}
add_v2_v2(tgpi->start, move);
@@ -1720,7 +1719,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELUPMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges + 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
gpencil_primitive_update(C, op, tgpi);
}
@@ -1730,7 +1729,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELDOWNMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges - 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
gpencil_primitive_update(C, op, tgpi);
}
@@ -1886,7 +1885,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELUPMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges + 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
/* update screen */
@@ -1898,7 +1897,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case WHEELDOWNMOUSE: {
if ((event->val != KM_RELEASE)) {
tgpi->tot_edges = tgpi->tot_edges - 1;
- CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES);
RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
/* update screen */
@@ -2038,15 +2037,8 @@ static void gpencil_primitive_common_props(wmOperatorType *ot, int subdiv, int t
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
/* Internal prop. */
- prop = RNA_def_int(ot->srna,
- "edges",
- MIN_EDGES,
- MIN_EDGES,
- MAX_EDGES,
- "Edges",
- "Number of points by edge",
- MIN_EDGES,
- MAX_EDGES);
+ prop = RNA_def_int(
+ ot->srna, "edges", 1, 1, MAX_EDGES, "Edges", "Number of points by edge", 1, MAX_EDGES);
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
RNA_def_enum(ot->srna, "type", gpencil_primitive_type, type, "Type", "Type of shape");
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index f082af979a1..81a844cf6e1 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -870,7 +870,7 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene,
}
int mval_i[2];
- round_v2i_v2fl(mval_i, &point2D->x);
+ round_v2i_v2fl(mval_i, point2D->m_xy);
if ((depth != NULL) && (ED_view3d_autodist_simple(region, mval_i, r_out, 0, depth))) {
/* projecting onto 3D-Geometry
@@ -878,7 +878,7 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene,
*/
}
else {
- float mval_f[2] = {point2D->x, point2D->y};
+ float mval_f[2] = {UNPACK2(point2D->m_xy)};
float mval_prj[2];
float rvec[3], dvec[3];
float zfac;
@@ -2020,7 +2020,7 @@ static void gpencil_stroke_convertcoords(ARegion *region,
const float origin[3],
float out[3])
{
- float mval_f[2] = {(float)point2D->x, (float)point2D->y};
+ float mval_f[2] = {UNPACK2(point2D->m_xy)};
float mval_prj[2];
float rvec[3], dvec[3];
float zfac;
@@ -2808,8 +2808,8 @@ static void gpencil_sbuffer_vertex_color_random(
if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
- int ix = (int)(tpt->x * seed);
- int iy = (int)(tpt->y * seed);
+ int ix = (int)(tpt->m_xy[0] * seed);
+ int iy = (int)(tpt->m_xy[1] * seed);
int iz = ix + iy * seed;
float hsv[3];
float factor_value[3];
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 99164bbe439..5e50a17e80a 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -94,7 +94,7 @@ typedef enum eGP_TargetObjectMode {
*/
typedef struct tGPspoint {
/** Coordinates x and y of cursor (in relative to area). */
- float x, y;
+ float m_xy[2];
/** Pressure of tablet at this point. */
float pressure;
/** Pressure of tablet at this point for alpha factor. */
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index bafe68bd28d..c54fb93e495 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -380,10 +380,21 @@ bool delete_fcurve_keys(struct FCurve *fcu);
void clear_fcurve_keys(struct FCurve *fcu);
void duplicate_fcurve_keys(struct FCurve *fcu);
+typedef struct FCurveSegment {
+ struct FCurveSegment *next, *prev;
+ int start_index, length;
+} FCurveSegment;
+ListBase find_fcurve_segments(struct FCurve *fcu);
void clean_fcurve(struct bAnimContext *ac,
struct bAnimListElem *ale,
float thresh,
bool cleardefault);
+void blend_to_neighbor_fcurve_segment(struct FCurve *fcu,
+ struct FCurveSegment *segment,
+ const float factor);
+void breakdown_fcurve_segment(struct FCurve *fcu,
+ struct FCurveSegment *segment,
+ const float factor);
bool decimate_fcurve(struct bAnimListElem *ale, float remove_ratio, float error_sq_max);
/**
* Use a weighted moving-means method to reduce intensity of fluctuations.
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index 5bac452c7c9..db1ba80dd3c 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -100,7 +100,7 @@ void ED_node_socket_draw(struct bNodeSocket *sock,
float scale);
void ED_node_tree_update(const struct bContext *C);
void ED_node_tag_update_id(struct ID *id);
-void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
+
/**
* Sort nodes by selection: unselected nodes first, then selected,
* then the active node at the very end. Relative order is kept intact.
@@ -152,6 +152,26 @@ void ED_node_set_active(struct Main *bmain,
bool *r_active_texture_changed);
/**
+ * Call after one or more node trees have been changed and tagged accordingly.
+ *
+ * This function will make sure that other parts of Blender update accordingly. For example, if the
+ * node group interface changed, parent node groups have to be updated as well.
+ *
+ * Additionally, this will send notifiers and tag the depsgraph based on the changes. Depsgraph
+ * relation updates have to be triggered by the caller.
+ *
+ * \param C: Context if available. This can be null.
+ * \param bmain: Main whose data-blocks should be updated based on the changes.
+ * \param ntree: Under some circumstances the caller knows that only one node tree has
+ * changed since the last update. In this case the function may be able to skip scanning #bmain
+ * for other things that have to be changed. It may still scan #bmain if the interface of the
+ * node tree has changed.
+ */
+void ED_node_tree_propagate_change(const struct bContext *C,
+ struct Main *bmain,
+ struct bNodeTree *ntree);
+
+/**
* \param scene_owner: is the owner of the job,
* we don't use it for anything else currently so could also be a void pointer,
* but for now keep it an 'Scene' for consistency.
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index f60d62ed384..b91569cee03 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -23,6 +23,7 @@
#pragma once
+#include "DNA_ID_enums.h"
#include "DNA_vec_types.h"
#ifdef __cplusplus
@@ -41,7 +42,6 @@ struct bContext;
struct bScreen;
struct wmWindow;
struct wmWindowManager;
-enum eIconSizes;
/* render_ops.c */
@@ -100,7 +100,7 @@ void ED_preview_shader_job(const struct bContext *C,
struct MTex *slot,
int sizex,
int sizey,
- int method);
+ ePreviewRenderMethod method);
void ED_preview_icon_render(const struct bContext *C,
struct Scene *scene,
struct ID *id,
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 9df5b17975a..cee323bd5c9 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -982,21 +982,6 @@ uiBut *uiDefButF(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefButI(uiBlock *block,
int type,
int retval,
@@ -1154,35 +1139,6 @@ uiBut *uiDefIconBut(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconButF(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconButI(uiBlock *block,
int type,
int retval,
@@ -1241,20 +1197,6 @@ uiBut *uiDefIconButBitS(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconButBitC(uiBlock *block,
int type,
int bit,
@@ -1356,22 +1298,6 @@ uiBut *uiDefIconTextButF(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconTextButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconTextButI(uiBlock *block,
int type,
int retval,
@@ -1387,84 +1313,6 @@ uiBut *uiDefIconTextButI(uiBlock *block,
float a1,
float a2,
const char *tip);
-uiBut *uiDefIconTextButBitI(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- int *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButS(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButBitS(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
-uiBut *uiDefIconTextButBitC(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip);
uiBut *uiDefIconTextButR(uiBlock *block,
int type,
int retval,
@@ -2196,6 +2044,7 @@ uiLayout *UI_block_layout(uiBlock *block,
const struct uiStyle *style);
void UI_block_layout_set_current(uiBlock *block, uiLayout *layout);
void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y);
+bool UI_block_layout_needs_resolving(const uiBlock *block);
/**
* Used for property search when the layout process needs to be cancelled in order to avoid
* computing the locations for buttons, but the layout items created while adding the buttons
@@ -2544,11 +2393,42 @@ void uiTemplateComponentMenu(uiLayout *layout,
const char *propname,
const char *name);
void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float color[4]);
+
+/**
+ * Draw the main CacheFile properties and operators (file path, scale, etc.), that is those which
+ * do not have their own dedicated template functions.
+ */
void uiTemplateCacheFile(uiLayout *layout,
const struct bContext *C,
struct PointerRNA *ptr,
const char *propname);
+/**
+ * Lookup the CacheFile PointerRNA of the given pointer and return it in the output parameter.
+ * Returns true if `ptr` has a RNACacheFile, false otherwise. If false, the output parameter is not
+ * initialized.
+ */
+bool uiTemplateCacheFilePointer(struct PointerRNA *ptr,
+ const char *propname,
+ struct PointerRNA *r_file_ptr);
+
+/**
+ * Draw the velocity related properties of the CacheFile.
+ */
+void uiTemplateCacheFileVelocity(uiLayout *layout, struct PointerRNA *fileptr);
+
+/**
+ * Draw the render procedural related properties of the CacheFile.
+ */
+void uiTemplateCacheFileProcedural(uiLayout *layout,
+ const struct bContext *C,
+ struct PointerRNA *fileptr);
+
+/**
+ * Draw the time related properties of the CacheFile.
+ */
+void uiTemplateCacheFileTimeSettings(uiLayout *layout, struct PointerRNA *fileptr);
+
/* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
enum uiTemplateListFlags {
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index df508b87ce4..a275a59a4e7 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -4943,38 +4943,6 @@ uiBut *uiDefButF(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefButBit(block,
- type | UI_BUT_POIN_FLOAT,
- bit,
- retval,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefButI(uiBlock *block,
int type,
int retval,
@@ -5295,68 +5263,6 @@ static uiBut *uiDefIconButBit(uiBlock *block,
tip);
}
-uiBut *uiDefIconButF(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconBut(block,
- type | UI_BUT_POIN_FLOAT,
- retval,
- icon,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconButBit(block,
- type | UI_BUT_POIN_FLOAT,
- bit,
- retval,
- icon,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconButI(uiBlock *block,
int type,
int retval,
@@ -5481,36 +5387,6 @@ uiBut *uiDefIconButBitS(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefIconButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconBut(block,
- type | UI_BUT_POIN_CHAR,
- retval,
- icon,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconButBitC(uiBlock *block,
int type,
int bit,
@@ -5640,44 +5516,6 @@ uiBut *uiDefIconTextBut(uiBlock *block,
but->drawflag |= UI_BUT_ICON_LEFT;
return but;
}
-static uiBut *uiDefIconTextButBit(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- void *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- const int bitIdx = findBitIndex(bit);
- if (bitIdx == -1) {
- return NULL;
- }
- return uiDefIconTextBut(block,
- type | UI_BUT_POIN_BIT | bitIdx,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-
uiBut *uiDefIconTextButF(uiBlock *block,
int type,
int retval,
@@ -5710,40 +5548,6 @@ uiBut *uiDefIconTextButF(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefIconTextButBitF(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- float *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_FLOAT,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconTextButI(uiBlock *block,
int type,
int retval,
@@ -5776,172 +5580,6 @@ uiBut *uiDefIconTextButI(uiBlock *block,
a2,
tip);
}
-uiBut *uiDefIconTextButBitI(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- int *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_INT,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButS(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextBut(block,
- type | UI_BUT_POIN_SHORT,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButBitS(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- short *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_SHORT,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButC(uiBlock *block,
- int type,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextBut(block,
- type | UI_BUT_POIN_CHAR,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
-uiBut *uiDefIconTextButBitC(uiBlock *block,
- int type,
- int bit,
- int retval,
- int icon,
- const char *str,
- int x,
- int y,
- short width,
- short height,
- char *poin,
- float min,
- float max,
- float a1,
- float a2,
- const char *tip)
-{
- return uiDefIconTextButBit(block,
- type | UI_BUT_POIN_CHAR,
- bit,
- retval,
- icon,
- str,
- x,
- y,
- width,
- height,
- (void *)poin,
- min,
- max,
- a1,
- a2,
- tip);
-}
uiBut *uiDefIconTextButR(uiBlock *block,
int type,
int retval,
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 27fa2e5a22f..fd03cc5e12c 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -146,8 +146,8 @@ void eyedropper_draw_cursor_text_region(const int x, const int y, const char *na
uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
- const ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, event->xy[0], event->xy[1]);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
+ const ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, event->xy);
uiBut *but = ui_but_find_mouse_over(region, event);
@@ -163,13 +163,13 @@ void datadropper_win_area_find(
bScreen *screen = CTX_wm_screen(C);
*r_win = CTX_wm_window(C);
- *r_area = BKE_screen_find_area_xy(screen, -1, mval[0], mval[1]);
+ *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mval);
if (*r_area == NULL) {
wmWindowManager *wm = CTX_wm_manager(C);
*r_win = WM_window_find_under_cursor(wm, NULL, *r_win, mval, r_mval);
if (*r_win) {
screen = WM_window_get_active_screen(*r_win);
- *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, r_mval[0], r_mval[1]);
+ *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, r_mval);
}
}
else if (mval != r_mval) {
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 0ac6ea4021b..52730096b2f 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -263,32 +263,32 @@ static bool eyedropper_cryptomatte_sample_fl(
}
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
- if (!sa || !ELEM(sa->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) {
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, (const int[2]){mx, my});
+ if (!area || !ELEM(area->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) {
return false;
}
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my});
if (!region) {
return false;
}
int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
float fpos[2] = {-1.0f, -1.0};
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_space_image_get_position(sima, region, mval, fpos);
break;
}
case SPACE_NODE: {
Main *bmain = CTX_data_main(C);
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
ED_space_node_get_position(bmain, snode, region, mval, fpos);
break;
}
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_space_clip_get_position(sc, region, mval, fpos);
break;
}
@@ -337,7 +337,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
if (area) {
if (area->spacetype == SPACE_IMAGE) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceImage *sima = area->spacedata.first;
int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
@@ -348,7 +348,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
}
}
else if (area->spacetype == SPACE_NODE) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceNode *snode = area->spacedata.first;
int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
@@ -359,7 +359,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
}
}
else if (area->spacetype == SPACE_CLIP) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval);
if (region) {
SpaceClip *sc = area->spacedata.first;
int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin};
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index 261aa997d06..cf53ef0ec75 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -162,7 +162,7 @@ static void datadropper_id_sample_pt(
if (area) {
if (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my});
if (region) {
const int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
Base *base;
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index 4172c474f4a..8c6b0ac9cfe 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -157,7 +157,7 @@ static void depthdropper_depth_sample_pt(
{
/* we could use some clever */
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, (const int[2]){mx, my});
Scene *scene = CTX_data_scene(C);
ScrArea *area_prev = CTX_wm_area(C);
@@ -167,7 +167,7 @@ static void depthdropper_depth_sample_pt(
if (area) {
if (area->spacetype == SPACE_VIEW3D) {
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my});
if (region) {
struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
View3D *v3d = area->spacedata.first;
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c
index ccf0e727da8..6fe930b74d2 100644
--- a/source/blender/editors/interface/interface_eyedropper_driver.c
+++ b/source/blender/editors/interface/interface_eyedropper_driver.c
@@ -107,7 +107,7 @@ static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *eve
char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop);
/* ... and destination */
- char *dst_path = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL);
+ char *dst_path = RNA_path_from_ID_to_property(&ddr->ptr, ddr->prop);
/* Now create driver(s) */
if (target_path && dst_path) {
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index d720b52a59e..659ac0ae899 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -3495,8 +3495,17 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
ui_but_update(but);
- /* Popup blocks don't support moving after creation, so don't change the view for them. */
- if (!data->searchbox) {
+ /* Make sure the edited button is in view. */
+ if (data->searchbox) {
+ /* Popup blocks don't support moving after creation, so don't change the view for them. */
+ }
+ else if (UI_block_layout_needs_resolving(but->block)) {
+ /* Layout isn't resolved yet (may happen when activating while drawing through
+ * #UI_but_active_only()), so can't move it into view yet. This causes
+ * #ui_but_update_view_for_active() to run after the layout is resolved. */
+ but->changed = true;
+ }
+ else {
UI_but_ensure_in_view(C, data->region, but);
}
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index cbdb284c66b..98fcb36b778 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -5661,6 +5661,11 @@ void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y)
}
}
+bool UI_block_layout_needs_resolving(const uiBlock *block)
+{
+ return !BLI_listbase_is_empty(&block->layouts);
+}
+
void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr)
{
uiBlock *block = layout->root->block;
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 61869f3da41..f7424066ad8 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1023,8 +1023,8 @@ bool UI_context_copy_to_selected_check(PointerRNA *ptr,
return false;
}
- /* Skip non-existing properties on link. This was previously covered with the lprop != prop check
- * but we are now more permissive when it comes to ID properties, see below. */
+ /* Skip non-existing properties on link. This was previously covered with the `lprop != prop`
+ * check but we are now more permissive when it comes to ID properties, see below. */
if (lprop == NULL) {
return false;
}
@@ -1033,19 +1033,19 @@ bool UI_context_copy_to_selected_check(PointerRNA *ptr,
return false;
}
- /* Check property pointers matching
- * For ID properties, these pointers match
- * - if the property is API defined on an existing class (and they are equally named)
- * - never for ID properties on specific ID (even if they are equally named)
- * - never for NodesModifierSettings properties (even if they are equally named)
+ /* Check property pointers matching.
+ * For ID properties, these pointers match:
+ * - If the property is API defined on an existing class (and they are equally named).
+ * - Never for ID properties on specific ID (even if they are equally named).
+ * - Never for NodesModifierSettings properties (even if they are equally named).
*
* Be permissive on ID properties in the following cases:
- * - NodesModifierSettings properties
- * - (special check: only if the nodegroup matches, since the 'Input_n' properties are name
- * based and similar on potentionally very different nodegroups)
+ * - #NodesModifierSettings properties
+ * - (special check: only if the node-group matches, since the 'Input_n' properties are name
+ * based and similar on potentially very different node-groups).
* - ID properties on specific ID
- * - (no special check, copying seems OK [even if type does not match -- does not do anything
- * then])
+ * - (no special check, copying seems OK [even if type does not match -- does not do anything
+ * then])
*/
bool ignore_prop_eq = RNA_property_is_idprop(lprop) && RNA_property_is_idprop(prop);
if (RNA_struct_is_a(lptr.type, &RNA_NodesModifier) &&
@@ -1753,9 +1753,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev
bScreen *screen = CTX_wm_screen(C);
const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed");
ARegion *region_prev = CTX_wm_region(C);
- ARegion *region = screen ? BKE_screen_find_region_xy(
- screen, RGN_TYPE_ANY, event->xy[0], event->xy[1]) :
- NULL;
+ ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : NULL;
if (region == NULL) {
region = region_prev;
diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc
index f4c99fb3c16..e27dd2a7981 100644
--- a/source/blender/editors/interface/interface_region_search.cc
+++ b/source/blender/editors/interface/interface_region_search.cc
@@ -725,7 +725,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C,
region->type = &type;
/* create searchbox data */
- uiSearchboxData *data = (uiSearchboxData *)MEM_callocN(sizeof(uiSearchboxData), __func__);
+ uiSearchboxData *data = MEM_cnew<uiSearchboxData>(__func__);
/* set font, get bb */
data->fstyle = style->widget; /* copy struct */
@@ -1021,7 +1021,7 @@ void ui_but_search_refresh(uiButSearch *search_but)
return;
}
- uiSearchItems *items = (uiSearchItems *)MEM_callocN(sizeof(uiSearchItems), __func__);
+ uiSearchItems *items = MEM_cnew<uiSearchItems>(__func__);
/* setup search struct */
items->maxitem = 10;
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index b8026cbb40c..00e9a75848a 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -2672,7 +2672,7 @@ static void constraint_ops_extra_draw(bContext *C, uiLayout *layout, void *con_v
static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *con)
{
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
short proxy_protected, xco = 0, yco = 0;
// int rb_col; // UNUSED
@@ -6395,21 +6395,93 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float color[4])
/** \name Cache File Template
* \{ */
-void uiTemplateCacheFile(uiLayout *layout,
- const bContext *C,
- PointerRNA *ptr,
- const char *propname)
+void uiTemplateCacheFileVelocity(uiLayout *layout, PointerRNA *fileptr)
{
- if (!ptr->data) {
- return;
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiItemR(layout, fileptr, "velocity_name", 0, NULL, ICON_NONE);
+ uiItemR(layout, fileptr, "velocity_unit", 0, NULL, ICON_NONE);
+}
+
+void uiTemplateCacheFileProcedural(uiLayout *layout, const bContext *C, PointerRNA *fileptr)
+{
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiLayout *row, *sub;
+
+ /* Only enable render procedural option if the active engine supports it. */
+ const struct RenderEngineType *engine_type = CTX_data_engine_type(C);
+
+ Scene *scene = CTX_data_scene(C);
+ const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type,
+ scene);
+
+ if (!engine_supports_procedural) {
+ row = uiLayoutRow(layout, false);
+ /* For Cycles, verify that experimental features are enabled. */
+ if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) {
+ uiItemL(
+ row,
+ TIP_(
+ "The Cycles Alembic Procedural is only available with the experimental feature set"),
+ ICON_INFO);
+ }
+ else {
+ uiItemL(
+ row, TIP_("The active render engine does not have an Alembic Procedural"), ICON_INFO);
+ }
}
+ row = uiLayoutRow(layout, false);
+ uiLayoutSetActive(row, engine_supports_procedural);
+ uiItemR(row, fileptr, "use_render_procedural", 0, NULL, ICON_NONE);
+
+ const bool use_render_procedural = RNA_boolean_get(fileptr, "use_render_procedural");
+ const bool use_prefetch = RNA_boolean_get(fileptr, "use_prefetch");
+
+ row = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(row, use_render_procedural);
+ uiItemR(row, fileptr, "use_prefetch", 0, NULL, ICON_NONE);
+
+ sub = uiLayoutRow(layout, false);
+ uiLayoutSetEnabled(sub, use_prefetch && use_render_procedural);
+ uiItemR(sub, fileptr, "prefetch_cache_size", 0, NULL, ICON_NONE);
+}
+
+void uiTemplateCacheFileTimeSettings(uiLayout *layout, PointerRNA *fileptr)
+{
+ /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */
+ uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr);
+
+ uiLayout *row, *sub, *subsub;
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, fileptr, "is_sequence", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame"));
+ sub = uiLayoutRow(row, true);
+ uiLayoutSetPropDecorate(sub, false);
+ uiItemR(sub, fileptr, "override_frame", 0, "", ICON_NONE);
+ subsub = uiLayoutRow(sub, true);
+ uiLayoutSetActive(subsub, RNA_boolean_get(fileptr, "override_frame"));
+ uiItemR(subsub, fileptr, "frame", 0, "", ICON_NONE);
+ uiItemDecoratorR(row, fileptr, "frame", 0);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, fileptr, "frame_offset", 0, NULL, ICON_NONE);
+ uiLayoutSetActive(row, !RNA_boolean_get(fileptr, "is_sequence"));
+}
+
+bool uiTemplateCacheFilePointer(PointerRNA *ptr, const char *propname, PointerRNA *r_file_ptr)
+{
PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
if (!prop) {
printf(
"%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname);
- return;
+ return false;
}
if (RNA_property_type(prop) != PROP_POINTER) {
@@ -6417,10 +6489,27 @@ void uiTemplateCacheFile(uiLayout *layout,
__func__,
RNA_struct_identifier(ptr->type),
propname);
+ return false;
+ }
+
+ *r_file_ptr = RNA_property_pointer_get(ptr, prop);
+ return true;
+}
+
+void uiTemplateCacheFile(uiLayout *layout,
+ const bContext *C,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ if (!ptr->data) {
+ return;
+ }
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
return;
}
- PointerRNA fileptr = RNA_property_pointer_get(ptr, prop);
CacheFile *file = fileptr.data;
uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr);
@@ -6442,7 +6531,7 @@ void uiTemplateCacheFile(uiLayout *layout,
SpaceProperties *sbuts = CTX_wm_space_properties(C);
- uiLayout *row, *sub, *subsub;
+ uiLayout *row, *sub;
uiLayoutSetPropSep(layout, true);
@@ -6451,68 +6540,11 @@ void uiTemplateCacheFile(uiLayout *layout,
sub = uiLayoutRow(row, true);
uiItemO(sub, "", ICON_FILE_REFRESH, "cachefile.reload");
- row = uiLayoutRow(layout, false);
- uiItemR(row, &fileptr, "is_sequence", 0, NULL, ICON_NONE);
-
- /* Only enable render procedural option if the active engine supports it. */
- const struct RenderEngineType *engine_type = CTX_data_engine_type(C);
-
- Scene *scene = CTX_data_scene(C);
- const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type,
- scene);
-
- if (!engine_supports_procedural) {
- row = uiLayoutRow(layout, false);
- /* For Cycles, verify that experimental features are enabled. */
- if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) {
- uiItemL(
- row,
- TIP_(
- "The Cycles Alembic Procedural is only available with the experimental feature set"),
- ICON_INFO);
- }
- else {
- uiItemL(
- row, TIP_("The active render engine does not have an Alembic Procedural"), ICON_INFO);
- }
- }
-
- row = uiLayoutRow(layout, false);
- uiLayoutSetActive(row, engine_supports_procedural);
- uiItemR(row, &fileptr, "use_render_procedural", 0, NULL, ICON_NONE);
-
- const bool use_render_procedural = RNA_boolean_get(&fileptr, "use_render_procedural");
- const bool use_prefetch = RNA_boolean_get(&fileptr, "use_prefetch");
-
- row = uiLayoutRow(layout, false);
- uiLayoutSetEnabled(row, use_render_procedural);
- uiItemR(row, &fileptr, "use_prefetch", 0, NULL, ICON_NONE);
-
- sub = uiLayoutRow(layout, false);
- uiLayoutSetEnabled(sub, use_prefetch && use_render_procedural);
- uiItemR(sub, &fileptr, "prefetch_cache_size", 0, NULL, ICON_NONE);
-
- row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame"));
- sub = uiLayoutRow(row, true);
- uiLayoutSetPropDecorate(sub, false);
- uiItemR(sub, &fileptr, "override_frame", 0, "", ICON_NONE);
- subsub = uiLayoutRow(sub, true);
- uiLayoutSetActive(subsub, RNA_boolean_get(&fileptr, "override_frame"));
- uiItemR(subsub, &fileptr, "frame", 0, "", ICON_NONE);
- uiItemDecoratorR(row, &fileptr, "frame", 0);
-
- row = uiLayoutRow(layout, false);
- uiItemR(row, &fileptr, "frame_offset", 0, NULL, ICON_NONE);
- uiLayoutSetActive(row, !RNA_boolean_get(&fileptr, "is_sequence"));
-
if (sbuts->mainb == BCONTEXT_CONSTRAINT) {
row = uiLayoutRow(layout, false);
uiItemR(row, &fileptr, "scale", 0, IFACE_("Manual Scale"), ICON_NONE);
}
- uiItemR(layout, &fileptr, "velocity_name", 0, NULL, ICON_NONE);
- uiItemR(layout, &fileptr, "velocity_unit", 0, NULL, ICON_NONE);
-
/* TODO: unused for now, so no need to expose. */
#if 0
row = uiLayoutRow(layout, false);
diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc
index 500834f4434..81b24c75020 100644
--- a/source/blender/editors/interface/interface_view.cc
+++ b/source/blender/editors/interface/interface_view.cc
@@ -60,7 +60,7 @@ AbstractTreeView *UI_block_add_view(uiBlock &block,
StringRef idname,
std::unique_ptr<AbstractTreeView> tree_view)
{
- ViewLink *view_link = OBJECT_GUARDED_NEW(ViewLink);
+ ViewLink *view_link = MEM_new<ViewLink>(__func__);
BLI_addtail(&block.views, view_link);
view_link->view = std::move(tree_view);
@@ -72,7 +72,7 @@ AbstractTreeView *UI_block_add_view(uiBlock &block,
void ui_block_free_views(uiBlock *block)
{
LISTBASE_FOREACH_MUTABLE (ViewLink *, link, &block->views) {
- OBJECT_GUARDED_DELETE(link, ViewLink);
+ MEM_delete(link);
}
}
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index 44b5f85050f..f4da114159f 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -25,6 +25,20 @@ set(INC
../../io/alembic
../../io/collada
../../io/gpencil
+ ../../io/wavefront_obj
+ ../../io/usd
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ io_alembic.c
../../io/usd
../../makesdna
../../makesrna
@@ -43,6 +57,7 @@ set(SRC
io_gpencil_export.c
io_gpencil_import.c
io_gpencil_utils.c
+ io_obj.c
io_ops.c
io_usd.c
@@ -57,6 +72,7 @@ set(SRC
set(LIB
bf_blenkernel
bf_blenlib
+ bf_wavefront_obj
)
if(WITH_OPENCOLLADA)
diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c
new file mode 100644
index 00000000000..1e1e3c2ff42
--- /dev/null
+++ b/source/blender/editors/io/io_obj.c
@@ -0,0 +1,369 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup editor/io
+ */
+
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "DEG_depsgraph.h"
+
+#include "IO_wavefront_obj.h"
+#include "io_obj.h"
+
+const EnumPropertyItem io_obj_transform_axis_forward[] = {
+ {OBJ_AXIS_X_FORWARD, "X_FORWARD", 0, "X", "Positive X axis"},
+ {OBJ_AXIS_Y_FORWARD, "Y_FORWARD", 0, "Y", "Positive Y axis"},
+ {OBJ_AXIS_Z_FORWARD, "Z_FORWARD", 0, "Z", "Positive Z axis"},
+ {OBJ_AXIS_NEGATIVE_X_FORWARD, "NEGATIVE_X_FORWARD", 0, "-X", "Negative X axis"},
+ {OBJ_AXIS_NEGATIVE_Y_FORWARD, "NEGATIVE_Y_FORWARD", 0, "-Y", "Negative Y axis"},
+ {OBJ_AXIS_NEGATIVE_Z_FORWARD, "NEGATIVE_Z_FORWARD", 0, "-Z (Default)", "Negative Z axis"},
+ {0, NULL, 0, NULL, NULL}};
+
+const EnumPropertyItem io_obj_transform_axis_up[] = {
+ {OBJ_AXIS_X_UP, "X_UP", 0, "X", "Positive X axis"},
+ {OBJ_AXIS_Y_UP, "Y_UP", 0, "Y (Default)", "Positive Y axis"},
+ {OBJ_AXIS_Z_UP, "Z_UP", 0, "Z", "Positive Z axis"},
+ {OBJ_AXIS_NEGATIVE_X_UP, "NEGATIVE_X_UP", 0, "-X", "Negative X axis"},
+ {OBJ_AXIS_NEGATIVE_Y_UP, "NEGATIVE_Y_UP", 0, "-Y", "Negative Y axis"},
+ {OBJ_AXIS_NEGATIVE_Z_UP, "NEGATIVE_Z_UP", 0, "-Z", "Negative Z axis"},
+ {0, NULL, 0, NULL, NULL}};
+
+const EnumPropertyItem io_obj_export_evaluation_mode[] = {
+ {DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"},
+ {DAG_EVAL_VIEWPORT,
+ "DAG_EVAL_VIEWPORT",
+ 0,
+ "Viewport (Default)",
+ "Export objects as they appear in the viewport"},
+ {0, NULL, 0, NULL, NULL}};
+
+static int wm_obj_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ Main *bmain = CTX_data_main(C);
+ char filepath[FILE_MAX];
+
+ if (BKE_main_blendfile_path(bmain)[0] == '\0') {
+ BLI_strncpy(filepath, "untitled", sizeof(filepath));
+ }
+ else {
+ BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath));
+ }
+
+ BLI_path_extension_replace(filepath, sizeof(filepath), ".obj");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ }
+
+ WM_event_add_fileselect(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_obj_export_exec(bContext *C, wmOperator *op)
+{
+ if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+ BKE_report(op->reports, RPT_ERROR, "No filename given");
+ return OPERATOR_CANCELLED;
+ }
+ struct OBJExportParams export_params;
+ RNA_string_get(op->ptr, "filepath", export_params.filepath);
+ export_params.blen_filepath = CTX_data_main(C)->filepath;
+ export_params.export_animation = RNA_boolean_get(op->ptr, "export_animation");
+ export_params.start_frame = RNA_int_get(op->ptr, "start_frame");
+ export_params.end_frame = RNA_int_get(op->ptr, "end_frame");
+
+ export_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis");
+ export_params.up_axis = RNA_enum_get(op->ptr, "up_axis");
+ export_params.scaling_factor = RNA_float_get(op->ptr, "scaling_factor");
+ export_params.export_eval_mode = RNA_enum_get(op->ptr, "export_eval_mode");
+
+ export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects");
+ export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv");
+ export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals");
+ export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials");
+ export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh");
+ export_params.export_curves_as_nurbs = RNA_boolean_get(op->ptr, "export_curves_as_nurbs");
+
+ export_params.export_object_groups = RNA_boolean_get(op->ptr, "export_object_groups");
+ export_params.export_material_groups = RNA_boolean_get(op->ptr, "export_material_groups");
+ export_params.export_vertex_groups = RNA_boolean_get(op->ptr, "export_vertex_groups");
+ export_params.export_smooth_groups = RNA_boolean_get(op->ptr, "export_smooth_groups");
+ export_params.smooth_groups_bitflags = RNA_boolean_get(op->ptr, "smooth_group_bitflags");
+
+ OBJ_export(C, &export_params);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr)
+{
+
+ const bool export_animation = RNA_boolean_get(imfptr, "export_animation");
+ const bool export_smooth_groups = RNA_boolean_get(imfptr, "export_smooth_groups");
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+
+ /* Animation options. */
+ uiLayout *box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Animation"), ICON_ANIM);
+ uiLayout *col = uiLayoutColumn(box, false);
+ uiLayout *sub = uiLayoutColumn(col, false);
+ uiItemR(sub, imfptr, "export_animation", 0, NULL, ICON_NONE);
+ sub = uiLayoutColumn(sub, true);
+ uiItemR(sub, imfptr, "start_frame", 0, IFACE_("Frame Start"), ICON_NONE);
+ uiItemR(sub, imfptr, "end_frame", 0, IFACE_("End"), ICON_NONE);
+ uiLayoutSetEnabled(sub, export_animation);
+
+ /* Object Transform options. */
+ box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Object Properties"), ICON_OBJECT_DATA);
+ col = uiLayoutColumn(box, false);
+ sub = uiLayoutColumn(col, false);
+ uiItemR(sub, imfptr, "forward_axis", 0, IFACE_("Axis Forward"), ICON_NONE);
+ uiItemR(sub, imfptr, "up_axis", 0, IFACE_("Up"), ICON_NONE);
+ sub = uiLayoutColumn(col, false);
+ uiItemR(sub, imfptr, "scaling_factor", 0, NULL, ICON_NONE);
+ sub = uiLayoutColumnWithHeading(col, false, IFACE_("Objects"));
+ uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_eval_mode", 0, IFACE_("Properties"), ICON_NONE);
+
+ /* Options for what to write. */
+ box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Geometry Export"), ICON_EXPORT);
+ col = uiLayoutColumn(box, false);
+ sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export"));
+ uiItemR(sub, imfptr, "export_uv", 0, IFACE_("UV Coordinates"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_normals", 0, IFACE_("Normals"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_materials", 0, IFACE_("Materials"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_triangulated_mesh", 0, IFACE_("Triangulated Mesh"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_curves_as_nurbs", 0, IFACE_("Curves as NURBS"), ICON_NONE);
+
+ box = uiLayoutBox(layout);
+ uiItemL(box, IFACE_("Grouping"), ICON_GROUP);
+ col = uiLayoutColumn(box, false);
+ sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export"));
+ uiItemR(sub, imfptr, "export_object_groups", 0, IFACE_("Object Groups"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_material_groups", 0, IFACE_("Material Groups"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_vertex_groups", 0, IFACE_("Vertex Groups"), ICON_NONE);
+ uiItemR(sub, imfptr, "export_smooth_groups", 0, IFACE_("Smooth Groups"), ICON_NONE);
+ sub = uiLayoutColumn(sub, false);
+ uiLayoutSetEnabled(sub, export_smooth_groups);
+ uiItemR(sub, imfptr, "smooth_group_bitflags", 0, IFACE_("Smooth Group Bitflags"), ICON_NONE);
+}
+
+static void wm_obj_export_draw(bContext *UNUSED(C), wmOperator *op)
+{
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
+ ui_obj_export_settings(op->layout, &ptr);
+}
+
+/**
+ * Return true if any property in the UI is changed.
+ */
+static bool wm_obj_export_check(bContext *C, wmOperator *op)
+{
+ char filepath[FILE_MAX];
+ Scene *scene = CTX_data_scene(C);
+ bool changed = false;
+ RNA_string_get(op->ptr, "filepath", filepath);
+
+ if (!BLI_path_extension_check(filepath, ".obj")) {
+ BLI_path_extension_ensure(filepath, FILE_MAX, ".obj");
+ RNA_string_set(op->ptr, "filepath", filepath);
+ changed = true;
+ }
+
+ {
+ int start = RNA_int_get(op->ptr, "start_frame");
+ int end = RNA_int_get(op->ptr, "end_frame");
+ /* Set the defaults. */
+ if (start == INT_MIN) {
+ start = SFRA;
+ changed = true;
+ }
+ if (end == INT_MAX) {
+ end = EFRA;
+ changed = true;
+ }
+ /* Fix user errors. */
+ if (end < start) {
+ end = start;
+ changed = true;
+ }
+ RNA_int_set(op->ptr, "start_frame", start);
+ RNA_int_set(op->ptr, "end_frame", end);
+ }
+
+ /* Both forward and up axes cannot be the same (or same except opposite sign). */
+ if (RNA_enum_get(op->ptr, "forward_axis") % TOTAL_AXES ==
+ (RNA_enum_get(op->ptr, "up_axis") % TOTAL_AXES)) {
+ /* TODO (ankitm) Show a warning here. */
+ RNA_enum_set(op->ptr, "up_axis", RNA_enum_get(op->ptr, "up_axis") % TOTAL_AXES + 1);
+ changed = true;
+ }
+ return changed;
+}
+
+void WM_OT_obj_export(struct wmOperatorType *ot)
+{
+ ot->name = "Export Wavefront OBJ";
+ ot->description = "Save the scene to a Wavefront OBJ file";
+ ot->idname = "WM_OT_obj_export";
+
+ ot->invoke = wm_obj_export_invoke;
+ ot->exec = wm_obj_export_exec;
+ ot->poll = WM_operator_winactive;
+ ot->ui = wm_obj_export_draw;
+ ot->check = wm_obj_export_check;
+
+ WM_operator_properties_filesel(ot,
+ FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO,
+ FILE_BLENDER,
+ FILE_SAVE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
+ FILE_DEFAULTDISPLAY,
+ FILE_SORT_ALPHA);
+
+ /* Animation options. */
+ RNA_def_boolean(ot->srna,
+ "export_animation",
+ false,
+ "Export Animation",
+ "Export multiple frames instead of the current frame only");
+ RNA_def_int(ot->srna,
+ "start_frame",
+ INT_MIN, /* wm_obj_export_check uses this to set SFRA. */
+ INT_MIN,
+ INT_MAX,
+ "Start Frame",
+ "The first frame to be exported",
+ INT_MIN,
+ INT_MAX);
+ RNA_def_int(ot->srna,
+ "end_frame",
+ INT_MAX, /* wm_obj_export_check uses this to set EFRA. */
+ INT_MIN,
+ INT_MAX,
+ "End Frame",
+ "The last frame to be exported",
+ INT_MIN,
+ INT_MAX);
+ /* Object transform options. */
+ RNA_def_enum(ot->srna,
+ "forward_axis",
+ io_obj_transform_axis_forward,
+ OBJ_AXIS_NEGATIVE_Z_FORWARD,
+ "Forward Axis",
+ "");
+ RNA_def_enum(ot->srna, "up_axis", io_obj_transform_axis_up, OBJ_AXIS_Y_UP, "Up Axis", "");
+ RNA_def_float(ot->srna,
+ "scaling_factor",
+ 1.0f,
+ 0.001f,
+ 10000.0f,
+ "Scale",
+ "Upscale the object by this factor",
+ 0.01,
+ 1000.0f);
+ /* File Writer options. */
+ RNA_def_enum(ot->srna,
+ "export_eval_mode",
+ io_obj_export_evaluation_mode,
+ DAG_EVAL_VIEWPORT,
+ "Object Properties",
+ "Determines properties like object visibility, modifiers etc., where they differ "
+ "for Render and Viewport");
+ RNA_def_boolean(ot->srna,
+ "export_selected_objects",
+ false,
+ "Export Selected Objects",
+ "Export only selected objects instead of all supported objects");
+ RNA_def_boolean(ot->srna, "export_uv", true, "Export UVs", "");
+ RNA_def_boolean(ot->srna,
+ "export_normals",
+ true,
+ "Export Normals",
+ "Export per-face normals if the face is flat-shaded, per-face-per-loop "
+ "normals if smooth-shaded");
+ RNA_def_boolean(ot->srna,
+ "export_materials",
+ true,
+ "Export Materials",
+ "Export MTL library. There must be a Principled-BSDF node for image textures to "
+ "be exported to the MTL file");
+ RNA_def_boolean(ot->srna,
+ "export_triangulated_mesh",
+ false,
+ "Export Triangulated Mesh",
+ "All ngons with four or more vertices will be triangulated. Meshes in "
+ "the scene will not be affected. Behaves like Triangulate Modifier with "
+ "ngon-method: \"Beauty\", quad-method: \"Shortest Diagonal\", min vertices: 4");
+ RNA_def_boolean(ot->srna,
+ "export_curves_as_nurbs",
+ false,
+ "Export Curves as NURBS",
+ "Export curves in parametric form instead of exporting as mesh");
+
+ RNA_def_boolean(ot->srna,
+ "export_object_groups",
+ false,
+ "Export Object Groups",
+ "Append mesh name to object name, separated by a '_'");
+ RNA_def_boolean(ot->srna,
+ "export_material_groups",
+ false,
+ "Export Material Groups",
+ "Append mesh name and material name to object name, separated by a '_'");
+ RNA_def_boolean(
+ ot->srna,
+ "export_vertex_groups",
+ false,
+ "Export Vertex Groups",
+ "Export the name of the vertex group of a face. It is approximated "
+ "by choosing the vertex group with the most members among the vertices of a face");
+ RNA_def_boolean(
+ ot->srna,
+ "export_smooth_groups",
+ false,
+ "Export Smooth Groups",
+ "Every smooth-shaded face is assigned group \"1\" and every flat-shaded face \"off\"");
+ RNA_def_boolean(
+ ot->srna, "smooth_group_bitflags", false, "Generate Bitflags for Smooth Groups", "");
+}
diff --git a/source/blender/editors/io/io_obj.h b/source/blender/editors/io/io_obj.h
new file mode 100644
index 00000000000..5a0e6971edd
--- /dev/null
+++ b/source/blender/editors/io/io_obj.h
@@ -0,0 +1,25 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup editor/io
+ */
+
+#pragma once
+
+struct wmOperatorType;
+
+void WM_OT_obj_export(struct wmOperatorType *ot);
diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c
index b2788ee49a2..5dff0b69c2a 100644
--- a/source/blender/editors/io/io_ops.c
+++ b/source/blender/editors/io/io_ops.c
@@ -39,6 +39,7 @@
#include "io_cache.h"
#include "io_gpencil.h"
+#include "io_obj.h"
void ED_operatortypes_io(void)
{
@@ -68,4 +69,5 @@ void ED_operatortypes_io(void)
WM_operatortype_append(CACHEFILE_OT_open);
WM_operatortype_append(CACHEFILE_OT_reload);
+ WM_operatortype_append(WM_OT_obj_export);
}
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 3772a37ac44..6b58e1a060d 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -2605,6 +2605,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
/**
* Calculate the center and maximum excursion of mesh.
+ * (Considers all meshes in multi-object edit mode)
*/
static void calc_ortho_extent(KnifeTool_OpData *kcd)
{
@@ -2613,6 +2614,7 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
BMIter iter;
BMVert *v;
float min[3], max[3];
+ float ws[3];
INIT_MINMAX(min, max);
for (uint b = 0; b < kcd->objects_len; b++) {
@@ -2620,11 +2622,17 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd)
em = BKE_editmesh_from_object(ob);
if (kcd->cagecos[b]) {
- minmax_v3v3_v3_array(min, max, kcd->cagecos[b], em->bm->totvert);
+ for (int i = 0; i < em->bm->totvert; i++) {
+ copy_v3_v3(ws, kcd->cagecos[b][i]);
+ mul_m4_v3(ob->obmat, ws);
+ minmax_v3v3_v3(min, max, ws);
+ }
}
else {
BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- minmax_v3v3_v3(min, max, v->co);
+ copy_v3_v3(ws, v->co);
+ mul_m4_v3(ob->obmat, ws);
+ minmax_v3v3_v3(min, max, ws);
}
}
}
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 8cfcc96517c..a1a7dfac282 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -388,8 +388,7 @@ static int face_set_extract_modal(bContext *C, wmOperator *op, const wmEvent *ev
* that the mouse clicked in a viewport region and its coordinates can be used to ray-cast
* the PBVH and update the active Face Set ID. */
bScreen *screen = CTX_wm_screen(C);
- ARegion *region = BKE_screen_find_main_region_at_xy(
- screen, SPACE_VIEW3D, event->xy[0], event->xy[1]);
+ ARegion *region = BKE_screen_find_main_region_at_xy(screen, SPACE_VIEW3D, event->xy);
if (!region) {
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 5c3a8fc2277..91a512ae8e9 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -89,7 +89,7 @@ ListBase *ED_object_constraint_active_list(Object *ob)
if (ob->mode & OB_MODE_POSE) {
bPoseChannel *pchan;
- pchan = BKE_pose_channel_active(ob);
+ pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan) {
return &pchan->constraints;
}
@@ -2215,7 +2215,7 @@ static bool get_new_constraint_target(
bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add)
{
Object *obact = ED_object_active_context(C);
- bPoseChannel *pchanact = BKE_pose_channel_active(obact);
+ bPoseChannel *pchanact = BKE_pose_channel_active_if_layer_visible(obact);
bool only_curve = false, only_mesh = false, only_ob = false;
bool found = false;
@@ -2370,7 +2370,7 @@ static int constraint_add_exec(
pchan = NULL;
}
else {
- pchan = BKE_pose_channel_active(ob);
+ pchan = BKE_pose_channel_active_if_layer_visible(ob);
/* ensure not to confuse object/pose adding */
if (pchan == NULL) {
@@ -2650,7 +2650,7 @@ void POSE_OT_constraint_add_with_targets(wmOperatorType *ot)
static int pose_ik_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
bConstraint *con = NULL;
uiPopupMenu *pup;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index f06744068d5..38d0a044cb4 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -1638,10 +1638,10 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot)
/** \name Object Mode Set Operator
* \{ */
-static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
- PointerRNA *UNUSED(ptr),
- PropertyRNA *UNUSED(prop),
- bool *r_free)
+static const EnumPropertyItem *object_mode_set_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
{
const EnumPropertyItem *input = rna_enum_object_mode_items;
EnumPropertyItem *item = NULL;
@@ -1790,7 +1790,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
ot->prop = RNA_def_enum(
ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", "");
- RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf);
+ RNA_def_enum_funcs(ot->prop, object_mode_set_itemf);
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", "");
diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c
index e3c2932e17a..f9ad35d261d 100644
--- a/source/blender/editors/object/object_gpencil_modifier.c
+++ b/source/blender/editors/object/object_gpencil_modifier.c
@@ -533,6 +533,10 @@ static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op,
Object *ob,
int type)
{
+ if (ob == NULL) {
+ return NULL;
+ }
+
char modifier_name[MAX_NAME];
GpencilModifierData *md;
RNA_string_get(op->ptr, "modifier", modifier_name);
@@ -968,6 +972,9 @@ static int dash_segment_add_exec(bContext *C, wmOperator *op)
DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
op, ob, eGpencilModifierType_Dash);
+ if (dmd == NULL) {
+ return OPERATOR_FINISHED;
+ }
const int new_active_index = dmd->segment_active_index + 1;
DashGpencilModifierSegment *new_segments = MEM_malloc_arrayN(
dmd->segments_len + 1, sizeof(DashGpencilModifierSegment), __func__);
@@ -1032,6 +1039,10 @@ static int dash_segment_remove_exec(bContext *C, wmOperator *op)
DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
op, ob, eGpencilModifierType_Dash);
+ if (dmd == NULL) {
+ return OPERATOR_FINISHED;
+ }
+
if (dmd->segment_active_index < 0 || dmd->segment_active_index >= dmd->segments_len) {
return OPERATOR_CANCELLED;
}
@@ -1108,6 +1119,10 @@ static int dash_segment_move_exec(bContext *C, wmOperator *op)
DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
op, ob, eGpencilModifierType_Dash);
+ if (dmd == NULL) {
+ return OPERATOR_FINISHED;
+ }
+
if (dmd->segments_len < 2) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 5065a2c00f0..51967ff35c7 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -582,7 +582,7 @@ static int add_hook_object(const bContext *C,
BLI_strncpy(hmd->subtarget, arm->act_bone->name, sizeof(hmd->subtarget));
- pchan_act = BKE_pose_channel_active(ob);
+ pchan_act = BKE_pose_channel_active_if_layer_visible(ob);
if (LIKELY(pchan_act)) {
invert_m4_m4(pose_mat, pchan_act->pose_mat);
mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 811f20e82be..a6eb35d49b9 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -583,8 +583,8 @@ bool ED_object_parent_set(ReportList *reports,
}
case PAR_BONE:
case PAR_BONE_RELATIVE:
- pchan = BKE_pose_channel_active(par);
- pchan_eval = BKE_pose_channel_active(parent_eval);
+ pchan = BKE_pose_channel_active_if_layer_visible(par);
+ pchan_eval = BKE_pose_channel_active_if_layer_visible(parent_eval);
if (pchan == NULL) {
BKE_report(reports, RPT_ERROR, "No active bone");
@@ -2355,7 +2355,8 @@ static bool make_override_library_poll(bContext *C)
/* Object must be directly linked to be overridable. */
return (ED_operator_objectmode(C) && obact != NULL &&
(ID_IS_LINKED(obact) || (obact->instance_collection != NULL &&
- ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection))));
+ ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection) &&
+ !ID_IS_OVERRIDE_LIBRARY(obact))));
}
static const EnumPropertyItem *make_override_collections_of_linked_object_itemf(
diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc
index 719ffd36f03..4737de4d8fa 100644
--- a/source/blender/editors/object/object_remesh.cc
+++ b/source/blender/editors/object/object_remesh.cc
@@ -463,8 +463,8 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev
Object *active_object = CTX_data_active_object(C);
Mesh *mesh = (Mesh *)active_object->data;
- VoxelSizeEditCustomData *cd = (VoxelSizeEditCustomData *)MEM_callocN(
- sizeof(VoxelSizeEditCustomData), "Voxel Size Edit OP Custom Data");
+ VoxelSizeEditCustomData *cd = MEM_cnew<VoxelSizeEditCustomData>(
+ "Voxel Size Edit OP Custom Data");
/* Initial operator Custom Data setup. */
cd->draw_handle = ED_region_draw_cb_activate(
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 4c4727f51ee..c320313643d 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -1408,6 +1408,19 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
sub_v3_v3(mpt, offset_local);
mul_v3_m4v3(&pt->x, diff_mat, mpt);
}
+
+ /* Apply transform to editcurve*/
+ if (gps->editcurve != NULL) {
+ 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++) {
+ float mpt[3];
+ mul_v3_m4v3(mpt, inverse_diff_mat, bezt->vec[j]);
+ sub_v3_v3(mpt, offset_local);
+ mul_v3_m4v3(bezt->vec[j], diff_mat, mpt);
+ }
+ }
+ }
}
}
}
diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c
index 5f85f6ea0eb..df44d840ad3 100644
--- a/source/blender/editors/object/object_utils.c
+++ b/source/blender/editors/object/object_utils.c
@@ -115,7 +115,7 @@ bool ED_object_calc_active_center_for_posemode(Object *ob,
const bool select_only,
float r_center[3])
{
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) {
copy_v3_v3(r_center, pchan->pose_head);
return true;
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 367d72b0ad7..4f571fa6353 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -743,8 +743,10 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
invert_m4_m4(from_imat, from_mat);
invert_m4_m4(to_imat, to_mat);
- if (target_psmd->mesh_final->runtime.deformed_only) {
- /* we don't want to mess up target_psmd->dm when converting to global coordinates below */
+ const bool use_dm_final_indices = (target_psys->part->use_modifier_stack &&
+ !target_psmd->mesh_final->runtime.deformed_only);
+
+ if (use_dm_final_indices) {
mesh = target_psmd->mesh_final;
}
else {
@@ -755,6 +757,7 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
return false;
}
/* don't modify the original vertices */
+ /* we don't want to mess up target_psmd->dm when converting to global coordinates below */
mesh = (Mesh *)BKE_id_copy_ex(NULL, &mesh->id, NULL, LIB_ID_COPY_LOCALIZE);
/* BMESH_ONLY, deform dm may not have tessface */
@@ -825,7 +828,13 @@ static bool remap_hair_emitter(Depsgraph *depsgraph,
tpa->foffset = 0.0f;
tpa->num = nearest.index;
- tpa->num_dmcache = psys_particle_dm_face_lookup(target_mesh, mesh, tpa->num, tpa->fuv, NULL);
+ if (use_dm_final_indices) {
+ tpa->num_dmcache = DMCACHE_ISCHILD;
+ }
+ else {
+ tpa->num_dmcache = psys_particle_dm_face_lookup(
+ target_psmd->mesh_final, target_psmd->mesh_original, tpa->num, tpa->fuv, NULL);
+ }
}
else {
me = &medge[nearest.index];
diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt
index 46afa390997..31dca83a3ab 100644
--- a/source/blender/editors/render/CMakeLists.txt
+++ b/source/blender/editors/render/CMakeLists.txt
@@ -36,15 +36,15 @@ set(INC
)
set(SRC
- render_internal.c
- render_opengl.c
- render_ops.c
- render_preview.c
- render_shading.c
- render_update.c
- render_view.c
+ render_internal.cc
+ render_opengl.cc
+ render_ops.cc
+ render_preview.cc
+ render_shading.cc
+ render_update.cc
+ render_view.cc
- render_intern.h
+ render_intern.hh
)
set(LIB
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.hh
index d374717664b..d374717664b 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.hh
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.cc
index 29d829dc131..441be3a6ce3 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.cc
@@ -21,9 +21,9 @@
* \ingroup edrend
*/
-#include <math.h>
-#include <stddef.h>
-#include <string.h>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -50,6 +50,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -77,12 +78,12 @@
#include "SEQ_relations.h"
-#include "render_intern.h"
+#include "render_intern.hh"
/* Render Callbacks */
static int render_break(void *rjv);
-typedef struct RenderJob {
+struct RenderJob {
Main *main;
Scene *scene;
ViewLayer *single_layer;
@@ -109,7 +110,7 @@ typedef struct RenderJob {
ColorManagedDisplaySettings display_settings;
bool supports_glsl_draw;
bool interface_locked;
-} RenderJob;
+};
/* called inside thread! */
static bool image_buffer_calc_tile_rect(const RenderResult *rr,
@@ -121,11 +122,11 @@ static bool image_buffer_calc_tile_rect(const RenderResult *rr,
{
int tile_y, tile_height, tile_x, tile_width;
- /* When `renrect` argument is not NULL, we only refresh scan-lines. */
+ /* When `renrect` argument is not nullptr, we only refresh scan-lines. */
if (renrect) {
/* if (tile_height == recty), rendering of layer is ready,
* we should not draw, other things happen... */
- if (rr->renlay == NULL || renrect->ymax >= rr->recty) {
+ if (rr->renlay == nullptr || renrect->ymax >= rr->recty) {
return false;
}
@@ -189,7 +190,7 @@ static void image_buffer_rect_update(RenderJob *rj,
const char *viewname)
{
Scene *scene = rj->scene;
- const float *rectf = NULL;
+ const float *rectf = nullptr;
int linear_stride, linear_offset_x, linear_offset_y;
ColorManagedViewSettings *view_settings;
ColorManagedDisplaySettings *display_settings;
@@ -230,12 +231,12 @@ static void image_buffer_rect_update(RenderJob *rj,
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
return;
}
- if (rr->renlay == NULL) {
+ if (rr->renlay == nullptr) {
return;
}
rectf = RE_RenderLayerGetPass(rr->renlay, RE_PASSNAME_COMBINED, viewname);
}
- if (rectf == NULL) {
+ if (rectf == nullptr) {
return;
}
@@ -256,7 +257,7 @@ static void image_buffer_rect_update(RenderJob *rj,
IMB_partial_display_buffer_update(ibuf,
rectf,
- NULL,
+ nullptr,
linear_stride,
linear_offset_x,
linear_offset_y,
@@ -315,17 +316,17 @@ static int screen_render_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
RenderEngineType *re_type = RE_engines_find(scene->r.engine);
ViewLayer *active_layer = CTX_data_view_layer(C);
- ViewLayer *single_layer = NULL;
+ ViewLayer *single_layer = nullptr;
Render *re;
Image *ima;
View3D *v3d = CTX_wm_view3d(C);
Main *mainp = CTX_data_main(C);
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
- struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
+ struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : nullptr;
/* Cannot do render if there is not this function. */
- if (re_type->render == NULL) {
+ if (re_type->render == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -342,11 +343,11 @@ static int screen_render_exec(bContext *C, wmOperator *op)
G.is_break = false;
- RE_draw_lock_cb(re, NULL, NULL);
- RE_test_break_cb(re, NULL, render_break);
+ RE_draw_lock_cb(re, nullptr, nullptr);
+ RE_test_break_cb(re, nullptr, render_break);
ima = BKE_image_ensure_viewer(mainp, IMA_TYPE_R_RESULT, "Render Result");
- BKE_image_signal(mainp, ima, NULL, IMA_SIGNAL_FREE);
+ BKE_image_signal(mainp, ima, nullptr, IMA_SIGNAL_FREE);
BKE_image_backup_render(scene, ima, true);
/* cleanup sequencer caches before starting user triggered render.
@@ -371,7 +372,7 @@ static int screen_render_exec(bContext *C, wmOperator *op)
RE_RenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still);
}
- RE_SetReports(re, NULL);
+ RE_SetReports(re, nullptr);
/* No redraw needed, we leave state as we entered it. */
ED_update_for_newframe(mainp, CTX_data_depsgraph_pointer(C));
@@ -383,7 +384,7 @@ static int screen_render_exec(bContext *C, wmOperator *op)
static void render_freejob(void *rjv)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
BKE_color_managed_view_settings_free(&rj->view_settings);
MEM_freeN(rj);
@@ -471,15 +472,15 @@ static void make_renderinfo_string(const RenderStats *rs,
static void image_renderinfo_cb(void *rjv, RenderStats *rs)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
RenderResult *rr;
rr = RE_AcquireResultRead(rj->re);
if (rr) {
/* malloc OK here, stats_draw is not in tile threads */
- if (rr->text == NULL) {
- rr->text = MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext");
+ if (rr->text == nullptr) {
+ rr->text = static_cast<char *>(MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext"));
}
make_renderinfo_string(rs, rj->scene, rj->v3d_override, rr->error, rr->text);
@@ -493,7 +494,7 @@ static void image_renderinfo_cb(void *rjv, RenderStats *rs)
static void render_progress_update(void *rjv, float progress)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
if (rj->progress && *rj->progress != progress) {
*rj->progress = progress;
@@ -511,20 +512,22 @@ static void render_progress_update(void *rjv, float progress)
static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, ImageUser *iuser)
{
wmWindowManager *wm;
- ScrArea *first_area = NULL, *matched_area = NULL;
+ ScrArea *first_area = nullptr, *matched_area = nullptr;
/* image window, compo node users */
- for (wm = rj->main->wm.first; wm && matched_area == NULL; wm = wm->id.next) { /* only 1 wm */
+ for (wm = static_cast<wmWindowManager *>(rj->main->wm.first); wm && matched_area == nullptr;
+ wm = static_cast<wmWindowManager *>(wm->id.next)) { /* only 1 wm */
wmWindow *win;
- for (win = wm->windows.first; win && matched_area == NULL; win = win->next) {
+ for (win = static_cast<wmWindow *>(wm->windows.first); win && matched_area == nullptr;
+ win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
/* area->spacedata might be empty when toggling full-screen mode. */
- if (sima != NULL && sima->image == rj->image) {
- if (first_area == NULL) {
+ if (sima != nullptr && sima->image == rj->image) {
+ if (first_area == nullptr) {
first_area = area;
}
if (area == rj->area) {
@@ -537,12 +540,12 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
}
}
- if (matched_area == NULL) {
+ if (matched_area == nullptr) {
matched_area = first_area;
}
if (matched_area) {
- SpaceImage *sima = matched_area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(matched_area->spacedata.first);
RenderResult *main_rr = RE_AcquireResultRead(rj->re);
/* TODO(sergey): is there faster way to get the layer index? */
@@ -562,7 +565,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)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
Image *ima = rj->image;
ImBuf *ibuf;
void *lock;
@@ -584,7 +587,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
return;
}
- if (rr == NULL) {
+ if (rr == nullptr) {
return;
}
@@ -622,14 +625,14 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
static void current_scene_update(void *rjv, Scene *scene)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
rj->current_scene = scene;
rj->iuser.scene = scene;
}
static void render_startjob(void *rjv, short *stop, short *do_update, float *progress)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
rj->stop = stop;
rj->do_update = do_update;
@@ -657,7 +660,7 @@ static void render_startjob(void *rjv, short *stop, short *do_update, float *pro
rj->write_still);
}
- RE_SetReports(rj->re, NULL);
+ RE_SetReports(rj->re, nullptr);
}
static void render_image_restore_layer(RenderJob *rj)
@@ -665,15 +668,16 @@ static void render_image_restore_layer(RenderJob *rj)
wmWindowManager *wm;
/* image window, compo node users */
- for (wm = rj->main->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
+ for (wm = static_cast<wmWindowManager *>(rj->main->wm.first); wm;
+ wm = static_cast<wmWindowManager *>(wm->id.next)) { /* only 1 wm */
wmWindow *win;
- for (win = wm->windows.first; win; win = win->next) {
+ for (win = static_cast<wmWindow *>(wm->windows.first); win; win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area == rj->area) {
if (area->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
if (RE_HasSingleLayer(rj->re)) {
/* For single layer renders keep the active layer
@@ -699,7 +703,7 @@ static void render_image_restore_layer(RenderJob *rj)
static void render_endjob(void *rjv)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
/* this render may be used again by the sequencer without the active
* 'Render' where the callbacks would be re-assigned. assign dummy callbacks
@@ -725,7 +729,8 @@ static void render_endjob(void *rjv)
rj->scene->r.scemode &= ~R_NO_FRAME_UPDATE;
if (rj->single_layer) {
- nodeUpdateID(rj->scene->nodetree, &rj->scene->id);
+ BKE_ntree_update_tag_id_changed(rj->main, &rj->scene->id);
+ BKE_ntree_update_main(rj->main, nullptr);
WM_main_add_notifier(NC_NODE | NA_EDITED, rj->scene);
}
@@ -735,7 +740,7 @@ static void render_endjob(void *rjv)
/* XXX render stability hack */
G.is_rendering = false;
- WM_main_add_notifier(NC_SCENE | ND_RENDER_RESULT, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_RENDER_RESULT, nullptr);
/* Partial render result will always update display buffer
* for first render layer only. This is nice because you'll
@@ -772,7 +777,7 @@ static void render_endjob(void *rjv)
* and using one from Global will unlock exactly the same manager as
* was locked before running the job.
*/
- WM_set_locked_interface(G_MAIN->wm.first, false);
+ WM_set_locked_interface(static_cast<wmWindowManager *>(G_MAIN->wm.first), false);
DEG_tag_on_visible_update(G_MAIN, false);
}
}
@@ -780,7 +785,7 @@ static void render_endjob(void *rjv)
/* called by render, check job 'stop' value or the global */
static int render_breakjob(void *rjv)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
if (G.is_break) {
return 1;
@@ -807,7 +812,7 @@ static int render_break(void *UNUSED(rjv))
/* maybe need a way to get job send notifier? */
static void render_drawlock(void *rjv, bool lock)
{
- RenderJob *rj = rjv;
+ RenderJob *rj = static_cast<RenderJob *>(rjv);
/* If interface is locked, renderer callback shall do nothing. */
if (!rj->interface_locked) {
@@ -869,11 +874,12 @@ static void clean_viewport_memory(Main *bmain, Scene *scene)
BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, true);
/* Go over all the visible objects. */
- for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ for (wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); wm;
+ wm = static_cast<wmWindowManager *>(wm->id.next)) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- for (base = view_layer->object_bases.first; base; base = base->next) {
+ for (base = static_cast<Base *>(view_layer->object_bases.first); base; base = base->next) {
clean_viewport_memory_base(base);
}
}
@@ -891,7 +897,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *active_layer = CTX_data_view_layer(C);
- ViewLayer *single_layer = NULL;
+ ViewLayer *single_layer = nullptr;
RenderEngineType *re_type = RE_engines_find(scene->r.engine);
Render *re;
wmJob *wm_job;
@@ -900,13 +906,13 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
const bool is_animation = RNA_boolean_get(op->ptr, "animation");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
const bool use_viewport = RNA_boolean_get(op->ptr, "use_viewport");
- View3D *v3d = use_viewport ? CTX_wm_view3d(C) : NULL;
- struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
+ View3D *v3d = use_viewport ? CTX_wm_view3d(C) : nullptr;
+ struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : nullptr;
const char *name;
ScrArea *area;
/* Cannot do render if there is not this function. */
- if (re_type->render == NULL) {
+ if (re_type->render == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -962,7 +968,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
area = render_view_open(C, event->xy[0], event->xy[1], op->reports);
/* job custom data */
- rj = MEM_callocN(sizeof(RenderJob), "render job");
+ rj = MEM_cnew<RenderJob>("render job");
rj->main = bmain;
rj->scene = scene;
rj->current_scene = rj->scene;
@@ -986,7 +992,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
BKE_color_managed_view_settings_copy(&rj->view_settings, &scene->view_settings);
if (area) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
rj->orig_layer = sima->iuser.layer;
}
@@ -1030,7 +1036,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
WM_JOB_TYPE_RENDER);
WM_jobs_customdata_set(wm_job, rj, render_freejob);
WM_jobs_timer(wm_job, 0.2, NC_SCENE | ND_RENDER_RESULT, 0);
- WM_jobs_callbacks(wm_job, render_startjob, NULL, NULL, render_endjob);
+ WM_jobs_callbacks(wm_job, render_startjob, nullptr, nullptr, render_endjob);
if (RNA_struct_property_is_set(op->ptr, "layer")) {
WM_jobs_delay_start(wm_job, 0.2);
@@ -1038,7 +1044,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
/* get a render result image, and make sure it is empty */
ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
- BKE_image_signal(rj->main, ima, NULL, IMA_SIGNAL_FREE);
+ BKE_image_signal(rj->main, ima, nullptr, IMA_SIGNAL_FREE);
BKE_image_backup_render(rj->scene, ima, true);
rj->image = ima;
@@ -1098,32 +1104,32 @@ void RENDER_OT_render(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna,
"animation",
- 0,
+ false,
"Animation",
"Render files from the animation range of this scene");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_boolean(
ot->srna,
"write_still",
- 0,
+ false,
"Write Image",
"Save rendered the image to the output path (used only when animation is disabled)");
prop = RNA_def_boolean(ot->srna,
"use_viewport",
- 0,
+ false,
"Use 3D Viewport",
"When inside a 3D viewport, use layers and camera of the viewport");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_string(ot->srna,
"layer",
- NULL,
+ nullptr,
RE_MAXNAME,
"Render Layer",
"Single render layer to re-render (used only when animation is disabled)");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_string(ot->srna,
"scene",
- NULL,
+ nullptr,
MAX_ID_NAME - 2,
"Scene",
"Scene to render, current scene if not specified");
@@ -1139,7 +1145,7 @@ Scene *ED_render_job_get_scene(const bContext *C)
return rj->scene;
}
- return NULL;
+ return nullptr;
}
Scene *ED_render_job_get_current_scene(const bContext *C)
@@ -1149,7 +1155,7 @@ Scene *ED_render_job_get_current_scene(const bContext *C)
if (rj) {
return rj->current_scene;
}
- return NULL;
+ return nullptr;
}
/* Motion blur curve preset */
@@ -1180,7 +1186,7 @@ void RENDER_OT_shutter_curve_preset(wmOperatorType *ot)
{CURVE_PRESET_LINE, "LINE", 0, "Line", ""},
{CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""},
{CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
ot->name = "Shutter Curve Preset";
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.cc
index 1e1a95f2965..8d2e7e9b453 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.cc
@@ -21,9 +21,9 @@
* \ingroup render
*/
-#include <math.h>
-#include <stddef.h>
-#include <string.h>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -82,7 +82,7 @@
#include "GPU_framebuffer.h"
#include "GPU_matrix.h"
-#include "render_intern.h"
+#include "render_intern.hh"
/* Define this to get timing information. */
// #define DEBUG_TIME
@@ -95,7 +95,7 @@
* For really highres renders it might fail still. */
#define MAX_SCHEDULED_FRAMES 8
-typedef struct OGLRender {
+struct OGLRender {
Main *bmain;
Render *re;
Scene *scene;
@@ -159,7 +159,7 @@ typedef struct OGLRender {
#ifdef DEBUG_TIME
double time_start;
#endif
-} OGLRender;
+};
static bool screen_opengl_is_multiview(OGLRender *oglrender)
{
@@ -167,12 +167,12 @@ static bool screen_opengl_is_multiview(OGLRender *oglrender)
RegionView3D *rv3d = oglrender->rv3d;
RenderData *rd = &oglrender->scene->r;
- if ((rd == NULL) || ((v3d != NULL) && (rv3d == NULL))) {
+ if ((rd == nullptr) || ((v3d != nullptr) && (rv3d == nullptr))) {
return false;
}
return (rd->scemode & R_MULTIVIEW) &&
- ((v3d == NULL) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
+ ((v3d == nullptr) || (rv3d->persp == RV3D_CAMOB && v3d->camera));
}
static void screen_opengl_views_setup(OGLRender *oglrender)
@@ -192,10 +192,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
if (!is_multiview) {
/* we only have one view when multiview is off */
- rv = rr->views.first;
+ rv = static_cast<RenderView *>(rr->views.first);
- if (rv == NULL) {
- rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
+ if (rv == nullptr) {
+ rv = MEM_cnew<RenderView>("new opengl render view");
BLI_addtail(&rr->views, rv);
}
@@ -224,9 +224,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
}
/* remove all the views that are not needed */
- rv = rr->views.last;
+ rv = static_cast<RenderView *>(rr->views.last);
while (rv) {
- srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name));
+ srv = static_cast<SceneRenderView *>(
+ BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name)));
if (BKE_scene_multiview_is_render_view_active(rd, srv)) {
rv = rv->prev;
}
@@ -253,15 +254,16 @@ static void screen_opengl_views_setup(OGLRender *oglrender)
}
/* create all the views that are needed */
- for (srv = rd->views.first; srv; srv = srv->next) {
+ for (srv = static_cast<SceneRenderView *>(rd->views.first); srv; srv = srv->next) {
if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) {
continue;
}
- rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name));
+ rv = static_cast<RenderView *>(
+ BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name)));
- if (rv == NULL) {
- rv = MEM_callocN(sizeof(RenderView), "new opengl render view");
+ if (rv == nullptr) {
+ rv = MEM_cnew<RenderView>("new opengl render view");
BLI_strncpy(rv->name, srv->name, sizeof(rv->name));
BLI_addtail(&rr->views, rv);
}
@@ -291,19 +293,19 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
ARegion *region = oglrender->region;
View3D *v3d = oglrender->v3d;
RegionView3D *rv3d = oglrender->rv3d;
- Object *camera = NULL;
+ Object *camera = nullptr;
int sizex = oglrender->sizex;
int sizey = oglrender->sizey;
- const short view_context = (v3d != NULL);
+ const short view_context = (v3d != nullptr);
bool draw_sky = (scene->r.alphamode == R_ADDSKY);
- float *rectf = NULL;
- uchar *rect = NULL;
+ float *rectf = nullptr;
+ uchar *rect = nullptr;
const char *viewname = RE_GetActiveRenderView(oglrender->re);
- ImBuf *ibuf_result = NULL;
+ ImBuf *ibuf_result = nullptr;
if (oglrender->is_sequencer) {
SpaceSeq *sseq = oglrender->sseq;
- struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : NULL;
+ struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : nullptr;
/* use pre-calculated ImBuf (avoids deadlock), see: */
ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id];
@@ -318,7 +320,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
* TODO(sergey): In the case of output to float container (EXR)
* it actually makes sense to keep float buffer instead.
*/
- if (out->rect_float != NULL) {
+ if (out->rect_float != nullptr) {
IMB_rect_from_float(out);
imb_freerectfloatImBuf(out);
}
@@ -352,7 +354,8 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
ED_annotation_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
G.f &= ~G_FLAG_RENDER_VIEWPORT;
- gp_rect = MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect");
+ gp_rect = static_cast<uchar *>(
+ MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect"));
GPU_offscreen_read_pixels(oglrender->ofs, GPU_DATA_UBYTE, gp_rect);
for (i = 0; i < sizex * sizey * 4; i += 4) {
@@ -372,7 +375,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
if (view_context) {
ibuf_view = ED_view3d_draw_offscreen_imbuf(depsgraph,
scene,
- v3d->shading.type,
+ static_cast<eDrawType>(v3d->shading.type),
v3d,
region,
sizex,
@@ -392,7 +395,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
else {
ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(depsgraph,
scene,
- NULL,
+ nullptr,
OB_SOLID,
scene->camera,
oglrender->sizex,
@@ -420,9 +423,9 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
}
}
- if (ibuf_result != NULL) {
+ if (ibuf_result != nullptr) {
if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
- BKE_image_stamp_buf(scene, camera, NULL, rect, rectf, rr->rectx, rr->recty, 4);
+ 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);
IMB_freeImBuf(ibuf_result);
@@ -445,7 +448,7 @@ static void screen_opengl_render_write(OGLRender *oglrender)
&scene->r.im_format,
(scene->r.scemode & R_EXTENSION) != 0,
false,
- NULL);
+ nullptr);
/* write images as individual images or stereo */
BKE_render_result_stamp_info(scene, scene->camera, rr, false);
@@ -506,7 +509,8 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
}
rr = RE_AcquireResultRead(oglrender->re);
- for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) {
+ for (rv = static_cast<RenderView *>(rr->views.first), view_id = 0; rv;
+ rv = rv->next, view_id++) {
BLI_assert(view_id < oglrender->views_len);
RE_SetActiveRenderView(oglrender->re, rv->name);
oglrender->view_id = view_id;
@@ -530,7 +534,7 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const AnimData *adt)
{
- if (adt == NULL || adt->action == NULL) {
+ if (adt == nullptr || adt->action == nullptr) {
return;
}
@@ -539,7 +543,7 @@ static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const An
int frame_end = PEFRA;
LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
- if (fcu->driver != NULL || fcu->fpt != NULL) {
+ if (fcu->driver != nullptr || fcu->fpt != nullptr) {
/* Drivers have values for any point in time, so to get "the keyed frames" they are
* useless. Same for baked FCurves, they also have keys for every frame, which is not
* useful for rendering the keyed subset of the frames. */
@@ -568,7 +572,7 @@ static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const An
static void gather_frames_to_render_for_grease_pencil(const OGLRender *oglrender,
const bGPdata *gp)
{
- if (gp == NULL) {
+ if (gp == nullptr) {
return;
}
@@ -589,7 +593,7 @@ static void gather_frames_to_render_for_grease_pencil(const OGLRender *oglrender
static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data)
{
ID **id_p = cb_data->id_pointer;
- if (*id_p == NULL) {
+ if (*id_p == nullptr) {
return IDWALK_RET_NOP;
}
ID *id = *id_p;
@@ -602,7 +606,7 @@ static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data)
return IDWALK_RET_STOP_RECURSION;
}
- OGLRender *oglrender = cb_data->user_data;
+ OGLRender *oglrender = static_cast<OGLRender *>(cb_data->user_data);
/* Whitelist of datablocks to follow pointers into. */
const ID_Type id_type = GS(id->name);
@@ -699,7 +703,7 @@ static void gather_frames_to_render(bContext *C, OGLRender *oglrender)
/* Gather the frames from linked data-blocks (materials, shape-keys, etc.). */
BKE_library_foreach_ID_link(
- NULL, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE);
+ nullptr, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE);
}
CTX_DATA_END;
}
@@ -722,8 +726,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
const bool is_render_keyed_only = RNA_boolean_get(op->ptr, "render_keyed_only");
const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer");
const bool is_write_still = RNA_boolean_get(op->ptr, "write_still");
- const eImageFormatDepth color_depth = (is_animation) ? scene->r.im_format.depth :
- R_IMF_CHAN_DEPTH_32;
+ const eImageFormatDepth color_depth = static_cast<eImageFormatDepth>(
+ (is_animation) ? scene->r.im_format.depth : R_IMF_CHAN_DEPTH_32);
char err_out[256] = "unknown";
if (G.background) {
@@ -747,7 +751,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
is_view_context = false;
}
- if (!is_view_context && scene->camera == NULL) {
+ if (!is_view_context && scene->camera == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Scene has no camera");
return false;
}
@@ -777,7 +781,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
}
/* allocate opengl render */
- oglrender = MEM_callocN(sizeof(OGLRender), "OGLRender");
+ oglrender = MEM_cnew<OGLRender>("OGLRender");
op->customdata = oglrender;
oglrender->ofs = ofs;
@@ -801,7 +805,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->is_sequencer = is_sequencer;
if (is_sequencer) {
oglrender->sseq = CTX_wm_space_seq(C);
- ImBuf **ibufs_arr = MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__);
+ ImBuf **ibufs_arr = static_cast<ImBuf **>(
+ MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__));
oglrender->seq_data.ibufs_arr = ibufs_arr;
}
@@ -812,7 +817,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* so quad view renders camera */
ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->region);
- oglrender->rv3d = oglrender->region->regiondata;
+ oglrender->rv3d = static_cast<RegionView3D *>(oglrender->region->regiondata);
/* MUST be cleared on exit */
memset(&oglrender->scene->customdata_mask_modal,
@@ -832,13 +837,14 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
/* create image and image user */
oglrender->ima = BKE_image_ensure_viewer(oglrender->bmain, IMA_TYPE_R_RESULT, "Render Result");
- BKE_image_signal(oglrender->bmain, oglrender->ima, NULL, IMA_SIGNAL_FREE);
+ BKE_image_signal(oglrender->bmain, oglrender->ima, nullptr, IMA_SIGNAL_FREE);
BKE_image_backup_render(oglrender->scene, oglrender->ima, true);
oglrender->iuser.scene = scene;
/* create render result */
- RE_InitState(oglrender->re, NULL, &scene->r, &scene->view_layers, NULL, sizex, sizey, NULL);
+ RE_InitState(
+ oglrender->re, nullptr, &scene->r, &scene->view_layers, nullptr, sizex, sizey, nullptr);
/* create render views */
screen_opengl_views_setup(oglrender);
@@ -848,8 +854,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
oglrender->win = win;
oglrender->totvideos = 0;
- oglrender->mh = NULL;
- oglrender->movie_ctx_arr = NULL;
+ oglrender->mh = nullptr;
+ oglrender->movie_ctx_arr = nullptr;
if (is_animation) {
if (is_render_keyed_only) {
@@ -866,7 +872,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
BLI_spin_init(&oglrender->reports_lock);
}
else {
- oglrender->task_pool = NULL;
+ oglrender->task_pool = nullptr;
}
oglrender->num_scheduled_frames = 0;
BLI_mutex_init(&oglrender->task_mutex);
@@ -959,7 +965,7 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
static void screen_opengl_render_cancel(bContext *C, wmOperator *op)
{
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
}
/* share between invoke and exec */
@@ -969,7 +975,7 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op)
OGLRender *oglrender;
Scene *scene;
- oglrender = op->customdata;
+ oglrender = static_cast<OGLRender *>(op->customdata);
scene = oglrender->scene;
oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r);
@@ -983,13 +989,14 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op)
&scene->r, oglrender->sizex, oglrender->sizey, &width, &height);
oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype);
- if (oglrender->mh == NULL) {
+ if (oglrender->mh == nullptr) {
BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported");
screen_opengl_render_end(C, oglrender);
return false;
}
- oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies");
+ oglrender->movie_ctx_arr = static_cast<void **>(
+ MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies"));
for (i = 0; i < oglrender->totvideos; i++) {
Scene *scene_eval = DEG_get_evaluated_scene(oglrender->depsgraph);
@@ -1017,10 +1024,10 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op)
return true;
}
-typedef struct WriteTaskData {
+struct WriteTaskData {
RenderResult *rr;
Scene tmp_scene;
-} WriteTaskData;
+};
static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
{
@@ -1073,18 +1080,19 @@ static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
&scene->r.im_format,
(scene->r.scemode & R_EXTENSION) != 0,
true,
- NULL);
+ nullptr);
BKE_render_result_stamp_info(scene, scene->camera, rr, false);
- ok = RE_WriteRenderViewsImage(NULL, rr, scene, true, name);
+ ok = RE_WriteRenderViewsImage(nullptr, rr, scene, true, name);
if (!ok) {
BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", name);
}
}
- if (reports.list.first != NULL) {
+ if (reports.list.first != nullptr) {
BLI_spin_lock(&oglrender->reports_lock);
- for (Report *report = reports.list.first; report != NULL; report = report->next) {
- BKE_report(oglrender->reports, report->type, report->message);
+ for (Report *report = static_cast<Report *>(reports.list.first); report != nullptr;
+ report = report->next) {
+ BKE_report(oglrender->reports, static_cast<eReportType>(report->type), report->message);
}
BLI_spin_unlock(&oglrender->reports_lock);
}
@@ -1105,7 +1113,7 @@ static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
return false;
}
Scene *scene = oglrender->scene;
- WriteTaskData *task_data = MEM_mallocN(sizeof(WriteTaskData), "write task data");
+ WriteTaskData *task_data = MEM_new<WriteTaskData>("write task data");
task_data->rr = rr;
task_data->tmp_scene = *scene;
BLI_mutex_lock(&oglrender->task_mutex);
@@ -1114,18 +1122,18 @@ static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex);
}
BLI_mutex_unlock(&oglrender->task_mutex);
- BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, NULL);
+ BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, nullptr);
return true;
}
static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
{
- OGLRender *oglrender = op->customdata;
+ OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
Scene *scene = oglrender->scene;
Depsgraph *depsgraph = oglrender->depsgraph;
char name[FILE_MAX];
bool ok = false;
- const bool view_context = (oglrender->v3d != NULL);
+ const bool view_context = (oglrender->v3d != nullptr);
bool is_movie;
RenderResult *rr;
@@ -1148,7 +1156,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
&scene->r.im_format,
(scene->r.scemode & R_EXTENSION) != 0,
true,
- NULL);
+ nullptr);
if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
BLI_spin_lock(&oglrender->reports_lock);
@@ -1177,7 +1185,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
BKE_scene_camera_switch_update(scene);
}
- if (oglrender->render_frames == NULL ||
+ if (oglrender->render_frames == nullptr ||
BLI_BITMAP_TEST_BOOL(oglrender->render_frames, CFRA - PSFRA)) {
/* render into offscreen buffer */
screen_opengl_render_apply(C, oglrender);
@@ -1185,10 +1193,12 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
/* save to disk */
rr = RE_AcquireResultRead(oglrender->re);
- RenderResult *new_rr = RE_DuplicateRenderResult(rr);
- RE_ReleaseResult(oglrender->re);
+ {
+ RenderResult *new_rr = RE_DuplicateRenderResult(rr);
+ RE_ReleaseResult(oglrender->re);
- ok = schedule_write_result(oglrender, new_rr);
+ ok = schedule_write_result(oglrender, new_rr);
+ }
finally: /* Step the frame and bail early if needed */
@@ -1197,16 +1207,16 @@ finally: /* Step the frame and bail early if needed */
/* stop at the end or on error */
if (CFRA >= PEFRA || !ok) {
- screen_opengl_render_end(C, op->customdata);
- return 0;
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
+ return false;
}
- return 1;
+ return true;
}
static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- OGLRender *oglrender = op->customdata;
+ OGLRender *oglrender = static_cast<OGLRender *>(op->customdata);
const bool anim = RNA_boolean_get(op->ptr, "animation");
bool ret;
@@ -1214,7 +1224,7 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent
case EVT_ESCKEY:
/* cancel */
oglrender->pool_ok = false; /* Flag pool for cancel. */
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
return OPERATOR_FINISHED;
case TIMER:
/* render frame? */
@@ -1231,8 +1241,8 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene);
if (anim == 0) {
- screen_opengl_render_apply(C, op->customdata);
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata));
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
return OPERATOR_FINISHED;
}
@@ -1261,7 +1271,7 @@ static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEven
}
}
- oglrender = op->customdata;
+ oglrender = static_cast<OGLRender *>(op->customdata);
render_view_open(C, event->xy[0], event->xy[1], op->reports);
/* View may be changed above #USER_RENDER_DISPLAY_WINDOW. */
@@ -1284,8 +1294,8 @@ static int screen_opengl_render_exec(bContext *C, wmOperator *op)
if (!is_animation) { /* same as invoke */
/* render image */
- screen_opengl_render_apply(C, op->customdata);
- screen_opengl_render_end(C, op->customdata);
+ screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata));
+ screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata));
return OPERATOR_FINISHED;
}
@@ -1312,7 +1322,7 @@ static char *screen_opengl_render_description(struct bContext *UNUSED(C),
struct PointerRNA *ptr)
{
if (!RNA_boolean_get(ptr, "animation")) {
- return NULL;
+ return nullptr;
}
if (RNA_boolean_get(ptr, "render_keyed_only")) {
@@ -1344,32 +1354,32 @@ void RENDER_OT_opengl(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna,
"animation",
- 0,
+ false,
"Animation",
"Render files from the animation range of this scene");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"render_keyed_only",
- 0,
+ false,
"Render Keyframes Only",
"Render only those frames where selected objects have a key in their "
"animation data. Only used when rendering animation");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(
- ot->srna, "sequencer", 0, "Sequencer", "Render using the sequencer's OpenGL display");
+ ot->srna, "sequencer", false, "Sequencer", "Render using the sequencer's OpenGL display");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(
ot->srna,
"write_still",
- 0,
+ false,
"Write Image",
"Save rendered the image to the output path (used only when animation is disabled)");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"view_context",
- 1,
+ true,
"View Context",
"Use the current 3D view for rendering, else use scene settings");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.cc
index e0aa02b354d..0f10d186e6e 100644
--- a/source/blender/editors/render/render_ops.c
+++ b/source/blender/editors/render/render_ops.cc
@@ -21,7 +21,7 @@
* \ingroup edrend
*/
-#include <stdlib.h>
+#include <cstdlib>
#include "BLI_utildefines.h"
@@ -29,11 +29,11 @@
#include "WM_api.h"
-#include "render_intern.h" /* own include */
+#include "render_intern.hh" /* own include */
/***************************** render ***********************************/
-void ED_operatortypes_render(void)
+void ED_operatortypes_render()
{
WM_operatortype_append(OBJECT_OT_material_slot_add);
WM_operatortype_append(OBJECT_OT_material_slot_remove);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.cc
index 409430d28f1..55e37f85071 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.cc
@@ -23,9 +23,9 @@
/* global includes */
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
#ifndef WIN32
# include <unistd.h>
@@ -116,7 +116,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect);
/** \name Local Structs
* \{ */
-typedef struct ShaderPreview {
+struct ShaderPreview {
/* from wmJob */
void *owner;
short *stop, *do_update;
@@ -137,31 +137,32 @@ typedef struct ShaderPreview {
int sizex, sizey;
uint *pr_rect;
- int pr_method;
+ ePreviewRenderMethod pr_method;
bool own_id_copy;
Main *bmain;
Main *pr_main;
-} ShaderPreview;
+};
-typedef struct IconPreviewSize {
+struct IconPreviewSize {
struct IconPreviewSize *next, *prev;
int sizex, sizey;
uint *rect;
-} IconPreviewSize;
+};
-typedef struct IconPreview {
+struct IconPreview {
Main *bmain;
- Depsgraph *depsgraph; /* May be NULL (see #WM_OT_previews_ensure). */
+ Depsgraph *depsgraph; /* May be nullptr (see #WM_OT_previews_ensure). */
Scene *scene;
void *owner;
- ID *id, *id_copy; /* May be NULL! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */
+ ID *id,
+ *id_copy; /* May be nullptr! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */
ListBase sizes;
- /* May be NULL, is used for rendering IDs that require some other object for it to be applied on
- * before the ID can be represented as an image, for example when rendering an Action. */
+ /* May be nullptr, is used for rendering IDs that require some other object for it to be applied
+ * on before the ID can be represented as an image, for example when rendering an Action. */
struct Object *active_object;
-} IconPreview;
+};
/** \} */
@@ -169,18 +170,18 @@ typedef struct IconPreview {
/** \name Preview for Buttons
* \{ */
-static Main *G_pr_main = NULL;
-static Main *G_pr_main_grease_pencil = NULL;
+static Main *G_pr_main = nullptr;
+static Main *G_pr_main_grease_pencil = nullptr;
#ifndef WITH_HEADLESS
static Main *load_main_from_memory(const void *blend, int blend_size)
{
const int fileflags = G.fileflags;
- Main *bmain = NULL;
+ Main *bmain = nullptr;
BlendFileData *bfd;
G.fileflags |= G_FILE_NO_UI;
- bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, NULL);
+ bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, nullptr);
if (bfd) {
bmain = bfd->main;
@@ -192,7 +193,7 @@ static Main *load_main_from_memory(const void *blend, int blend_size)
}
#endif
-void ED_preview_ensure_dbase(void)
+void ED_preview_ensure_dbase()
{
#ifndef WITH_HEADLESS
static bool base_initialized = false;
@@ -212,12 +213,12 @@ static bool check_engine_supports_preview(Scene *scene)
return (type->flag & RE_USE_PREVIEW) != 0;
}
-static bool preview_method_is_render(int pr_method)
+static bool preview_method_is_render(const ePreviewRenderMethod pr_method)
{
return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER);
}
-void ED_preview_free_dbase(void)
+void ED_preview_free_dbase()
{
if (G_pr_main) {
BKE_main_free(G_pr_main);
@@ -230,11 +231,11 @@ void ED_preview_free_dbase(void)
static Scene *preview_get_scene(Main *pr_main)
{
- if (pr_main == NULL) {
- return NULL;
+ if (pr_main == nullptr) {
+ return nullptr;
}
- return pr_main->scenes.first;
+ return static_cast<Scene *>(pr_main->scenes.first);
}
static const char *preview_collection_name(const ePreviewType pr_type)
@@ -276,10 +277,10 @@ static bool render_engine_supports_ray_visibility(const Scene *sce)
static void switch_preview_collection_visibilty(ViewLayer *view_layer, const ePreviewType pr_type)
{
/* Set appropriate layer as visible. */
- LayerCollection *lc = view_layer->layer_collections.first;
+ LayerCollection *lc = static_cast<LayerCollection *>(view_layer->layer_collections.first);
const char *collection_name = preview_collection_name(pr_type);
- for (lc = lc->layer_collections.first; lc; lc = lc->next) {
+ for (lc = static_cast<LayerCollection *>(lc->layer_collections.first); lc; lc = lc->next) {
if (STREQ(lc->collection->id.name + 2, collection_name)) {
lc->collection->flag &= ~COLLECTION_HIDE_RENDER;
}
@@ -308,7 +309,8 @@ static void switch_preview_floor_material(Main *pr_main,
}
const char *material_name = preview_floor_material_name(scene, pr_method);
- Material *mat = BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2);
+ Material *mat = static_cast<Material *>(
+ BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2));
if (mat) {
me->mat[0] = mat;
}
@@ -329,7 +331,8 @@ static void switch_preview_floor_visibility(Main *pr_main,
}
}
if (base->object->type == OB_MESH) {
- switch_preview_floor_material(pr_main, base->object->data, scene, pr_method);
+ switch_preview_floor_material(
+ pr_main, static_cast<Mesh *>(base->object->data), scene, pr_method);
}
}
}
@@ -348,16 +351,16 @@ static void set_preview_visibility(Main *pr_main,
static World *preview_get_localized_world(ShaderPreview *sp, World *world)
{
- if (world == NULL) {
- return NULL;
+ if (world == nullptr) {
+ return nullptr;
}
- if (sp->worldcopy != NULL) {
+ if (sp->worldcopy != nullptr) {
return sp->worldcopy;
}
- ID *id_copy = BKE_id_copy_ex(NULL,
+ ID *id_copy = BKE_id_copy_ex(nullptr,
&world->id,
- NULL,
+ nullptr,
LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE |
LIB_ID_COPY_NO_ANIMDATA);
sp->worldcopy = (World *)id_copy;
@@ -367,9 +370,9 @@ static World *preview_get_localized_world(ShaderPreview *sp, World *world)
static ID *duplicate_ids(ID *id, const bool allow_failure)
{
- if (id == NULL) {
+ if (id == nullptr) {
/* Non-ID preview render. */
- return NULL;
+ return nullptr;
}
switch (GS(id->name)) {
@@ -379,20 +382,23 @@ static ID *duplicate_ids(ID *id, const bool allow_failure)
case ID_LA:
case ID_WO: {
BLI_assert(BKE_previewimg_id_supports_jobs(id));
- ID *id_copy = BKE_id_copy_ex(
- NULL, id, NULL, LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA);
+ ID *id_copy = BKE_id_copy_ex(nullptr,
+ id,
+ nullptr,
+ LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE |
+ LIB_ID_COPY_NO_ANIMDATA);
return id_copy;
}
/* These support threading, but don't need duplicating. */
case ID_IM:
case ID_BR:
BLI_assert(BKE_previewimg_id_supports_jobs(id));
- return NULL;
+ return nullptr;
default:
if (!allow_failure) {
BLI_assert_msg(0, "ID type preview not supported.");
}
- return NULL;
+ return nullptr;
}
}
@@ -419,13 +425,14 @@ static World *preview_get_world(Main *pr_main,
const ID_Type id_type,
const ePreviewRenderMethod pr_method)
{
- World *result = NULL;
+ World *result = nullptr;
const char *world_name = preview_world_name(sce, id_type, pr_method);
- result = BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2);
+ result = static_cast<World *>(
+ BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2));
/* No world found return first world. */
- if (result == NULL) {
- result = pr_main->worlds.first;
+ if (result == nullptr) {
+ result = static_cast<World *>(pr_main->worlds.first);
}
BLI_assert_msg(result, "Preview file has no world.");
@@ -454,7 +461,7 @@ static World *preview_prepare_world(Main *pr_main,
}
/* call this with a pointer to initialize preview scene */
-/* call this with NULL to restore assigned ID pointers in preview scene */
+/* call this with nullptr to restore assigned ID pointers in preview scene */
static Scene *preview_prepare_scene(
Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp)
{
@@ -465,7 +472,7 @@ static Scene *preview_prepare_scene(
sce = preview_get_scene(pr_main);
if (sce) {
- ViewLayer *view_layer = sce->view_layers.first;
+ ViewLayer *view_layer = static_cast<ViewLayer *>(sce->view_layers.first);
/* Only enable the combined renderpass */
view_layer->passflag = SCE_PASS_COMBINED;
@@ -491,7 +498,8 @@ static Scene *preview_prepare_scene(
sce->r.cfra = scene->r.cfra;
/* Setup the world. */
- sce->world = preview_prepare_world(pr_main, sce, scene->world, id_type, sp->pr_method);
+ sce->world = preview_prepare_world(
+ pr_main, sce, scene->world, static_cast<ID_Type>(id_type), sp->pr_method);
if (id_type == ID_TE) {
/* Texture is not actually rendered with engine, just set dummy value. */
@@ -499,13 +507,13 @@ static Scene *preview_prepare_scene(
}
if (id_type == ID_MA) {
- Material *mat = NULL, *origmat = (Material *)id;
+ Material *mat = nullptr, *origmat = (Material *)id;
if (origmat) {
/* work on a copy */
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
mat = sp->matcopy = (Material *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->materials, mat);
/* Use current scene world for lighting. */
@@ -523,10 +531,10 @@ static Scene *preview_prepare_scene(
}
/* For grease pencil, always use sphere for icon renders. */
- const ePreviewType preview_type = (sp->pr_method == PR_ICON_RENDER &&
- sp->pr_main == G_pr_main_grease_pencil) ?
- MA_SPHERE_A :
- mat->pr_type;
+ const ePreviewType preview_type = static_cast<ePreviewType>(
+ (sp->pr_method == PR_ICON_RENDER && sp->pr_main == G_pr_main_grease_pencil) ?
+ MA_SPHERE_A :
+ mat->pr_type);
set_preview_visibility(pr_main, sce, view_layer, preview_type, sp->pr_method);
}
else {
@@ -555,23 +563,23 @@ static Scene *preview_prepare_scene(
}
}
else if (id_type == ID_TE) {
- Tex *tex = NULL, *origtex = (Tex *)id;
+ Tex *tex = nullptr, *origtex = (Tex *)id;
if (origtex) {
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
tex = sp->texcopy = (Tex *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->textures, tex);
}
}
else if (id_type == ID_LA) {
- Light *la = NULL, *origla = (Light *)id;
+ Light *la = nullptr, *origla = (Light *)id;
/* work on a copy */
if (origla) {
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
la = sp->lampcopy = (Light *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->lights, la);
}
@@ -594,12 +602,12 @@ static Scene *preview_prepare_scene(
}
}
else if (id_type == ID_WO) {
- World *wrld = NULL, *origwrld = (World *)id;
+ World *wrld = nullptr, *origwrld = (World *)id;
if (origwrld) {
- BLI_assert(sp->id_copy != NULL);
+ BLI_assert(sp->id_copy != nullptr);
wrld = sp->worldcopy = (World *)sp->id_copy;
- sp->id_copy = NULL;
+ sp->id_copy = nullptr;
BLI_addtail(&pr_main->worlds, wrld);
}
@@ -610,7 +618,7 @@ static Scene *preview_prepare_scene(
return sce;
}
- return NULL;
+ return nullptr;
}
/* new UI convention: draw is in pixel space already. */
@@ -647,7 +655,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
/* test if something rendered ok */
re = RE_GetRender(name);
- if (re == NULL) {
+ if (re == nullptr) {
return false;
}
@@ -659,7 +667,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
}
else {
/* possible the job clears the views but we're still drawing T45496 */
- rv = NULL;
+ rv = nullptr;
}
if (rv && rv->rectf) {
@@ -670,8 +678,8 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty);
if (rres.rectx && rres.recty) {
- uchar *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int),
- "ed_preview_draw_rect");
+ uchar *rect_byte = static_cast<uchar *>(
+ MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect"));
float fx = rect->xmin + offx;
float fy = rect->ymin;
@@ -679,12 +687,21 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
RE_AcquiredResultGet32(re, &rres, (uint *)rect_byte, 0);
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- immDrawPixelsTex(
- &state, fx, fy, rres.rectx, rres.recty, GPU_RGBA8, false, rect_byte, 1.0f, 1.0f, NULL);
+ immDrawPixelsTex(&state,
+ fx,
+ fy,
+ rres.rectx,
+ rres.recty,
+ GPU_RGBA8,
+ false,
+ rect_byte,
+ 1.0f,
+ 1.0f,
+ nullptr);
MEM_freeN(rect_byte);
- ok = 1;
+ ok = true;
}
}
}
@@ -703,7 +720,7 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
ID *parent = (ID *)parentp;
MTex *slot = (MTex *)slotp;
SpaceProperties *sbuts = CTX_wm_space_properties(C);
- ShaderPreview *sp = WM_jobs_customdata(wm, area);
+ ShaderPreview *sp = static_cast<ShaderPreview *>(WM_jobs_customdata(wm, area));
rcti newrect;
int ok;
int newx = BLI_rcti_size_x(rect);
@@ -729,10 +746,10 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
/* start a new preview render job if signaled through sbuts->preview,
* if no render result was found and no preview render job is running,
* or if the job is running and the size of preview changed */
- if ((sbuts != NULL && sbuts->preview) ||
+ if ((sbuts != nullptr && sbuts->preview) ||
(!ok && !WM_jobs_test(wm, area, WM_JOB_TYPE_RENDER_PREVIEW)) ||
(sp && (abs(sp->sizex - newx) >= 2 || abs(sp->sizey - newy) > 2))) {
- if (sbuts != NULL) {
+ if (sbuts != nullptr) {
sbuts->preview = 0;
}
ED_preview_shader_job(C, area, id, parent, slot, newx, newy, PR_BUTS_RENDER);
@@ -796,11 +813,11 @@ static Scene *object_preview_scene_create(const struct ObjectPreviewData *previe
* viewport displays. */
CFRA = preview_data->cfra;
- ViewLayer *view_layer = scene->view_layers.first;
+ ViewLayer *view_layer = static_cast<ViewLayer *>(scene->view_layers.first);
Depsgraph *depsgraph = DEG_graph_new(
preview_data->pr_main, scene, view_layer, DAG_EVAL_VIEWPORT);
- BLI_assert(preview_data->object != NULL);
+ BLI_assert(preview_data->object != nullptr);
BLI_addtail(&preview_data->pr_main->objects, preview_data->object);
BKE_collection_object_add(preview_data->pr_main, scene->master_collection, preview_data->object);
@@ -831,26 +848,23 @@ static Scene *object_preview_scene_create(const struct ObjectPreviewData *previe
static void object_preview_render(IconPreview *preview, IconPreviewSize *preview_sized)
{
Main *preview_main = BKE_main_new();
- const float pixelsize_old = U.pixelsize;
char err_out[256] = "unknown";
BLI_assert(preview->id_copy && (preview->id_copy != preview->id));
- struct ObjectPreviewData preview_data = {
- .pr_main = preview_main,
- /* Act on a copy. */
- .object = (Object *)preview->id_copy,
- .cfra = preview->scene->r.cfra,
- .sizex = preview_sized->sizex,
- .sizey = preview_sized->sizey,
- };
+ struct ObjectPreviewData preview_data = {};
+ preview_data.pr_main = preview_main;
+ /* Act on a copy. */
+ preview_data.object = (Object *)preview->id_copy;
+ preview_data.cfra = preview->scene->r.cfra;
+ preview_data.sizex = preview_sized->sizex;
+ preview_data.sizey = preview_sized->sizey;
+
Depsgraph *depsgraph;
Scene *scene = object_preview_scene_create(&preview_data, &depsgraph);
/* Ownership is now ours. */
- preview->id_copy = NULL;
-
- U.pixelsize = 2.0f;
+ preview->id_copy = nullptr;
View3DShading shading;
BKE_screen_view3d_shading_init(&shading);
@@ -868,13 +882,11 @@ static void object_preview_render(IconPreview *preview, IconPreviewSize *preview
IB_rect,
V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS,
R_ALPHAPREMUL,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
err_out);
/* TODO: color-management? */
- U.pixelsize = pixelsize_old;
-
if (ibuf) {
icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect);
IMB_freeImBuf(ibuf);
@@ -893,15 +905,15 @@ static void object_preview_render(IconPreview *preview, IconPreviewSize *preview
static struct PoseBackup *action_preview_render_prepare(IconPreview *preview)
{
Object *object = preview->active_object;
- if (object == NULL) {
+ if (object == nullptr) {
WM_report(RPT_WARNING, "No active object, unable to apply the Action before rendering");
- return NULL;
+ return nullptr;
}
- if (object->pose == NULL) {
+ if (object->pose == nullptr) {
WM_reportf(RPT_WARNING,
"Object %s has no pose, unable to apply the Action before rendering",
object->id.name + 2);
- return NULL;
+ return nullptr;
}
/* Create a backup of the current pose. */
@@ -922,7 +934,7 @@ static struct PoseBackup *action_preview_render_prepare(IconPreview *preview)
static void action_preview_render_cleanup(IconPreview *preview, struct PoseBackup *pose_backup)
{
- if (pose_backup == NULL) {
+ if (pose_backup == nullptr) {
return;
}
ED_pose_backup_restore(pose_backup);
@@ -942,7 +954,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
/* Not all code paths that lead to this function actually provide a depsgraph.
* The "Refresh Asset Preview" button (ED_OT_lib_id_generate_preview) does,
* but WM_OT_previews_ensure does not. */
- BLI_assert(depsgraph != NULL);
+ BLI_assert(depsgraph != nullptr);
BLI_assert(preview->scene == DEG_get_input_scene(depsgraph));
/* Apply the pose before getting the evaluated scene, so that the new pose is evaluated. */
@@ -950,7 +962,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *camera_eval = scene_eval->camera;
- if (camera_eval == NULL) {
+ if (camera_eval == nullptr) {
printf("Scene has no camera, unable to render preview of %s without it.\n",
preview->id->name + 2);
return;
@@ -959,7 +971,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
/* This renders with the Workbench engine settings stored on the Scene. */
ImBuf *ibuf = ED_view3d_draw_offscreen_imbuf_simple(depsgraph,
scene_eval,
- NULL,
+ nullptr,
OB_SOLID,
camera_eval,
preview_sized->sizex,
@@ -967,8 +979,8 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview
IB_rect,
V3D_OFSDRAW_NONE,
R_ADDSKY,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
err_out);
action_preview_render_cleanup(preview, pose_backup);
@@ -994,7 +1006,7 @@ static void shader_preview_update(void *spv,
RenderResult *UNUSED(rr),
volatile struct rcti *UNUSED(rect))
{
- ShaderPreview *sp = spv;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
*(sp->do_update) = true;
}
@@ -1002,7 +1014,7 @@ static void shader_preview_update(void *spv,
/* called by renderer, checks job value */
static int shader_preview_break(void *spv)
{
- ShaderPreview *sp = spv;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(spv);
return *(sp->stop);
}
@@ -1020,13 +1032,14 @@ static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Rend
/* This is needed otherwise no RenderResult is created. */
sce->r.scemode &= ~R_BUTS_PREVIEW;
- RE_InitState(re, NULL, &sce->r, &sce->view_layers, NULL, width, height, NULL);
+ RE_InitState(re, nullptr, &sce->r, &sce->view_layers, nullptr, width, height, nullptr);
RE_SetScene(re, sce);
/* Create buffer in empty RenderView created in the init step. */
RenderResult *rr = RE_AcquireResultWrite(re);
RenderView *rv = (RenderView *)rr->views.first;
- rv->rectf = MEM_callocN(sizeof(float[4]) * width * height, "texture render result");
+ rv->rectf = static_cast<float *>(
+ MEM_callocN(sizeof(float[4]) * width * height, "texture render result"));
RE_ReleaseResult(re);
/* Get texture image pool (if any) */
@@ -1099,7 +1112,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
/* get the stuff from the builtin preview dbase */
sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp);
- if (sce == NULL) {
+ if (sce == nullptr) {
return;
}
@@ -1112,7 +1125,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
re = RE_GetRender(name);
/* full refreshed render from first tile */
- if (re == NULL) {
+ if (re == nullptr) {
re = RE_NewRender(name);
}
@@ -1162,7 +1175,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
}
/* unassign the pointers, reset vars */
- preview_prepare_scene(sp->bmain, sp->scene, NULL, GS(id->name), sp);
+ preview_prepare_scene(sp->bmain, sp->scene, nullptr, GS(id->name), sp);
/* XXX bad exception, end-exec is not being called in render, because it uses local main. */
#if 0
@@ -1177,7 +1190,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
/* runs inside thread for material and icons */
static void shader_preview_startjob(void *customdata, short *stop, short *do_update)
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
sp->stop = stop;
sp->do_update = do_update;
@@ -1208,17 +1221,17 @@ static void preview_id_copy_free(ID *id)
static void shader_preview_free(void *customdata)
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
Main *pr_main = sp->pr_main;
- ID *main_id_copy = NULL;
- ID *sub_id_copy = NULL;
+ ID *main_id_copy = nullptr;
+ ID *sub_id_copy = nullptr;
if (sp->matcopy) {
main_id_copy = (ID *)sp->matcopy;
BLI_remlink(&pr_main->materials, sp->matcopy);
}
if (sp->texcopy) {
- BLI_assert(main_id_copy == NULL);
+ BLI_assert(main_id_copy == nullptr);
main_id_copy = (ID *)sp->texcopy;
BLI_remlink(&pr_main->textures, sp->texcopy);
}
@@ -1233,7 +1246,7 @@ static void shader_preview_free(void *customdata)
BLI_remlink(&pr_main->worlds, sp->worldcopy);
}
if (sp->lampcopy) {
- BLI_assert(main_id_copy == NULL);
+ BLI_assert(main_id_copy == nullptr);
main_id_copy = (ID *)sp->lampcopy;
BLI_remlink(&pr_main->lights, sp->lampcopy);
}
@@ -1275,7 +1288,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&brush->id));
/* Use default color-spaces for brushes. */
- brush->icon_imbuf = IMB_loadiffname(path, flags, NULL);
+ brush->icon_imbuf = IMB_loadiffname(path, flags, nullptr);
/* otherwise lets try to find it in other directories */
if (!(brush->icon_imbuf)) {
@@ -1286,7 +1299,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
if (path[0]) {
/* Use default color spaces. */
- brush->icon_imbuf = IMB_loadiffname(path, flags, NULL);
+ brush->icon_imbuf = IMB_loadiffname(path, flags, nullptr);
}
}
@@ -1312,7 +1325,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect)
short ex, ey, dx, dy;
/* paranoia test */
- if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
+ if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) {
return;
}
@@ -1342,7 +1355,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect)
IMB_scalefastImBuf(ima, ex, ey);
/* if needed, convert to 32 bits */
- if (ima->rect == NULL) {
+ if (ima->rect == nullptr) {
IMB_rect_from_float(ima);
}
@@ -1370,13 +1383,13 @@ static void set_alpha(char *cp, int sizex, int sizey, char alpha)
static void icon_preview_startjob(void *customdata, short *stop, short *do_update)
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
if (sp->pr_method == PR_ICON_DEFERRED) {
- PreviewImage *prv = sp->owner;
+ PreviewImage *prv = static_cast<PreviewImage *>(sp->owner);
ImBuf *thumb;
- char *deferred_data = PRV_DEFERRED_DATA(prv);
- int source = deferred_data[0];
+ char *deferred_data = static_cast<char *>(PRV_DEFERRED_DATA(prv));
+ ThumbSource source = static_cast<ThumbSource>(deferred_data[0]);
char *path = &deferred_data[1];
// printf("generating deferred %d×%d preview for %s\n", sp->sizex, sp->sizey, path);
@@ -1395,15 +1408,15 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
ID *id = sp->id;
short idtype = GS(id->name);
- BLI_assert(id != NULL);
+ BLI_assert(id != nullptr);
if (idtype == ID_IM) {
Image *ima = (Image *)id;
- ImBuf *ibuf = NULL;
+ ImBuf *ibuf = nullptr;
ImageUser iuser;
BKE_imageuser_default(&iuser);
- if (ima == NULL) {
+ if (ima == nullptr) {
return;
}
@@ -1414,9 +1427,9 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
/* elubie: this needs to be changed: here image is always loaded if not
* already there. Very expensive for large images. Need to find a way to
* only get existing ibuf */
- ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
- if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr);
+ if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) {
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
return;
}
@@ -1424,7 +1437,7 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
*do_update = true;
- BKE_image_release_ibuf(ima, ibuf, NULL);
+ BKE_image_release_ibuf(ima, ibuf, nullptr);
}
else if (idtype == ID_BR) {
Brush *br = (Brush *)id;
@@ -1468,7 +1481,7 @@ static void common_preview_startjob(void *customdata,
short *do_update,
float *UNUSED(progress))
{
- ShaderPreview *sp = customdata;
+ ShaderPreview *sp = static_cast<ShaderPreview *>(customdata);
if (ELEM(sp->pr_method, PR_ICON_RENDER, PR_ICON_DEFERRED)) {
icon_preview_startjob(customdata, stop, do_update);
@@ -1484,12 +1497,12 @@ static void common_preview_startjob(void *customdata,
*/
static void other_id_types_preview_render(IconPreview *ip,
IconPreviewSize *cur_size,
- const int pr_method,
+ const ePreviewRenderMethod pr_method,
short *stop,
short *do_update,
float *progress)
{
- ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview");
+ ShaderPreview *sp = MEM_cnew<ShaderPreview>("Icon ShaderPreview");
/* These types don't use the ShaderPreview mess, they have their own types and functions. */
BLI_assert(!ip->id || !ELEM(GS(ip->id->name), ID_OB));
@@ -1505,7 +1518,7 @@ static void other_id_types_preview_render(IconPreview *ip,
sp->id_copy = ip->id_copy;
sp->bmain = ip->bmain;
sp->own_id_copy = false;
- Material *ma = NULL;
+ Material *ma = nullptr;
if (sp->pr_method == PR_ICON_RENDER) {
BLI_assert(ip->id);
@@ -1515,7 +1528,7 @@ static void other_id_types_preview_render(IconPreview *ip,
ma = (Material *)ip->id;
}
- if ((ma == NULL) || (ma->gp_style == NULL)) {
+ if ((ma == nullptr) || (ma->gp_style == nullptr)) {
sp->pr_main = G_pr_main;
}
else {
@@ -1553,10 +1566,12 @@ static void icon_preview_startjob_all_sizes(void *customdata,
IconPreview *ip = (IconPreview *)customdata;
IconPreviewSize *cur_size;
- for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) {
- PreviewImage *prv = ip->owner;
+ for (cur_size = static_cast<IconPreviewSize *>(ip->sizes.first); cur_size;
+ cur_size = cur_size->next) {
+ PreviewImage *prv = static_cast<PreviewImage *>(ip->owner);
/* Is this a render job or a deferred loading job? */
- const int pr_method = (prv->tag & PRV_TAG_DEFFERED) ? PR_ICON_DEFERRED : PR_ICON_RENDER;
+ const ePreviewRenderMethod pr_method = (prv->tag & PRV_TAG_DEFFERED) ? PR_ICON_DEFERRED :
+ PR_ICON_RENDER;
if (*stop) {
break;
@@ -1573,7 +1588,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
* they can skip this test. */
/* TODO: Decouple the ID-type-specific render functions from this function, so that it's not
* necessary to know here what happens inside lower-level functions. */
- const bool use_solid_render_mode = (ip->id != NULL) && ELEM(GS(ip->id->name), ID_OB, ID_AC);
+ const bool use_solid_render_mode = (ip->id != nullptr) && ELEM(GS(ip->id->name), ID_OB, ID_AC);
if (!use_solid_render_mode && preview_method_is_render(pr_method) &&
!check_engine_supports_preview(ip->scene)) {
continue;
@@ -1586,7 +1601,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
}
#endif
- if (ip->id != NULL) {
+ if (ip->id != nullptr) {
switch (GS(ip->id->name)) {
case ID_OB:
if (object_preview_is_type_supported((Object *)ip->id)) {
@@ -1599,7 +1614,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
action_preview_render(ip, cur_size);
continue;
default:
- /* Fall through to the same code as the `ip->id == NULL` case. */
+ /* Fall through to the same code as the `ip->id == nullptr` case. */
break;
}
}
@@ -1609,7 +1624,7 @@ static void icon_preview_startjob_all_sizes(void *customdata,
static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey)
{
- IconPreviewSize *cur_size = ip->sizes.first, *new_size;
+ IconPreviewSize *cur_size = static_cast<IconPreviewSize *>(ip->sizes.first);
while (cur_size) {
if (cur_size->sizex == sizex && cur_size->sizey == sizey) {
@@ -1620,7 +1635,7 @@ static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int si
cur_size = cur_size->next;
}
- new_size = MEM_callocN(sizeof(IconPreviewSize), "IconPreviewSize");
+ IconPreviewSize *new_size = MEM_cnew<IconPreviewSize>("IconPreviewSize");
new_size->sizex = sizex;
new_size->sizey = sizey;
new_size->rect = rect;
@@ -1630,7 +1645,7 @@ static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int si
static void icon_preview_endjob(void *customdata)
{
- IconPreview *ip = customdata;
+ IconPreview *ip = static_cast<IconPreview *>(customdata);
if (ip->id) {
@@ -1647,7 +1662,7 @@ static void icon_preview_endjob(void *customdata)
for (i = 0; i < NUM_ICON_SIZES; i++) {
if (prv_img->gputexture[i]) {
GPU_texture_free(prv_img->gputexture[i]);
- prv_img->gputexture[i] = NULL;
+ prv_img->gputexture[i] = nullptr;
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, ip->id);
}
}
@@ -1656,7 +1671,7 @@ static void icon_preview_endjob(void *customdata)
}
if (ip->owner) {
- PreviewImage *prv_img = ip->owner;
+ PreviewImage *prv_img = static_cast<PreviewImage *>(ip->owner);
prv_img->tag &= ~PRV_TAG_DEFFERED_RENDERING;
LISTBASE_FOREACH (IconPreviewSize *, icon_size, &ip->sizes) {
@@ -1685,20 +1700,20 @@ static void icon_preview_free(void *customdata)
bool ED_preview_id_is_supported(const ID *id)
{
- if (id == NULL) {
+ if (id == nullptr) {
return false;
}
if (GS(id->name) == ID_OB) {
return object_preview_is_type_supported((const Object *)id);
}
- return BKE_previewimg_id_get_p(id) != NULL;
+ return BKE_previewimg_id_get_p(id) != nullptr;
}
void ED_preview_icon_render(
const bContext *C, Scene *scene, ID *id, uint *rect, int sizex, int sizey)
{
- IconPreview ip = {NULL};
+ IconPreview ip = {nullptr};
short stop = false, update = false;
float progress = 0.0f;
@@ -1721,7 +1736,7 @@ void ED_preview_icon_render(
icon_preview_endjob(&ip);
BLI_freelistN(&ip.sizes);
- if (ip.id_copy != NULL) {
+ if (ip.id_copy != nullptr) {
preview_id_copy_free(ip.id_copy);
}
}
@@ -1742,10 +1757,10 @@ void ED_preview_icon_job(
WM_JOB_EXCL_RENDER,
WM_JOB_TYPE_RENDER_PREVIEW);
- ip = MEM_callocN(sizeof(IconPreview), "icon preview");
+ ip = MEM_cnew<IconPreview>("icon preview");
/* render all resolutions from suspended job too */
- old_ip = WM_jobs_customdata_get(wm_job);
+ old_ip = static_cast<IconPreview *>(WM_jobs_customdata_get(wm_job));
if (old_ip) {
BLI_movelisttolist(&ip->sizes, &old_ip->sizes);
}
@@ -1764,7 +1779,7 @@ void ED_preview_icon_job(
/* Special threading hack:
* warn main code that this preview is being rendered and cannot be freed... */
{
- PreviewImage *prv_img = owner;
+ PreviewImage *prv_img = static_cast<PreviewImage *>(owner);
if (prv_img->tag & PRV_TAG_DEFFERED) {
prv_img->tag |= PRV_TAG_DEFFERED_RENDERING;
}
@@ -1777,7 +1792,8 @@ void ED_preview_icon_job(
* Particularly important for heavy scenes and Eevee using OpenGL that blocks
* the user interface drawing. */
WM_jobs_delay_start(wm_job, (delay) ? 2.0 : 0.0);
- WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob);
+ WM_jobs_callbacks(
+ wm_job, icon_preview_startjob_all_sizes, nullptr, nullptr, icon_preview_endjob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
@@ -1789,7 +1805,7 @@ void ED_preview_shader_job(const bContext *C,
MTex *slot,
int sizex,
int sizey,
- int method)
+ ePreviewRenderMethod method)
{
Object *ob = CTX_data_active_object(C);
wmJob *wm_job;
@@ -1814,7 +1830,7 @@ void ED_preview_shader_job(const bContext *C,
"Shader Preview",
WM_JOB_EXCL_RENDER,
WM_JOB_TYPE_RENDER_PREVIEW);
- sp = MEM_callocN(sizeof(ShaderPreview), "shader preview");
+ sp = MEM_cnew<ShaderPreview>("shader preview");
/* customdata for preview thread */
sp->scene = scene;
@@ -1828,7 +1844,7 @@ void ED_preview_shader_job(const bContext *C,
sp->parent = parent;
sp->slot = slot;
sp->bmain = CTX_data_main(C);
- Material *ma = NULL;
+ Material *ma = nullptr;
/* hardcoded preview .blend for Eevee + Cycles, this should be solved
* once with custom preview .blend path for external engines */
@@ -1838,7 +1854,7 @@ void ED_preview_shader_job(const bContext *C,
ma = (Material *)id;
}
- if ((ma == NULL) || (ma->gp_style == NULL)) {
+ if ((ma == nullptr) || (ma->gp_style == nullptr)) {
sp->pr_main = G_pr_main;
}
else {
@@ -1855,7 +1871,7 @@ void ED_preview_shader_job(const bContext *C,
/* setup job */
WM_jobs_customdata_set(wm_job, sp, shader_preview_free);
WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL);
- WM_jobs_callbacks(wm_job, common_preview_startjob, NULL, shader_preview_updatejob, NULL);
+ WM_jobs_callbacks(wm_job, common_preview_startjob, nullptr, shader_preview_updatejob, nullptr);
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
@@ -1865,28 +1881,28 @@ void ED_preview_kill_jobs(wmWindowManager *wm, Main *UNUSED(bmain))
if (wm) {
/* This is called to stop all preview jobs before scene data changes, to
* avoid invalid memory access. */
- WM_jobs_kill(wm, NULL, common_preview_startjob);
- WM_jobs_kill(wm, NULL, icon_preview_startjob_all_sizes);
+ WM_jobs_kill(wm, nullptr, common_preview_startjob);
+ WM_jobs_kill(wm, nullptr, icon_preview_startjob_all_sizes);
}
}
-typedef struct PreviewRestartQueueEntry {
+struct PreviewRestartQueueEntry {
struct PreviewRestartQueueEntry *next, *prev;
enum eIconSizes size;
ID *id;
-} PreviewRestartQueueEntry;
+};
static ListBase /* #PreviewRestartQueueEntry */ G_restart_previews_queue;
-void ED_preview_restart_queue_free(void)
+void ED_preview_restart_queue_free()
{
BLI_freelistN(&G_restart_previews_queue);
}
void ED_preview_restart_queue_add(ID *id, enum eIconSizes size)
{
- PreviewRestartQueueEntry *queue_entry = MEM_mallocN(sizeof(*queue_entry), __func__);
+ PreviewRestartQueueEntry *queue_entry = MEM_new<PreviewRestartQueueEntry>(__func__);
queue_entry->size = size;
queue_entry->id = id;
BLI_addtail(&G_restart_previews_queue, queue_entry);
@@ -1905,7 +1921,7 @@ void ED_preview_restart_queue_work(const bContext *C)
}
BKE_previewimg_clear_single(preview, queue_entry->size);
- UI_icon_render_id(C, NULL, queue_entry->id, queue_entry->size, true);
+ UI_icon_render_id(C, nullptr, queue_entry->id, queue_entry->size, true);
BLI_freelinkN(&G_restart_previews_queue, queue_entry);
}
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.cc
index 54ff25ede28..992bba420c1 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.cc
@@ -20,8 +20,8 @@
* \ingroup edrend
*/
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
#include "MEM_guardedalloc.h"
@@ -96,7 +96,7 @@
#include "engines/eevee/eevee_lightcache.h"
-#include "render_intern.h" /* own include */
+#include "render_intern.hh" /* own include */
static bool object_materials_supported_poll_ex(bContext *C, const Object *ob);
@@ -106,7 +106,7 @@ static bool object_materials_supported_poll_ex(bContext *C, const Object *ob);
static bool object_array_for_shading_edit_mode_enabled_filter(const Object *ob, void *user_data)
{
- bContext *C = user_data;
+ bContext *C = static_cast<bContext *>(user_data);
if (object_materials_supported_poll_ex(C, ob)) {
if (BKE_object_is_in_editmode(ob) == true) {
return true;
@@ -123,7 +123,7 @@ static Object **object_array_for_shading_edit_mode_enabled(bContext *C, uint *r_
static bool object_array_for_shading_edit_mode_disabled_filter(const Object *ob, void *user_data)
{
- bContext *C = user_data;
+ bContext *C = static_cast<bContext *>(user_data);
if (object_materials_supported_poll_ex(C, ob)) {
if (BKE_object_is_in_editmode(ob) == false) {
return true;
@@ -159,7 +159,7 @@ static bool object_materials_supported_poll_ex(bContext *C, const Object *ob)
}
/* Material linked to obdata. */
- const ID *data = ob->data;
+ const ID *data = static_cast<ID *>(ob->data);
return (data && !ID_IS_LINKED(data) && !ID_IS_OVERRIDE_LIBRARY(data));
}
@@ -188,8 +188,8 @@ static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
- ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr);
}
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@@ -238,8 +238,8 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op)
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
- ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr);
}
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
@@ -277,7 +277,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
bool changed_multi = false;
Object *obact = CTX_data_active_object(C);
- const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL;
+ const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : nullptr;
uint objects_len = 0;
Object **objects = object_array_for_shading_edit_mode_enabled(C, &objects_len);
@@ -328,7 +328,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op))
ListBase *nurbs = BKE_curve_editNurbs_get((Curve *)ob->data);
if (nurbs) {
- for (nu = nurbs->first; nu; nu = nu->next) {
+ for (nu = static_cast<Nurb *>(nurbs->first); nu; nu = nu->next) {
if (ED_curve_nurb_select_check(v3d, nu)) {
changed = true;
nu->mat_nr = mat_nr_active;
@@ -384,7 +384,7 @@ static int material_slot_de_select(bContext *C, bool select)
{
bool changed_multi = false;
Object *obact = CTX_data_active_object(C);
- const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL;
+ const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : nullptr;
uint objects_len = 0;
Object **objects = object_array_for_shading_edit_mode_enabled(C, &objects_len);
@@ -432,7 +432,7 @@ static int material_slot_de_select(bContext *C, bool select)
int a;
if (nurbs) {
- for (nu = nurbs->first; nu; nu = nu->next) {
+ for (nu = static_cast<Nurb *>(nurbs->first); nu; nu = nu->next) {
if (nu->mat_nr == mat_nr_active) {
if (nu->bezt) {
a = nu->pntsu;
@@ -477,7 +477,7 @@ static int material_slot_de_select(bContext *C, bool select)
if (changed) {
changed_multi = true;
- DEG_id_tag_update(ob->data, ID_RECALC_SELECT);
+ DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
}
}
@@ -545,7 +545,8 @@ static int material_slot_copy_exec(bContext *C, wmOperator *UNUSED(op))
Material ***matar_object = &ob->mat;
- Material **matar = MEM_callocN(sizeof(*matar) * (size_t)ob->totcol, __func__);
+ Material **matar = static_cast<Material **>(
+ MEM_callocN(sizeof(*matar) * (size_t)ob->totcol, __func__));
for (int i = ob->totcol; i--;) {
matar[i] = ob->matbits[i] ? (*matar_object)[i] : (*matar_obdata)[i];
}
@@ -620,7 +621,7 @@ static int material_slot_move_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- slot_remap = MEM_mallocN(sizeof(uint) * ob->totcol, __func__);
+ slot_remap = static_cast<uint *>(MEM_mallocN(sizeof(uint) * ob->totcol, __func__));
range_vn_u(slot_remap, ob->totcol, 0);
@@ -643,7 +644,7 @@ void OBJECT_OT_material_slot_move(wmOperatorType *ot)
static const EnumPropertyItem material_slot_move[] = {
{1, "UP", 0, "Up", ""},
{-1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -715,8 +716,8 @@ static int material_slot_remove_unused_exec(bContext *C, wmOperator *op)
if (ob_active->mode & OB_MODE_TEXTURE_PAINT) {
Scene *scene = CTX_data_scene(C);
- ED_paint_proj_mesh_data_check(scene, ob_active, NULL, NULL, NULL, NULL);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob_active, nullptr, nullptr, nullptr, nullptr);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr);
}
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_active);
@@ -749,7 +750,8 @@ void OBJECT_OT_material_slot_remove_unused(wmOperatorType *ot)
static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
{
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
Main *bmain = CTX_data_main(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
@@ -757,17 +759,18 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
/* hook into UI */
UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
- Object *ob = (prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : NULL;
+ Object *ob = static_cast<Object *>((prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data :
+ nullptr);
/* add or copy material */
if (ma) {
Material *new_ma = (Material *)BKE_id_copy_ex(
- bmain, &ma->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
+ bmain, &ma->id, nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
ma = new_ma;
}
else {
const char *name = DATA_("Material");
- if (!(ob != NULL && ob->type == OB_GPENCIL)) {
+ if (!(ob != nullptr && ob->type == OB_GPENCIL)) {
ma = BKE_material_add(bmain, name);
}
else {
@@ -778,10 +781,10 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
}
if (prop) {
- if (ob != NULL) {
+ if (ob != nullptr) {
/* Add slot follows user-preferences for creating new slots,
* RNA pointer assignment doesn't, see: T60014. */
- if (BKE_object_material_get_p(ob, ob->actcol) == NULL) {
+ if (BKE_object_material_get_p(ob, ob->actcol) == nullptr) {
BKE_object_material_slot_add(bmain, ob);
}
}
@@ -791,7 +794,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op))
id_us_min(&ma->id);
RNA_id_pointer_create(&ma->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr, NULL);
+ RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
RNA_property_update(C, &ptr, prop);
}
@@ -823,7 +826,7 @@ void MATERIAL_OT_new(wmOperatorType *ot)
static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
{
- Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
+ Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data);
Main *bmain = CTX_data_main(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
@@ -845,7 +848,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
id_us_min(&tex->id);
RNA_id_pointer_create(&tex->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr, NULL);
+ RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
RNA_property_update(C, &ptr, prop);
}
@@ -876,7 +879,7 @@ void TEXTURE_OT_new(wmOperatorType *ot)
static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
{
- World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data;
+ World *wo = static_cast<World *>(CTX_data_pointer_get_type(C, "world", &RNA_World).data);
Main *bmain = CTX_data_main(C);
PointerRNA ptr, idptr;
PropertyRNA *prop;
@@ -884,7 +887,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
/* add or copy world */
if (wo) {
World *new_wo = (World *)BKE_id_copy_ex(
- bmain, &wo->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
+ bmain, &wo->id, nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS);
wo = new_wo;
}
else {
@@ -902,7 +905,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op))
id_us_min(&wo->id);
RNA_id_pointer_create(&wo->id, &idptr);
- RNA_property_pointer_set(&ptr, prop, idptr, NULL);
+ RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
RNA_property_update(C, &ptr, prop);
}
@@ -960,7 +963,7 @@ void SCENE_OT_view_layer_add(wmOperatorType *ot)
0,
"Blank",
"Add a new view layer with all collections disabled"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -997,7 +1000,7 @@ static int view_layer_remove_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- if (!ED_scene_view_layer_delete(bmain, scene, view_layer, NULL)) {
+ if (!ED_scene_view_layer_delete(bmain, scene, view_layer, nullptr)) {
return OPERATOR_CANCELLED;
}
@@ -1041,7 +1044,7 @@ static int view_layer_add_aov_exec(bContext *C, wmOperator *UNUSED(op))
BKE_view_layer_verify_aov(engine, scene, view_layer);
}
RE_engine_free(engine);
- engine = NULL;
+ engine = nullptr;
}
if (scene->nodetree) {
@@ -1080,7 +1083,7 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- if (view_layer->active_aov == NULL) {
+ if (view_layer->active_aov == nullptr) {
return OPERATOR_FINISHED;
}
@@ -1093,7 +1096,7 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op))
BKE_view_layer_verify_aov(engine, scene, view_layer);
}
RE_engine_free(engine);
- engine = NULL;
+ engine = nullptr;
}
if (scene->nodetree) {
@@ -1135,7 +1138,7 @@ enum {
static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op)
{
- if (scene->eevee.light_cache_data != NULL) {
+ if (scene->eevee.light_cache_data != nullptr) {
int subset = RNA_enum_get(op->ptr, "subset");
switch (subset) {
case LIGHTCACHE_SUBSET_ALL:
@@ -1261,7 +1264,7 @@ void SCENE_OT_light_cache_bake(wmOperatorType *ot)
0,
"Cubemaps Only",
"Try to only bake reflection cubemaps if irradiance grids are up to date"},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -1317,7 +1320,7 @@ static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op))
}
EEVEE_lightcache_free(scene->eevee.light_cache_data);
- scene->eevee.light_cache_data = NULL;
+ scene->eevee.light_cache_data = nullptr;
EEVEE_lightcache_info_update(&scene->eevee);
@@ -1358,7 +1361,7 @@ static int render_view_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- BKE_scene_add_render_view(scene, NULL);
+ BKE_scene_add_render_view(scene, nullptr);
scene->r.actview = BLI_listbase_count(&scene->r.views) - 1;
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
@@ -1389,7 +1392,8 @@ void SCENE_OT_render_view_add(wmOperatorType *ot)
static int render_view_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- SceneRenderView *rv = BLI_findlink(&scene->r.views, scene->r.actview);
+ SceneRenderView *rv = static_cast<SceneRenderView *>(
+ BLI_findlink(&scene->r.views, scene->r.actview));
if (!BKE_scene_remove_render_view(scene, rv)) {
return OPERATOR_CANCELLED;
@@ -1444,9 +1448,9 @@ static bool freestyle_linestyle_check_report(FreestyleLineSet *lineset, ReportLi
static bool freestyle_active_module_poll(bContext *C)
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
- FreestyleModuleConfig *module = ptr.data;
+ FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data);
- return module != NULL;
+ return module != nullptr;
}
static int freestyle_module_add_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1486,7 +1490,7 @@ static int freestyle_module_remove_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
- FreestyleModuleConfig *module = ptr.data;
+ FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data);
BKE_freestyle_module_delete(&view_layer->freestyle_config, module);
@@ -1516,7 +1520,7 @@ static int freestyle_module_move_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
- FreestyleModuleConfig *module = ptr.data;
+ FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data);
int dir = RNA_enum_get(op->ptr, "direction");
if (BKE_freestyle_module_move(&view_layer->freestyle_config, module, dir)) {
@@ -1538,7 +1542,7 @@ void SCENE_OT_freestyle_module_move(wmOperatorType *ot)
static const EnumPropertyItem direction_items[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -1574,7 +1578,7 @@ static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, NULL);
+ BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, nullptr);
DEG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
@@ -1610,7 +1614,7 @@ static bool freestyle_active_lineset_poll(bContext *C)
return false;
}
- return BKE_freestyle_lineset_get_active(&view_layer->freestyle_config) != NULL;
+ return BKE_freestyle_lineset_get_active(&view_layer->freestyle_config) != nullptr;
}
static int freestyle_lineset_copy_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1730,7 +1734,7 @@ void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot)
static const EnumPropertyItem direction_items[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -1814,7 +1818,7 @@ static int freestyle_color_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_color_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_color_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown line color modifier type");
return OPERATOR_CANCELLED;
}
@@ -1861,7 +1865,7 @@ static int freestyle_alpha_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown alpha transparency modifier type");
return OPERATOR_CANCELLED;
}
@@ -1908,7 +1912,7 @@ static int freestyle_thickness_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown line thickness modifier type");
return OPERATOR_CANCELLED;
}
@@ -1955,7 +1959,7 @@ static int freestyle_geometry_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, NULL, type) == NULL) {
+ if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, nullptr, type) == nullptr) {
BKE_report(op->reports, RPT_ERROR, "Unknown stroke geometry modifier type");
return OPERATOR_CANCELLED;
}
@@ -2014,7 +2018,7 @@ static int freestyle_modifier_remove_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
- LineStyleModifier *modifier = ptr.data;
+ LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data);
if (!freestyle_linestyle_check_report(lineset, op->reports)) {
return OPERATOR_CANCELLED;
@@ -2070,7 +2074,7 @@ static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
- LineStyleModifier *modifier = ptr.data;
+ LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data);
if (!freestyle_linestyle_check_report(lineset, op->reports)) {
return OPERATOR_CANCELLED;
@@ -2126,7 +2130,7 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config);
PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
- LineStyleModifier *modifier = ptr.data;
+ LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data);
int dir = RNA_enum_get(op->ptr, "direction");
bool changed = false;
@@ -2166,7 +2170,7 @@ void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot)
static const EnumPropertyItem direction_items[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -2252,9 +2256,12 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op)
mtex_ar[act] = mtex_ar[act - 1];
mtex_ar[act - 1] = mtexswap;
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act - 1, -1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act - 1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act - 1, -1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act, act - 1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, -1, act, false);
set_active_mtex(id, act - 1);
}
@@ -2265,9 +2272,12 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op)
mtex_ar[act] = mtex_ar[act + 1];
mtex_ar[act + 1] = mtexswap;
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act + 1, -1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act + 1, 0);
- BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act + 1, -1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, act, act + 1, false);
+ BKE_animdata_fix_paths_rename(
+ id, adt, nullptr, "texture_slots", nullptr, nullptr, -1, act, false);
set_active_mtex(id, act + 1);
}
@@ -2285,7 +2295,7 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot)
static const EnumPropertyItem slot_move[] = {
{-1, "UP", 0, "Up", ""},
{1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL},
+ {0, nullptr, 0, nullptr, nullptr},
};
/* identifiers */
@@ -2311,9 +2321,10 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot)
/* material copy/paste */
static int copy_material_exec(bContext *C, wmOperator *UNUSED(op))
{
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
- if (ma == NULL) {
+ if (ma == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2345,9 +2356,10 @@ void MATERIAL_OT_copy(wmOperatorType *ot)
static int paste_material_exec(bContext *C, wmOperator *UNUSED(op))
{
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
- if (ma == NULL) {
+ if (ma == nullptr) {
return OPERATOR_CANCELLED;
}
@@ -2382,14 +2394,14 @@ void MATERIAL_OT_paste(wmOperatorType *ot)
static short mtexcopied = 0; /* must be reset on file load */
static MTex mtexcopybuf;
-void ED_render_clear_mtex_copybuf(void)
+void ED_render_clear_mtex_copybuf()
{ /* use for file reload */
mtexcopied = 0;
}
static void copy_mtex_copybuf(ID *id)
{
- MTex **mtex = NULL;
+ MTex **mtex = nullptr;
switch (GS(id->name)) {
case ID_PA:
@@ -2413,9 +2425,9 @@ static void copy_mtex_copybuf(ID *id)
static void paste_mtex_copybuf(ID *id)
{
- MTex **mtex = NULL;
+ MTex **mtex = nullptr;
- if (mtexcopied == 0 || mtexcopybuf.tex == NULL) {
+ if (mtexcopied == 0 || mtexcopybuf.tex == nullptr) {
return;
}
@@ -2432,8 +2444,8 @@ static void paste_mtex_copybuf(ID *id)
}
if (mtex) {
- if (*mtex == NULL) {
- *mtex = MEM_mallocN(sizeof(MTex), "mtex copy");
+ if (*mtex == nullptr) {
+ *mtex = MEM_new<MTex>("mtex copy");
}
else if ((*mtex)->tex) {
id_us_min(&(*mtex)->tex->id);
@@ -2455,7 +2467,7 @@ static int copy_mtex_exec(bContext *C, wmOperator *UNUSED(op))
{
ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id;
- if (id == NULL) {
+ if (id == nullptr) {
/* copying empty slot */
ED_render_clear_mtex_copybuf();
return OPERATOR_CANCELLED;
@@ -2470,7 +2482,7 @@ static bool copy_mtex_poll(bContext *C)
{
ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id;
- return (id != NULL);
+ return (id != nullptr);
}
void TEXTURE_OT_slot_copy(wmOperatorType *ot)
@@ -2499,14 +2511,15 @@ static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op))
{
ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id;
- if (id == NULL) {
- Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data;
- Light *la = CTX_data_pointer_get_type(C, "light", &RNA_Light).data;
- World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data;
- ParticleSystem *psys =
- CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data;
- FreestyleLineStyle *linestyle =
- CTX_data_pointer_get_type(C, "line_style", &RNA_FreestyleLineStyle).data;
+ if (id == nullptr) {
+ Material *ma = static_cast<Material *>(
+ CTX_data_pointer_get_type(C, "material", &RNA_Material).data);
+ Light *la = static_cast<Light *>(CTX_data_pointer_get_type(C, "light", &RNA_Light).data);
+ World *wo = static_cast<World *>(CTX_data_pointer_get_type(C, "world", &RNA_World).data);
+ ParticleSystem *psys = static_cast<ParticleSystem *>(
+ CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data);
+ FreestyleLineStyle *linestyle = static_cast<FreestyleLineStyle *>(
+ CTX_data_pointer_get_type(C, "line_style", &RNA_FreestyleLineStyle).data);
if (ma) {
id = &ma->id;
@@ -2524,14 +2537,14 @@ static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op))
id = &linestyle->id;
}
- if (id == NULL) {
+ if (id == nullptr) {
return OPERATOR_CANCELLED;
}
}
paste_mtex_copybuf(id);
- WM_event_add_notifier(C, NC_TEXTURE | ND_SHADING_LINKS, NULL);
+ WM_event_add_notifier(C, NC_TEXTURE | ND_SHADING_LINKS, nullptr);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.cc
index e975eab4736..b2958efde9b 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.cc
@@ -20,8 +20,8 @@
* \ingroup edrend
*/
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
#include "DNA_cachefile_types.h"
#include "DNA_light_types.h"
@@ -62,7 +62,7 @@
#include "WM_api.h"
-#include <stdio.h>
+#include <cstdio>
/* -------------------------------------------------------------------- */
/** \name Render Engines
@@ -82,8 +82,8 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
continue;
}
- View3D *v3d = area->spacedata.first;
- RegionView3D *rv3d = region->regiondata;
+ View3D *v3d = static_cast<View3D *>(area->spacedata.first);
+ RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
RenderEngine *engine = rv3d->render_engine;
/* call update if the scene changed, or if the render engine
@@ -94,7 +94,7 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
bContext *C = CTX_create();
CTX_data_main_set(C, bmain);
CTX_data_scene_set(C, scene);
- CTX_wm_manager_set(C, bmain->wm.first);
+ CTX_wm_manager_set(C, static_cast<wmWindowManager *>(bmain->wm.first));
CTX_wm_window_set(C, window);
CTX_wm_screen_set(C, WM_window_get_active_screen(window));
CTX_wm_area_set(C, area);
@@ -111,15 +111,15 @@ void ED_render_view3d_update(Depsgraph *depsgraph,
else {
RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type);
if (updated) {
- DRW_notify_view_update((&(DRWUpdateContext){
- .bmain = bmain,
- .depsgraph = depsgraph,
- .scene = scene,
- .view_layer = view_layer,
- .region = region,
- .v3d = v3d,
- .engine_type = engine_type,
- }));
+ DRWUpdateContext drw_context = {nullptr};
+ drw_context.bmain = bmain;
+ drw_context.depsgraph = depsgraph;
+ drw_context.scene = scene;
+ drw_context.view_layer = view_layer;
+ drw_context.region = region;
+ drw_context.v3d = v3d;
+ drw_context.engine_type = engine_type;
+ DRW_notify_view_update(&drw_context);
}
}
}
@@ -148,7 +148,7 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, const bool
recursive_check = true;
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(window);
@@ -166,13 +166,13 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *area)
{
/* clear all render engines in this area */
ARegion *region;
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
if (area->spacetype != SPACE_VIEW3D) {
return;
}
- for (region = area->regionbase.first; region; region = region->next) {
+ for (region = static_cast<ARegion *>(area->regionbase.first); region; region = region->next) {
if (region->regiontype != RGN_TYPE_WINDOW || !(region->regiondata)) {
continue;
}
@@ -183,16 +183,18 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *area)
void ED_render_engine_changed(Main *bmain, const bool update_scene_data)
{
/* on changing the render engine type, clear all running render engines */
- for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (bScreen *screen = static_cast<bScreen *>(bmain->screens.first); screen;
+ screen = static_cast<bScreen *>(screen->id.next)) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
ED_render_engine_area_exit(bmain, area);
}
}
- RE_FreePersistentData(NULL);
+ RE_FreePersistentData(nullptr);
/* Inform all render engines and draw managers. */
- DEGEditorUpdateContext update_ctx = {NULL};
+ DEGEditorUpdateContext update_ctx = {nullptr};
update_ctx.bmain = bmain;
- for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ for (Scene *scene = static_cast<Scene *>(bmain->scenes.first); scene;
+ scene = static_cast<Scene *>(scene->id.next)) {
update_ctx.scene = scene;
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
/* TDODO(sergey): Iterate over depsgraphs instead? */
@@ -258,14 +260,16 @@ static void texture_changed(Main *bmain, Tex *tex)
/* icons */
BKE_icon_changed(BKE_icon_id_ensure(&tex->id));
- for (scene = bmain->scenes.first; scene; scene = scene->id.next) {
+ for (scene = static_cast<Scene *>(bmain->scenes.first); scene;
+ scene = static_cast<Scene *>(scene->id.next)) {
/* paint overlays */
- for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) {
+ for (view_layer = static_cast<ViewLayer *>(scene->view_layers.first); view_layer;
+ view_layer = view_layer->next) {
BKE_paint_invalidate_overlay_tex(scene, view_layer, tex);
}
/* find compositing nodes */
if (scene->use_nodes && scene->nodetree) {
- for (node = scene->nodetree->nodes.first; node; node = node->next) {
+ for (node = static_cast<bNode *>(scene->nodetree->nodes.first); node; node = node->next) {
if (node->id == &tex->id) {
ED_node_tag_update_id(&scene->id);
}
@@ -288,7 +292,8 @@ static void image_changed(Main *bmain, Image *ima)
BKE_icon_changed(BKE_icon_id_ensure(&ima->id));
/* textures */
- for (tex = bmain->textures.first; tex; tex = tex->id.next) {
+ for (tex = static_cast<Tex *>(bmain->textures.first); tex;
+ tex = static_cast<Tex *>(tex->id.next)) {
if (tex->type == TEX_IMAGE && tex->ima == ima) {
texture_changed(bmain, tex);
}
@@ -300,10 +305,11 @@ static void scene_changed(Main *bmain, Scene *scene)
Object *ob;
/* glsl */
- for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ for (ob = static_cast<Object *>(bmain->objects.first); ob;
+ ob = static_cast<Object *>(ob->id.next)) {
if (ob->mode & OB_MODE_TEXTURE_PAINT) {
BKE_texpaint_slots_refresh_object(scene, ob);
- ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr);
}
}
}
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.cc
index 9163718ffad..980cd899120 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.cc
@@ -21,8 +21,8 @@
* \ingroup edrend
*/
-#include <stddef.h>
-#include <string.h>
+#include <cstddef>
+#include <cstring>
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
@@ -47,7 +47,7 @@
#include "wm_window.h"
-#include "render_intern.h"
+#include "render_intern.hh"
/*********************** utilities for finding areas *************************/
@@ -59,11 +59,11 @@
static ScrArea *biggest_non_image_area(bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area, *big = NULL;
+ ScrArea *area, *big = nullptr;
int size, maxsize = 0, bwmaxsize = 0;
short foundwin = 0;
- for (area = screen->areabase.first; area; area = area->next) {
+ for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) {
if (area->winx > 30 && area->winy > 30) {
size = area->winx * area->winy;
if (!area->full && area->spacetype == SPACE_PROPERTIES) {
@@ -86,17 +86,17 @@ static ScrArea *biggest_non_image_area(bContext *C)
static ScrArea *find_area_showing_r_result(bContext *C, Scene *scene, wmWindow **win)
{
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *area = NULL;
+ ScrArea *area = nullptr;
SpaceImage *sima;
/* find an imagewindow showing render result */
- for (*win = wm->windows.first; *win; *win = (*win)->next) {
+ for (*win = static_cast<wmWindow *>(wm->windows.first); *win; *win = (*win)->next) {
if (WM_window_get_active_scene(*win) == scene) {
const bScreen *screen = WM_window_get_active_screen(*win);
- for (area = screen->areabase.first; area; area = area->next) {
+ for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) {
if (area->spacetype == SPACE_IMAGE) {
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) {
break;
}
@@ -118,9 +118,9 @@ static ScrArea *find_area_image_empty(bContext *C)
SpaceImage *sima;
/* find an imagewindow showing render result */
- for (area = screen->areabase.first; area; area = area->next) {
+ for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) {
if (area->spacetype == SPACE_IMAGE) {
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
if ((sima->mode == SI_MODE_VIEW) && !sima->image) {
break;
}
@@ -136,13 +136,13 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- wmWindow *win = NULL;
- ScrArea *area = NULL;
+ wmWindow *win = nullptr;
+ ScrArea *area = nullptr;
SpaceImage *sima;
bool area_was_image = false;
if (U.render_display_type == USER_RENDER_DISPLAY_NONE) {
- return NULL;
+ return nullptr;
}
if (U.render_display_type == USER_RENDER_DISPLAY_WINDOW) {
@@ -168,14 +168,14 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
true,
false,
true,
- WIN_ALIGN_LOCATION_CENTER) == NULL) {
+ WIN_ALIGN_LOCATION_CENTER) == nullptr) {
BKE_report(reports, RPT_ERROR, "Failed to open window!");
- return NULL;
+ return nullptr;
}
area = CTX_wm_area(C);
if (BLI_listbase_is_single(&area->spacedata) == false) {
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
sima->flag |= SI_PREVSPACE;
}
}
@@ -185,7 +185,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
/* If the active screen is already in full-screen mode, skip this and
* unset the area, so that the full-screen area is just changed later. */
if (area && area->full) {
- area = NULL;
+ area = nullptr;
}
else {
if (area && area->spacetype == SPACE_IMAGE) {
@@ -199,7 +199,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
if (!area) {
area = find_area_showing_r_result(C, scene, &win);
- if (area == NULL) {
+ if (area == nullptr) {
area = find_area_image_empty(C);
}
@@ -208,12 +208,12 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
wm_window_raise(win);
}
- if (area == NULL) {
+ if (area == nullptr) {
/* find largest open non-image area */
area = biggest_non_image_area(C);
if (area) {
ED_area_newspace(C, area, SPACE_IMAGE, true);
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
/* Makes "Escape" go back to previous space. */
sima->flag |= SI_PREVSPACE;
@@ -228,7 +228,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0);
if (area->spacetype != SPACE_IMAGE) {
// XXX newspace(area, SPACE_IMAGE);
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
/* Makes "Escape" go back to previous space. */
sima->flag |= SI_PREVSPACE;
@@ -236,7 +236,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
}
}
- sima = area->spacedata.first;
+ sima = static_cast<SpaceImage *>(area->spacedata.first);
sima->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
/* get the correct image, and scale it */
@@ -272,7 +272,7 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
/* ensure image editor full-screen and area full-screen states are in sync */
if ((sima->flag & SI_FULLWINDOW) && !area->full) {
@@ -333,7 +333,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
ScrArea *area = find_area_showing_r_result(C, CTX_data_scene(C), &winshow);
/* is there another window on current scene showing result? */
- for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) {
+ for (win = static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first); win; win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
if ((WM_window_is_temp_screen(win) &&
@@ -348,7 +348,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
if (area) {
/* but don't close it when rendering */
if (G.is_rendering == false) {
- SpaceImage *sima = area->spacedata.first;
+ SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
if (sima->flag & SI_PREVSPACE) {
sima->flag &= ~SI_PREVSPACE;
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 5dc6fe88663..95711fe20fa 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1667,7 +1667,7 @@ static bool event_in_markers_region(const ARegion *region, const wmEvent *event)
{
rcti rect = region->winrct;
rect.ymax = rect.ymin + UI_MARKER_MARGIN_Y;
- return BLI_rcti_isect_pt(&rect, event->xy[0], event->xy[1]);
+ return BLI_rcti_isect_pt_v(&rect, event->xy);
}
/**
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 304205d0cc4..04df90bf912 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -501,7 +501,7 @@ static eContextResult screen_ctx_active_pose_bone(const bContext *C, bContextDat
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
Object *obpose = BKE_object_pose_armature_get(obact);
- bPoseChannel *pchan = BKE_pose_channel_active(obpose);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(obpose);
if (pchan) {
CTX_data_pointer_set(result, &obpose->id, &RNA_PoseBone, pchan);
return CTX_RESULT_OK;
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index d017345b523..b9c92c1664d 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -1128,8 +1128,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
AREAMAP_FROM_SCREEN(screen), &screen_rect, event->xy[0], event->xy[1]) == NULL)) {
/* What area are we now in? */
- ScrArea *area = BKE_screen_find_area_xy(
- screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
if (area == sad->sa1) {
/* Same area, so possible split. */
@@ -1173,7 +1172,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* gesture is large enough? */
if (is_gesture) {
/* second area, for join when (sa1 != sa2) */
- sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
/* apply sends event */
actionzone_apply(C, op, sad->az->type);
actionzone_exit(op);
@@ -1241,12 +1240,16 @@ static ScrEdge *screen_area_edge_from_cursor(const bContext *C,
int borderwidth = (4 * UI_DPI_FAC);
ScrArea *sa1, *sa2;
if (screen_geom_edge_is_horizontal(actedge)) {
- sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] + borderwidth);
- sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] - borderwidth);
+ sa1 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0], cursor[1] + borderwidth});
+ sa2 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0], cursor[1] - borderwidth});
}
else {
- sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] + borderwidth, cursor[1]);
- sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] - borderwidth, cursor[1]);
+ sa1 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0] + borderwidth, cursor[1]});
+ sa2 = BKE_screen_find_area_xy(
+ screen, SPACE_TYPE_ANY, (const int[2]){cursor[0] - borderwidth, cursor[1]});
}
bool isGlobal = ((sa1 && ED_area_is_global(sa1)) || (sa2 && ED_area_is_global(sa2)));
if (!isGlobal) {
@@ -1334,8 +1337,7 @@ static int area_swap_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE:
/* second area, for join */
- sad->sa2 = BKE_screen_find_area_xy(
- CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ sad->sa2 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy);
break;
case LEFTMOUSE: /* release LMB */
if (event->val == KM_RELEASE) {
@@ -2508,8 +2510,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
ED_area_tag_redraw(sd->sarea);
}
/* area context not set */
- sd->sarea = BKE_screen_find_area_xy(
- CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy);
if (sd->sarea) {
ScrArea *area = sd->sarea;
@@ -3517,7 +3518,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE: {
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
jd->dir = area_getorientation(jd->sa1, jd->sa2);
if (area == jd->sa1) {
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index b26291c4d1b..4bc9f1e2565 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -166,8 +166,7 @@ static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (use_crop) {
area = CTX_wm_area(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area_test = BKE_screen_find_area_xy(
- screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]);
+ ScrArea *area_test = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
if (area_test != NULL) {
area = area_test;
}
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index b826ff8701d..517125f016e 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -59,6 +59,7 @@ set(SRC
sculpt.c
sculpt_automasking.c
sculpt_boundary.c
+ sculpt_brushes.c
sculpt_cloth.c
sculpt_detail.c
sculpt_dyntopo.c
@@ -71,6 +72,7 @@ set(SRC
sculpt_mask_expand.c
sculpt_mask_init.c
sculpt_multiplane_scrape.c
+ sculpt_ops.c
sculpt_paint_color.c
sculpt_pose.c
sculpt_smooth.c
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 7df5848e068..8a5d75d5f77 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -6623,7 +6623,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
}
}
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ ED_node_tree_propagate_change(C, bmain, ntree);
/* In case we added more than one node, position them too. */
nodePositionPropagate(out_node);
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 90887b9fc39..09013ea00f4 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -25,6 +25,8 @@
#include "BKE_paint.h"
+#include "BLI_compiler_compat.h"
+#include "BLI_math.h"
#include "BLI_rect.h"
#include "DNA_scene_types.h"
@@ -404,8 +406,61 @@ bool facemask_paint_poll(struct bContext *C);
/**
* Uses symm to selectively flip any axis of a coordinate.
*/
-void flip_v3_v3(float out[3], const float in[3], const enum ePaintSymmetryFlags symm);
-void flip_qt_qt(float out[4], const float in[4], const enum ePaintSymmetryFlags symm);
+
+BLI_INLINE void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm)
+{
+ if (symm & PAINT_SYMM_X) {
+ out[0] = -in[0];
+ }
+ else {
+ out[0] = in[0];
+ }
+ if (symm & PAINT_SYMM_Y) {
+ out[1] = -in[1];
+ }
+ else {
+ out[1] = in[1];
+ }
+ if (symm & PAINT_SYMM_Z) {
+ out[2] = -in[2];
+ }
+ else {
+ out[2] = in[2];
+ }
+}
+
+BLI_INLINE void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
+{
+ float axis[3], angle;
+
+ quat_to_axis_angle(axis, &angle, in);
+ normalize_v3(axis);
+
+ if (symm & PAINT_SYMM_X) {
+ axis[0] *= -1.0f;
+ angle *= -1.0f;
+ }
+ if (symm & PAINT_SYMM_Y) {
+ axis[1] *= -1.0f;
+ angle *= -1.0f;
+ }
+ if (symm & PAINT_SYMM_Z) {
+ axis[2] *= -1.0f;
+ angle *= -1.0f;
+ }
+
+ axis_angle_normalized_to_quat(out, axis, angle);
+}
+
+BLI_INLINE void flip_v3(float v[3], const ePaintSymmetryFlags symm)
+{
+ flip_v3_v3(v, v, symm);
+}
+
+BLI_INLINE void flip_qt(float quat[4], const ePaintSymmetryFlags symm)
+{
+ flip_qt_qt(quat, quat, symm);
+}
/* stroke operator */
typedef enum BrushStrokeMode {
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 541893f7957..95a0aba1ffb 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -397,51 +397,6 @@ static Image *imapaint_face_image(Object *ob, Mesh *me, int face_index)
return ima;
}
-void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm)
-{
- if (symm & PAINT_SYMM_X) {
- out[0] = -in[0];
- }
- else {
- out[0] = in[0];
- }
- if (symm & PAINT_SYMM_Y) {
- out[1] = -in[1];
- }
- else {
- out[1] = in[1];
- }
- if (symm & PAINT_SYMM_Z) {
- out[2] = -in[2];
- }
- else {
- out[2] = in[2];
- }
-}
-
-void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm)
-{
- float axis[3], angle;
-
- quat_to_axis_angle(axis, &angle, in);
- normalize_v3(axis);
-
- if (symm & PAINT_SYMM_X) {
- axis[0] *= -1.0f;
- angle *= -1.0f;
- }
- if (symm & PAINT_SYMM_Y) {
- axis[1] *= -1.0f;
- angle *= -1.0f;
- }
- if (symm & PAINT_SYMM_Z) {
- axis[2] *= -1.0f;
- angle *= -1.0f;
- }
-
- axis_angle_normalized_to_quat(out, axis, angle);
-}
-
void paint_sample_color(
bContext *C, ARegion *region, int x, int y, bool texpaint_proj, bool use_palette)
{
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index b764d0e1b5b..fd550790f2e 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1329,103 +1329,6 @@ static void sculpt_rake_data_update(struct SculptRakeData *srd, const float co[3
}
}
-static void sculpt_rake_rotate(const SculptSession *ss,
- const float sculpt_co[3],
- const float v_co[3],
- float factor,
- float r_delta[3])
-{
- float vec_rot[3];
-
-#if 0
- /* lerp */
- sub_v3_v3v3(vec_rot, v_co, sculpt_co);
- mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot);
- add_v3_v3(vec_rot, sculpt_co);
- sub_v3_v3v3(r_delta, vec_rot, v_co);
- mul_v3_fl(r_delta, factor);
-#else
- /* slerp */
- float q_interp[4];
- sub_v3_v3v3(vec_rot, v_co, sculpt_co);
-
- copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry);
- pow_qt_fl_normalized(q_interp, factor);
- mul_qt_v3(q_interp, vec_rot);
-
- add_v3_v3(vec_rot, sculpt_co);
- sub_v3_v3v3(r_delta, vec_rot, v_co);
-#endif
-}
-
-/**
- * Align the grab delta to the brush normal.
- *
- * \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`.
- */
-static void sculpt_project_v3_normal_align(SculptSession *ss,
- const float normal_weight,
- float grab_delta[3])
-{
- /* Signed to support grabbing in (to make a hole) as well as out. */
- const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta);
-
- /* This scale effectively projects the offset so dragging follows the cursor,
- * as the normal points towards the view, the scale increases. */
- float len_view_scale;
- {
- float view_aligned_normal[3];
- project_plane_v3_v3v3(
- view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal);
- len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm));
- len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f;
- }
-
- mul_v3_fl(grab_delta, 1.0f - normal_weight);
- madd_v3_v3fl(
- grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name SculptProjectVector
- *
- * Fast-path for #project_plane_v3_v3v3
- * \{ */
-
-typedef struct SculptProjectVector {
- float plane[3];
- float len_sq;
- float len_sq_inv_neg;
- bool is_valid;
-
-} SculptProjectVector;
-
-/**
- * \param plane: Direction, can be any length.
- */
-static void sculpt_project_v3_cache_init(SculptProjectVector *spvc, const float plane[3])
-{
- copy_v3_v3(spvc->plane, plane);
- spvc->len_sq = len_squared_v3(spvc->plane);
- spvc->is_valid = (spvc->len_sq > FLT_EPSILON);
- spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f;
-}
-
-/**
- * Calculate the projection.
- */
-static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3], float r_vec[3])
-{
-#if 0
- project_plane_v3_v3v3(r_vec, vec, spvc->plane);
-#else
- /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */
- madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg);
-#endif
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1835,15 +1738,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test,
/* ===== Sculpting =====
*/
-static void flip_v3(float v[3], const ePaintSymmetryFlags symm)
-{
- flip_v3_v3(v, v, symm);
-}
-
-static void flip_qt(float quat[4], const ePaintSymmetryFlags symm)
-{
- flip_qt_qt(quat, quat, symm);
-}
static float calc_overlap(StrokeCache *cache, const char symm, const char axis, const float angle)
{
@@ -1913,9 +1807,9 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
* (optionally using original coordinates).
*
* Functions are:
- * - #calc_area_center
- * - #calc_area_normal
- * - #calc_area_normal_and_center
+ * - #SCULPT_calc_area_center
+ * - #SCULPT_calc_area_normal
+ * - #SCULPT_calc_area_normal_and_center
*
* \note These are all _very_ similar, when changing one, check others.
* \{ */
@@ -2137,7 +2031,7 @@ static void calc_area_normal_and_center_reduce(const void *__restrict UNUSED(use
add_v2_v2_int(join->count_co, anctd->count_co);
}
-static void calc_area_center(
+void SCULPT_calc_area_center(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
@@ -2238,7 +2132,7 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
* This calculates flatten center and area normal together,
* amortizing the memory bandwidth and loop overhead to calculate both at the same time.
*/
-static void calc_area_normal_and_center(
+void SCULPT_calc_area_normal_and_center(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
@@ -2633,9 +2527,23 @@ void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3])
continue;
}
- if (ss->cache && (ss->cache->flag & (CLIP_X << i)) &&
- (fabsf(co[i]) <= ss->cache->clip_tolerance[i])) {
- co[i] = 0.0f;
+ bool do_clip = false;
+ float co_clip[3];
+ if (ss->cache && (ss->cache->flag & (CLIP_X << i))) {
+ /* Take possible mirror object into account. */
+ mul_v3_m4v3(co_clip, ss->cache->clip_mirror_mtx, co);
+
+ if (fabsf(co_clip[i]) <= ss->cache->clip_tolerance[i]) {
+ co_clip[i] = 0.0f;
+ float imtx[4][4];
+ invert_m4_m4(imtx, ss->cache->clip_mirror_mtx);
+ mul_m4_v3(imtx, co_clip);
+ do_clip = true;
+ }
+ }
+
+ if (do_clip) {
+ co[i] = co_clip[i];
}
else {
co[i] = val[i];
@@ -2856,10 +2764,6 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
/** \} */
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Topology Rake (Shared Utility)
- * \{ */
-
typedef struct {
SculptSession *ss;
const float *ray_start;
@@ -2885,1295 +2789,6 @@ typedef struct {
bool original;
} SculptFindNearestToRayData;
-static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
-
- float direction[3];
- copy_v3_v3(direction, ss->cache->grab_delta_symmetry);
-
- float tmp[3];
- mul_v3_v3fl(
- tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
- sub_v3_v3(direction, tmp);
- normalize_v3(direction);
-
- /* Cancel if there's no grab data. */
- if (is_zero_v3(direction)) {
- return;
- }
-
- const float bstrength = clamp_f(data->strength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade =
- bstrength *
- SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) *
- ss->cache->pressure;
-
- float avg[3], val[3];
-
- SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
-
- sub_v3_v3v3(val, avg, vd.co);
-
- madd_v3_v3v3fl(val, vd.co, val, fade);
-
- SCULPT_clip(sd, ss, vd.co, val);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void bmesh_topology_rake(
- Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- const float strength = clamp_f(bstrength, 0.0f, 1.0f);
-
- /* Interactions increase both strength and quality. */
- const int iterations = 3;
-
- int iteration;
- const int count = iterations * strength + 1;
- const float factor = iterations * strength / count;
-
- for (iteration = 0; iteration <= count; iteration++) {
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .strength = factor,
- };
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
-
- BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Mask Brush
- * \{ */
-
-static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- const float fade = SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
-
- if (bstrength > 0.0f) {
- (*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
- }
- else {
- (*vd.mask) += fade * bstrength * (*vd.mask);
- }
- *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- BKE_pbvh_vertex_iter_end;
- }
-}
-
-static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
-}
-
-static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- switch ((BrushMaskTool)brush->mask_tool) {
- case BRUSH_MASK_DRAW:
- do_mask_brush_draw(sd, ob, nodes, totnode);
- break;
- case BRUSH_MASK_SMOOTH:
- SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true);
- break;
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Multires Displacement Eraser Brush
- * \{ */
-
-static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
-
- float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- float limit_co[3];
- float disp[3];
- SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co);
- sub_v3_v3v3(disp, limit_co, vd.co);
- mul_v3_v3fl(proxy[vd.i], disp, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- BKE_curvemapping_init(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_displacement_eraser_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Multires Displacement Smear Brush
- * \{ */
-
-static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- float current_disp[3];
- float current_disp_norm[3];
- float interp_limit_surface_disp[3];
-
- copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]);
-
- switch (brush->smear_deform_type) {
- case BRUSH_SMEAR_DEFORM_DRAG:
- sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
- break;
- case BRUSH_SMEAR_DEFORM_PINCH:
- sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
- break;
- case BRUSH_SMEAR_DEFORM_EXPAND:
- sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
- break;
- }
-
- normalize_v3_v3(current_disp_norm, current_disp);
- mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
-
- float weights_accum = 1.0f;
-
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
- float vertex_disp[3];
- float vertex_disp_norm[3];
- float neighbor_limit_co[3];
- SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co);
- sub_v3_v3v3(vertex_disp,
- ss->cache->limit_surface_co[ni.index],
- ss->cache->limit_surface_co[vd.index]);
- const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index];
- normalize_v3_v3(vertex_disp_norm, vertex_disp);
-
- if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) {
- continue;
- }
-
- const float disp_interp = clamp_f(
- -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f);
- madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp);
- weights_accum += disp_interp;
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
-
- mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum);
-
- float new_co[3];
- add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp);
- interp_v3_v3v3(vd.co, vd.co, new_co, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_displacement_smear_store_prev_disp_task_cb_ex(
- void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- sub_v3_v3v3(ss->cache->prev_displacement[vd.index],
- SCULPT_vertex_co_get(ss, vd.index),
- ss->cache->limit_surface_co[vd.index]);
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
-
- BKE_curvemapping_init(brush->curve);
-
- const int totvert = SCULPT_vertex_count_get(ss);
- if (!ss->cache->prev_displacement) {
- ss->cache->prev_displacement = MEM_malloc_arrayN(
- totvert, sizeof(float[3]), "prev displacement");
- ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co");
- for (int i = 0; i < totvert; i++) {
- SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]);
- sub_v3_v3v3(ss->cache->prev_displacement[i],
- SCULPT_vertex_co_get(ss, i),
- ss->cache->limit_surface_co[i]);
- }
- }
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(
- 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings);
- BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Draw Brush
- * \{ */
-
-static void do_draw_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *offset = data->offset;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- /* Offset vertex. */
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], offset, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- const float bstrength = ss->cache->bstrength;
-
- /* Offset with as much as possible factored in already. */
- float effective_normal[3];
- SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
- mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
- mul_v3_v3(offset, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
-
- /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
- * initialize before threads so they can do curve mapping. */
- BKE_curvemapping_init(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .offset = offset,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
-}
-
-static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *offset = data->offset;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- /* Offset vertex. */
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], offset, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- const float bstrength = ss->cache->bstrength;
-
- /* Offset with as much as possible factored in already. */
- float effective_normal[3];
- SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
- mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
- mul_v3_v3(offset, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
-
- /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
- * initialize before threads so they can do curve mapping. */
- BKE_curvemapping_init(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .offset = offset,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Topology Brush
- * \{ */
-
-static void do_topology_slide_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float current_disp[3];
- float current_disp_norm[3];
- float final_disp[3] = {0.0f, 0.0f, 0.0f};
-
- switch (brush->slide_deform_type) {
- case BRUSH_SLIDE_DEFORM_DRAG:
- sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
- break;
- case BRUSH_SLIDE_DEFORM_PINCH:
- sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
- break;
- case BRUSH_SLIDE_DEFORM_EXPAND:
- sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
- break;
- }
-
- normalize_v3_v3(current_disp_norm, current_disp);
- mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
-
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
- float vertex_disp[3];
- float vertex_disp_norm[3];
- sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
- normalize_v3_v3(vertex_disp_norm, vertex_disp);
- if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) {
- madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp));
- }
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
-
- mul_v3_v3fl(proxy[vd.i], final_disp, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-void SCULPT_relax_vertex(SculptSession *ss,
- PBVHVertexIter *vd,
- float factor,
- bool filter_boundary_face_sets,
- float *r_final_pos)
-{
- float smooth_pos[3];
- float final_disp[3];
- float boundary_normal[3];
- int avg_count = 0;
- int neighbor_count = 0;
- zero_v3(smooth_pos);
- zero_v3(boundary_normal);
- const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index);
-
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
- neighbor_count++;
- if (!filter_boundary_face_sets ||
- (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) {
-
- /* When the vertex to relax is boundary, use only connected boundary vertices for the average
- * position. */
- if (is_boundary) {
- if (!SCULPT_vertex_is_boundary(ss, ni.index)) {
- continue;
- }
- add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
- avg_count++;
-
- /* Calculate a normal for the constraint plane using the edges of the boundary. */
- float to_neighbor[3];
- sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co);
- normalize_v3(to_neighbor);
- add_v3_v3(boundary_normal, to_neighbor);
- }
- else {
- add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
- avg_count++;
- }
- }
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
-
- /* Don't modify corner vertices. */
- if (neighbor_count <= 2) {
- copy_v3_v3(r_final_pos, vd->co);
- return;
- }
-
- if (avg_count > 0) {
- mul_v3_fl(smooth_pos, 1.0f / avg_count);
- }
- else {
- copy_v3_v3(r_final_pos, vd->co);
- return;
- }
-
- float plane[4];
- float smooth_closest_plane[3];
- float vno[3];
-
- if (is_boundary && avg_count == 2) {
- normalize_v3_v3(vno, boundary_normal);
- }
- else {
- SCULPT_vertex_normal_get(ss, vd->index, vno);
- }
-
- if (is_zero_v3(vno)) {
- copy_v3_v3(r_final_pos, vd->co);
- return;
- }
-
- plane_from_point_normal_v3(plane, vd->co, vno);
- closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos);
- sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co);
-
- mul_v3_fl(final_disp, factor);
- add_v3_v3v3(r_final_pos, vd->co, final_disp);
-}
-
-static void do_topology_relax_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- return;
- }
-
- BKE_curvemapping_init(brush->curve);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- if (ss->cache->alt_smooth) {
- SCULPT_boundary_info_ensure(ob);
- for (int i = 0; i < 4; i++) {
- BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
- }
- }
- else {
- BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
- }
-}
-
-static void calc_sculpt_plane(
- Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (SCULPT_stroke_is_main_symmetry_pass(ss->cache) &&
- (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache) ||
- !(brush->flag & BRUSH_ORIGINAL_PLANE) || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
- switch (brush->sculpt_plane) {
- case SCULPT_DISP_DIR_VIEW:
- copy_v3_v3(r_area_no, ss->cache->true_view_normal);
- break;
-
- case SCULPT_DISP_DIR_X:
- ARRAY_SET_ITEMS(r_area_no, 1.0f, 0.0f, 0.0f);
- break;
-
- case SCULPT_DISP_DIR_Y:
- ARRAY_SET_ITEMS(r_area_no, 0.0f, 1.0f, 0.0f);
- break;
-
- case SCULPT_DISP_DIR_Z:
- ARRAY_SET_ITEMS(r_area_no, 0.0f, 0.0f, 1.0f);
- break;
-
- case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
- normalize_v3(r_area_no);
- }
- break;
-
- default:
- break;
- }
-
- /* For flatten center. */
- /* Flatten center has not been calculated yet if we are not using the area normal. */
- if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) {
- calc_area_center(sd, ob, nodes, totnode, r_area_co);
- }
-
- /* For area normal. */
- if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
- (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
- copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
- }
- else {
- copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
- }
-
- /* For flatten center. */
- if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
- (brush->flag & BRUSH_ORIGINAL_PLANE)) {
- copy_v3_v3(r_area_co, ss->cache->last_center);
- }
- else {
- copy_v3_v3(ss->cache->last_center, r_area_co);
- }
- }
- else {
- /* For area normal. */
- copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
-
- /* For flatten center. */
- copy_v3_v3(r_area_co, ss->cache->last_center);
-
- /* For area normal. */
- flip_v3(r_area_no, ss->cache->mirror_symmetry_pass);
-
- /* For flatten center. */
- flip_v3(r_area_co, ss->cache->mirror_symmetry_pass);
-
- /* For area normal. */
- mul_m4_v3(ss->cache->symm_rot_mat, r_area_no);
-
- /* For flatten center. */
- mul_m4_v3(ss->cache->symm_rot_mat, r_area_co);
-
- /* Shift the plane for the current tile. */
- add_v3_v3(r_area_co, ss->cache->plane_offset);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Crease & Blob Brush
- * \{ */
-
-/**
- * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
- */
-static void do_crease_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- SculptProjectVector *spvc = data->spvc;
- const float flippedbstrength = data->flippedbstrength;
- const float *offset = data->offset;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- /* Offset vertex. */
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float val1[3];
- float val2[3];
-
- /* First we pinch. */
- sub_v3_v3v3(val1, test.location, vd.co);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(val1, val1, ss->cache->view_normal);
- }
-
- mul_v3_fl(val1, fade * flippedbstrength);
-
- sculpt_project_v3(spvc, val1, val1);
-
- /* Then we draw. */
- mul_v3_v3fl(val2, offset, fade);
-
- add_v3_v3v3(proxy[vd.i], val1, val2);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- const Scene *scene = ss->cache->vc->scene;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- float bstrength = ss->cache->bstrength;
- float flippedbstrength, crease_correction;
- float brush_alpha;
-
- SculptProjectVector spvc;
-
- /* Offset with as much as possible factored in already. */
- mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
- mul_v3_v3(offset, ss->cache->scale);
- mul_v3_fl(offset, bstrength);
-
- /* We divide out the squared alpha and multiply by the squared crease
- * to give us the pinch strength. */
- crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor;
- brush_alpha = BKE_brush_alpha_get(scene, brush);
- if (brush_alpha > 0.0f) {
- crease_correction /= brush_alpha * brush_alpha;
- }
-
- /* We always want crease to pinch or blob to relax even when draw is negative. */
- flippedbstrength = (bstrength < 0.0f) ? -crease_correction * bstrength :
- crease_correction * bstrength;
-
- if (brush->sculpt_tool == SCULPT_TOOL_BLOB) {
- flippedbstrength *= -1.0f;
- }
-
- /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single
- * point. Without this we get a 'flat' surface surrounding the pinch. */
- sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .spvc = &spvc,
- .offset = offset,
- .flippedbstrength = flippedbstrength,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
-}
-
-static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float(*stroke_xz)[3] = data->stroke_xz;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- float x_object_space[3];
- float z_object_space[3];
- copy_v3_v3(x_object_space, stroke_xz[0]);
- copy_v3_v3(z_object_space, stroke_xz[1]);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float disp_center[3];
- float x_disp[3];
- float z_disp[3];
- /* Calculate displacement from the vertex to the brush center. */
- sub_v3_v3v3(disp_center, test.location, vd.co);
-
- /* Project the displacement into the X vector (aligned to the stroke). */
- mul_v3_v3fl(x_disp, x_object_space, dot_v3v3(disp_center, x_object_space));
-
- /* Project the displacement into the Z vector (aligned to the surface normal). */
- mul_v3_v3fl(z_disp, z_object_space, dot_v3v3(disp_center, z_object_space));
-
- /* Add the two projected vectors to calculate the final displacement.
- * The Y component is removed. */
- add_v3_v3v3(disp_center, x_disp, z_disp);
-
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(disp_center, disp_center, ss->cache->view_normal);
- }
- mul_v3_v3fl(proxy[vd.i], disp_center, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- float area_no[3];
- float area_co[3];
-
- float mat[4][4];
- calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- /* delay the first daub because grab delta is not setup */
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- return;
- }
-
- if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
- return;
- }
-
- /* Initialize `mat`. */
- cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
- mat[0][3] = 0.0f;
- cross_v3_v3v3(mat[1], area_no, mat[0]);
- mat[1][3] = 0.0f;
- copy_v3_v3(mat[2], area_no);
- mat[2][3] = 0.0f;
- copy_v3_v3(mat[3], ss->cache->location);
- mat[3][3] = 1.0f;
- normalize_m4(mat);
-
- float stroke_xz[2][3];
- normalize_v3_v3(stroke_xz[0], mat[0]);
- normalize_v3_v3(stroke_xz[1], mat[2]);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .stroke_xz = stroke_xz,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
-}
-
-static void do_grab_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *grab_delta = data->grab_delta;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE;
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- if (grab_silhouette) {
- float silhouette_test_dir[3];
- normalize_v3_v3(silhouette_test_dir, grab_delta);
- if (dot_v3v3(ss->cache->initial_normal, ss->cache->grab_delta_symmetry) < 0.0f) {
- mul_v3_fl(silhouette_test_dir, -1.0f);
- }
- float vno[3];
- normal_short_to_float_v3(vno, orig_data.no);
- fade *= max_ff(dot_v3v3(vno, silhouette_test_dir), 0.0f);
- }
-
- mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- if (ss->cache->normal_weight > 0.0f) {
- sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .grab_delta = grab_delta,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
-}
-
-static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *grab_delta = data->grab_delta;
- const float *location = ss->cache->location;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
-
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- float dir;
- if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) {
- dir = 1.0f;
- }
- else {
- dir = -1.0f;
- }
-
- if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) {
- int symm = ss->cache->mirror_symmetry_pass;
- if (ELEM(symm, 1, 2, 4, 7)) {
- dir = -dir;
- }
- }
-
- KelvinletParams params;
- float force = len_v3(grab_delta) * dir * bstrength;
- BKE_kelvinlet_init_params(
- &params, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- float final_disp[3];
- switch (brush->elastic_deform_type) {
- case BRUSH_ELASTIC_DEFORM_GRAB:
- BKE_kelvinlet_grab(final_disp, &params, orig_data.co, location, grab_delta);
- mul_v3_fl(final_disp, bstrength * 20.0f);
- break;
- case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: {
- BKE_kelvinlet_grab_biscale(final_disp, &params, orig_data.co, location, grab_delta);
- mul_v3_fl(final_disp, bstrength * 20.0f);
- break;
- }
- case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: {
- BKE_kelvinlet_grab_triscale(final_disp, &params, orig_data.co, location, grab_delta);
- mul_v3_fl(final_disp, bstrength * 20.0f);
- break;
- }
- case BRUSH_ELASTIC_DEFORM_SCALE:
- BKE_kelvinlet_scale(
- final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
- break;
- case BRUSH_ELASTIC_DEFORM_TWIST:
- BKE_kelvinlet_twist(
- final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
- break;
- }
-
- if (vd.mask) {
- mul_v3_fl(final_disp, 1.0f - *vd.mask);
- }
-
- mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
-
- copy_v3_v3(proxy[vd.i], final_disp);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- if (ss->cache->normal_weight > 0.0f) {
- sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .grab_delta = grab_delta,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
-}
-
ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3])
{
ePaintSymmetryAreas symm_area = PAINT_SYMM_AREA_DEFAULT;
@@ -4257,7 +2872,7 @@ void SCULPT_calc_brush_plane(
break;
case SCULPT_DISP_DIR_AREA:
- calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
+ SCULPT_calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
normalize_v3(r_area_no);
@@ -4271,7 +2886,7 @@ void SCULPT_calc_brush_plane(
/* For flatten center. */
/* Flatten center has not been calculated yet if we are not using the area normal. */
if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) {
- calc_area_center(sd, ob, nodes, totnode, r_area_co);
+ SCULPT_calc_area_center(sd, ob, nodes, totnode, r_area_co);
}
/* For area normal. */
@@ -4316,564 +2931,12 @@ void SCULPT_calc_brush_plane(
}
}
-static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *cono = data->cono;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], cono, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
- float tmp[3], cono[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
- cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .cono = cono,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
-}
-
-static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- SculptProjectVector *spvc = data->spvc;
- const float *grab_delta = data->grab_delta;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
- const bool do_rake_rotation = ss->cache->is_rake_rotation_valid;
- const bool do_pinch = (brush->crease_pinch_factor != 0.5f);
- const float pinch = do_pinch ? (2.0f * (0.5f - brush->crease_pinch_factor) *
- (len_v3(grab_delta) / ss->cache->radius)) :
- 0.0f;
-
- const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- KelvinletParams params;
- BKE_kelvinlet_init_params(&params, ss->cache->radius, bstrength, 1.0f, 0.4f);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- float fade;
- if (do_elastic) {
- fade = 1.0f;
- }
- else {
- fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- }
-
- mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
-
- /* Negative pinch will inflate, helps maintain volume. */
- if (do_pinch) {
- float delta_pinch_init[3], delta_pinch[3];
-
- sub_v3_v3v3(delta_pinch, vd.co, test.location);
- if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal);
- }
-
- /* Important to calculate based on the grabbed location
- * (intentionally ignore fade here). */
- add_v3_v3(delta_pinch, grab_delta);
-
- sculpt_project_v3(spvc, delta_pinch, delta_pinch);
-
- copy_v3_v3(delta_pinch_init, delta_pinch);
-
- float pinch_fade = pinch * fade;
- /* When reducing, scale reduction back by how close to the center we are,
- * so we don't pinch into nothingness. */
- if (pinch > 0.0f) {
- /* Square to have even less impact for close vertices. */
- pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius));
- }
- mul_v3_fl(delta_pinch, 1.0f + pinch_fade);
- sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch);
- add_v3_v3(proxy[vd.i], delta_pinch);
- }
-
- if (do_rake_rotation) {
- float delta_rotate[3];
- sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate);
- add_v3_v3(proxy[vd.i], delta_rotate);
- }
-
- if (do_elastic) {
- float disp[3];
- BKE_kelvinlet_grab_triscale(disp, &params, vd.co, ss->cache->location, proxy[vd.i]);
- mul_v3_fl(disp, bstrength * 20.0f);
- if (vd.mask) {
- mul_v3_fl(disp, 1.0f - *vd.mask);
- }
- mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
- copy_v3_v3(proxy[vd.i], disp);
- }
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- const float bstrength = ss->cache->bstrength;
- float grab_delta[3];
-
- SculptProjectVector spvc;
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- if (bstrength < 0.0f) {
- negate_v3(grab_delta);
- }
-
- if (ss->cache->normal_weight > 0.0f) {
- sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
- }
-
- /* Optionally pinch while painting. */
- if (brush->crease_pinch_factor != 0.5f) {
- sculpt_project_v3_cache_init(&spvc, grab_delta);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .spvc = &spvc,
- .grab_delta = grab_delta,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
-}
-
-static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *cono = data->cono;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], cono, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
- float tmp[3], cono[3];
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
-
- cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
- cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .cono = cono,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
-}
-
-static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float angle = data->angle;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- float vec[3], rot[3][3];
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- orig_data.co,
- sqrtf(test.dist),
- orig_data.no,
- NULL,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
- axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
- mul_v3_m3v3(proxy[vd.i], rot, vec);
- add_v3_v3(proxy[vd.i], ss->cache->location);
- sub_v3_v3(proxy[vd.i], orig_data.co);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- static const int flip[8] = {1, -1, -1, 1, -1, 1, 1, -1};
- const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .angle = angle,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
-}
-
-static void do_layer_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
-
- const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
- const float bstrength = ss->cache->bstrength;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
-
- if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- continue;
- }
- const float fade = SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- const int vi = vd.index;
- float *disp_factor;
- if (use_persistent_base) {
- disp_factor = &ss->persistent_base[vi].disp;
- }
- else {
- disp_factor = &ss->cache->layer_displacement_factor[vi];
- }
-
- /* When using persistent base, the layer brush (holding Control) invert mode resets the
- * height of the layer to 0. This makes possible to clean edges of previously added layers
- * on top of the base. */
- /* The main direction of the layers is inverted using the regular brush strength with the
- * brush direction property. */
- if (use_persistent_base && ss->cache->invert) {
- (*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) *
- ((*disp_factor) > 0.0f ? -1.0f : 1.0f);
- }
- else {
- (*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor));
- }
- if (vd.mask) {
- const float clamp_mask = 1.0f - *vd.mask;
- *disp_factor = clamp_f(*disp_factor, -clamp_mask, clamp_mask);
- }
- else {
- *disp_factor = clamp_f(*disp_factor, -1.0f, 1.0f);
- }
-
- float final_co[3];
- float normal[3];
-
- if (use_persistent_base) {
- SCULPT_vertex_persistent_normal_get(ss, vi, normal);
- mul_v3_fl(normal, brush->height);
- madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor);
- }
- else {
- normal_short_to_float_v3(normal, orig_data.no);
- mul_v3_fl(normal, brush->height);
- madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor);
- }
-
- float vdisp[3];
- sub_v3_v3v3(vdisp, final_co, vd.co);
- mul_v3_fl(vdisp, fabsf(fade));
- add_v3_v3v3(final_co, vd.co, vdisp);
-
- SCULPT_clip(sd, ss, vd.co, final_co);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (ss->cache->layer_displacement_factor == NULL) {
- ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
- "layer displacement factor");
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
-}
-
-static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
- float val[3];
-
- if (vd.fno) {
- copy_v3_v3(val, vd.fno);
- }
- else {
- normal_short_to_float_v3(val, vd.no);
- }
-
- mul_v3_fl(val, fade * ss->cache->radius);
- mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
-}
-
int SCULPT_plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3])
{
return (!(brush->flag & BRUSH_PLANE_TRIM) ||
((dot_v3v3(val, val) <= cache->radius_squared * cache->plane_trim_squared)));
}
-static bool plane_point_side_flip(const float co[3], const float plane[4], const bool flip)
-{
- float d = plane_point_side_v3(plane, co);
- if (flip) {
- d = -d;
- }
- return d <= 0.0f;
-}
-
int SCULPT_plane_point_side(const float co[3], const float plane[4])
{
float d = plane_point_side_v3(plane, co);
@@ -4893,807 +2956,6 @@ float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss)
return rv;
}
-static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- float intr[3];
- float val[3];
-
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
-
- sub_v3_v3v3(val, intr, vd.co);
-
- if (SCULPT_plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
-
- float area_no[3];
- float area_co[3];
-
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
- float displace;
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
-
- displace = radius * offset;
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Clay Brush
- * \{ */
-
-typedef struct ClaySampleData {
- float plane_dist[2];
-} ClaySampleData;
-
-static void calc_clay_surface_task_cb(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- ClaySampleData *csd = tls->userdata_chunk;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
- float plane[4];
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, brush->falloff_shape);
-
- /* Apply the brush normal radius to the test before sampling. */
- float test_radius = sqrtf(test.radius_squared);
- test_radius *= brush->normal_radius_factor;
- test.radius_squared = test_radius * test_radius;
- plane_from_point_normal_v3(plane, area_co, area_no);
-
- if (is_zero_v4(plane)) {
- return;
- }
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- float plane_dist = dist_signed_to_plane_v3(vd.co, plane);
- float plane_dist_abs = fabsf(plane_dist);
- if (plane_dist > 0.0f) {
- csd->plane_dist[0] = MIN2(csd->plane_dist[0], plane_dist_abs);
- }
- else {
- csd->plane_dist[1] = MIN2(csd->plane_dist[1], plane_dist_abs);
- }
- BKE_pbvh_vertex_iter_end;
- }
-}
-
-static void calc_clay_surface_reduce(const void *__restrict UNUSED(userdata),
- void *__restrict chunk_join,
- void *__restrict chunk)
-{
- ClaySampleData *join = chunk_join;
- ClaySampleData *csd = chunk;
- join->plane_dist[0] = MIN2(csd->plane_dist[0], join->plane_dist[0]);
- join->plane_dist[1] = MIN2(csd->plane_dist[1], join->plane_dist[1]);
-}
-
-static void do_clay_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = fabsf(ss->cache->bstrength);
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
-
- sub_v3_v3v3(val, intr, vd.co);
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = fabsf(ss->cache->radius);
- const float initial_radius = fabsf(ss->cache->initial_radius);
- bool flip = ss->cache->bstrength < 0.0f;
-
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
- float displace;
-
- float area_no[3];
- float area_co[3];
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SculptThreadedTaskData sample_data = {
- .sd = NULL,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .totnode = totnode,
- .area_no = area_no,
- .area_co = ss->cache->location,
- };
-
- ClaySampleData csd = {{0}};
-
- TaskParallelSettings sample_settings;
- BKE_pbvh_parallel_range_settings(&sample_settings, true, totnode);
- sample_settings.func_reduce = calc_clay_surface_reduce;
- sample_settings.userdata_chunk = &csd;
- sample_settings.userdata_chunk_size = sizeof(ClaySampleData);
-
- BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
-
- float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]);
- d_offset = min_ff(radius, d_offset);
- d_offset = d_offset / radius;
- d_offset = 1.0f - d_offset;
- displace = fabsf(initial_radius * (0.25f + offset + (d_offset * 0.15f)));
- if (flip) {
- displace = -displace;
- }
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- copy_v3_v3(area_co, ss->cache->location);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
-}
-
-static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float(*mat)[4] = data->mat;
- const float *area_no_sp = data->area_no_sp;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- SculptBrushTest test;
- float(*proxy)[3];
- const bool flip = (ss->cache->bstrength < 0.0f);
- const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SCULPT_brush_test_init(ss, &test);
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) {
- continue;
- }
-
- if (!plane_point_side_flip(vd.co, test.plane_tool, flip)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
-
- if (!SCULPT_plane_trim(ss->cache, brush, val)) {
- continue;
- }
- /* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- ss->cache->radius * test.dist,
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const bool flip = (ss->cache->bstrength < 0.0f);
- const float radius = flip ? -ss->cache->radius : ss->cache->radius;
- const float offset = SCULPT_brush_plane_offset_get(sd, ss);
- const float displace = radius * (0.18f + offset);
-
- /* The sculpt-plane normal (whatever its set to). */
- float area_no_sp[3];
-
- /* Geometry normal */
- float area_no[3];
- float area_co[3];
-
- float temp[3];
- float mat[4][4];
- float scale[4][4];
- float tmat[4][4];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
- SCULPT_tilt_apply_to_normal(area_no_sp, ss->cache, brush->tilt_strength_factor);
-
- if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
- SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
- }
- else {
- copy_v3_v3(area_no, area_no_sp);
- }
-
- /* Delay the first daub because grab delta is not setup. */
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- return;
- }
-
- if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
- return;
- }
-
- mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- /* Clay Strips uses a cube test with falloff in the XY axis (not in Z) and a plane to deform the
- * vertices. When in Add mode, vertices that are below the plane and inside the cube are move
- * towards the plane. In this situation, there may be cases where a vertex is outside the cube
- * but below the plane, so won't be deformed, causing artifacts. In order to prevent these
- * artifacts, this displaces the test cube space in relation to the plane in order to
- * deform more vertices that may be below it. */
- /* The 0.7 and 1.25 factors are arbitrary and don't have any relation between them, they were set
- * by doing multiple tests using the default "Clay Strips" brush preset. */
- float area_co_displaced[3];
- madd_v3_v3v3fl(area_co_displaced, area_co, area_no, -radius * 0.7f);
-
- /* Initialize brush local-space matrix. */
- cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
- mat[0][3] = 0.0f;
- cross_v3_v3v3(mat[1], area_no, mat[0]);
- mat[1][3] = 0.0f;
- copy_v3_v3(mat[2], area_no);
- mat[2][3] = 0.0f;
- copy_v3_v3(mat[3], area_co_displaced);
- mat[3][3] = 1.0f;
- normalize_m4(mat);
-
- /* Scale brush local space matrix. */
- scale_m4_fl(scale, ss->cache->radius);
- mul_m4_m4m4(tmat, mat, scale);
-
- /* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in
- * Z this does not produce artifacts in the falloff cube and allows to deform extra vertices
- * during big deformation while keeping the surface as uniform as possible. */
- mul_v3_fl(tmat[2], 1.25f);
-
- invert_m4_m4(mat, tmat);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no_sp = area_no_sp,
- .area_co = area_co,
- .mat = mat,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
-}
-
-static void do_fill_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- if (!SCULPT_plane_point_side(vd.co, test.plane_tool)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
-
- if (!SCULPT_plane_trim(ss->cache, brush, val)) {
- continue;
- }
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
-
- float area_no[3];
- float area_co[3];
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
-
- float displace;
-
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
-
- displace = radius * offset;
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
-}
-
-static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float *area_no = data->area_no;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = ss->cache->bstrength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
-
- if (SCULPT_plane_point_side(vd.co, test.plane_tool)) {
- continue;
- }
-
- float intr[3];
- float val[3];
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- sub_v3_v3v3(val, intr, vd.co);
-
- if (!SCULPT_plane_trim(ss->cache, brush, val)) {
- continue;
- }
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
-
- float area_no[3];
- float area_co[3];
- float offset = SCULPT_brush_plane_offset_get(sd, ss);
-
- float displace;
-
- float temp[3];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
-
- SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
-
- displace = -radius * offset;
-
- mul_v3_v3v3(temp, area_no, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no = area_no,
- .area_co = area_co,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Sculpt Clay Thumb Brush
- * \{ */
-
-static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float(*mat)[4] = data->mat;
- const float *area_no_sp = data->area_no_sp;
- const float *area_co = data->area_co;
-
- PBVHVertexIter vd;
- float(*proxy)[3];
- const float bstrength = data->clay_strength;
-
- proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
- const int thread_id = BLI_task_parallel_thread_id(tls);
-
- float plane_tilt[4];
- float normal_tilt[3];
- float imat[4][4];
-
- invert_m4_m4(imat, mat);
- rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss->cache->clay_thumb_front_angle));
-
- /* Plane aligned to the geometry normal (back part of the brush). */
- plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
- /* Tilted plane (front part of the brush). */
- plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt);
-
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
- continue;
- }
- float local_co[3];
- mul_v3_m4v3(local_co, mat, vd.co);
- float intr[3], intr_tilt[3];
- float val[3];
-
- closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
- closest_to_plane_normalized_v3(intr_tilt, plane_tilt, vd.co);
-
- /* Mix the deformation of the aligned and the tilted plane based on the brush space vertex
- * coordinates. */
- /* We can also control the mix with a curve if it produces noticeable artifacts in the center
- * of the brush. */
- const float tilt_mix = local_co[1] > 0.0f ? 0.0f : 1.0f;
- interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix);
- sub_v3_v3v3(val, intr_tilt, vd.co);
-
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- thread_id);
-
- mul_v3_v3fl(proxy[vd.i], val, fade);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static float sculpt_clay_thumb_get_stabilized_pressure(StrokeCache *cache)
-{
- float final_pressure = 0.0f;
- for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) {
- final_pressure += cache->clay_pressure_stabilizer[i];
- }
- return final_pressure / SCULPT_CLAY_STABILIZER_LEN;
-}
-
-static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const float radius = ss->cache->radius;
- const float offset = SCULPT_brush_plane_offset_get(sd, ss);
- const float displace = radius * (0.25f + offset);
-
- /* Sampled geometry normal and area center. */
- float area_no_sp[3];
- float area_no[3];
- float area_co[3];
-
- float temp[3];
- float mat[4][4];
- float scale[4][4];
- float tmat[4][4];
-
- SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
-
- if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
- SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
- }
- else {
- copy_v3_v3(area_no, area_no_sp);
- }
-
- /* Delay the first daub because grab delta is not setup. */
- if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
- ss->cache->clay_thumb_front_angle = 0.0f;
- return;
- }
-
- /* Simulate the clay accumulation by increasing the plane angle as more samples are added to the
- * stroke. */
- if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) {
- ss->cache->clay_thumb_front_angle += 0.8f;
- ss->cache->clay_thumb_front_angle = clamp_f(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f);
- }
-
- if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
- return;
- }
-
- /* Displace the brush planes. */
- copy_v3_v3(area_co, ss->cache->location);
- mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
- mul_v3_fl(temp, displace);
- add_v3_v3(area_co, temp);
-
- /* Initialize brush local-space matrix. */
- cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
- mat[0][3] = 0.0f;
- cross_v3_v3v3(mat[1], area_no, mat[0]);
- mat[1][3] = 0.0f;
- copy_v3_v3(mat[2], area_no);
- mat[2][3] = 0.0f;
- copy_v3_v3(mat[3], ss->cache->location);
- mat[3][3] = 1.0f;
- normalize_m4(mat);
-
- /* Scale brush local space matrix. */
- scale_m4_fl(scale, ss->cache->radius);
- mul_m4_m4m4(tmat, mat, scale);
- invert_m4_m4(mat, tmat);
-
- float clay_strength = ss->cache->bstrength *
- sculpt_clay_thumb_get_stabilized_pressure(ss->cache);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .area_no_sp = area_no_sp,
- .area_co = ss->cache->location,
- .mat = mat,
- .clay_strength = clay_strength,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -6036,7 +3298,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
/* Apply one type of brush action. */
switch (brush->sculpt_tool) {
case SCULPT_TOOL_DRAW:
- do_draw_brush(sd, ob, nodes, totnode);
+ SCULPT_do_draw_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SMOOTH:
if (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_LAPLACIAN) {
@@ -6047,80 +3309,80 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
break;
case SCULPT_TOOL_CREASE:
- do_crease_brush(sd, ob, nodes, totnode);
+ SCULPT_do_crease_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_BLOB:
- do_crease_brush(sd, ob, nodes, totnode);
+ SCULPT_do_crease_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_PINCH:
- do_pinch_brush(sd, ob, nodes, totnode);
+ SCULPT_do_pinch_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_INFLATE:
- do_inflate_brush(sd, ob, nodes, totnode);
+ SCULPT_do_inflate_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_GRAB:
- do_grab_brush(sd, ob, nodes, totnode);
+ SCULPT_do_grab_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_ROTATE:
- do_rotate_brush(sd, ob, nodes, totnode);
+ SCULPT_do_rotate_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SNAKE_HOOK:
- do_snake_hook_brush(sd, ob, nodes, totnode);
+ SCULPT_do_snake_hook_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_NUDGE:
- do_nudge_brush(sd, ob, nodes, totnode);
+ SCULPT_do_nudge_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_THUMB:
- do_thumb_brush(sd, ob, nodes, totnode);
+ SCULPT_do_thumb_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_LAYER:
- do_layer_brush(sd, ob, nodes, totnode);
+ SCULPT_do_layer_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_FLATTEN:
- do_flatten_brush(sd, ob, nodes, totnode);
+ SCULPT_do_flatten_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY:
- do_clay_brush(sd, ob, nodes, totnode);
+ SCULPT_do_clay_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY_STRIPS:
- do_clay_strips_brush(sd, ob, nodes, totnode);
+ SCULPT_do_clay_strips_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_MULTIPLANE_SCRAPE:
SCULPT_do_multiplane_scrape_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_CLAY_THUMB:
- do_clay_thumb_brush(sd, ob, nodes, totnode);
+ SCULPT_do_clay_thumb_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_FILL:
if (invert && brush->flag & BRUSH_INVERT_TO_SCRAPE_FILL) {
- do_scrape_brush(sd, ob, nodes, totnode);
+ SCULPT_do_scrape_brush(sd, ob, nodes, totnode);
}
else {
- do_fill_brush(sd, ob, nodes, totnode);
+ SCULPT_do_fill_brush(sd, ob, nodes, totnode);
}
break;
case SCULPT_TOOL_SCRAPE:
if (invert && brush->flag & BRUSH_INVERT_TO_SCRAPE_FILL) {
- do_fill_brush(sd, ob, nodes, totnode);
+ SCULPT_do_fill_brush(sd, ob, nodes, totnode);
}
else {
- do_scrape_brush(sd, ob, nodes, totnode);
+ SCULPT_do_scrape_brush(sd, ob, nodes, totnode);
}
break;
case SCULPT_TOOL_MASK:
- do_mask_brush(sd, ob, nodes, totnode);
+ SCULPT_do_mask_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_POSE:
SCULPT_do_pose_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DRAW_SHARP:
- do_draw_sharp_brush(sd, ob, nodes, totnode);
+ SCULPT_do_draw_sharp_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_ELASTIC_DEFORM:
- do_elastic_deform_brush(sd, ob, nodes, totnode);
+ SCULPT_do_elastic_deform_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_SLIDE_RELAX:
- do_slide_relax_brush(sd, ob, nodes, totnode);
+ SCULPT_do_slide_relax_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_BOUNDARY:
SCULPT_do_boundary_brush(sd, ob, nodes, totnode);
@@ -6132,10 +3394,10 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
SCULPT_do_draw_face_sets_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DISPLACEMENT_ERASER:
- do_displacement_eraser_brush(sd, ob, nodes, totnode);
+ SCULPT_do_displacement_eraser_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DISPLACEMENT_SMEAR:
- do_displacement_smear_brush(sd, ob, nodes, totnode);
+ SCULPT_do_displacement_smear_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_PAINT:
SCULPT_do_paint_brush(sd, ob, nodes, totnode);
@@ -6157,7 +3419,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
if (sculpt_brush_use_topology_rake(ss, brush)) {
- bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor);
+ SCULPT_bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor);
}
/* The cloth brush adds the gravity as a regular force and it is processed in the solver. */
@@ -6737,6 +3999,8 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
{
ModifierData *md;
+ unit_m4(ss->cache->clip_mirror_mtx);
+
for (md = ob->modifiers.first; md; md = md->next) {
if (!(md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime))) {
continue;
@@ -6758,6 +4022,13 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss)
if (mmd->tolerance > ss->cache->clip_tolerance[i]) {
ss->cache->clip_tolerance[i] = mmd->tolerance;
}
+
+ /* Store matrix for mirror object clipping. */
+ if (mmd->mirror_ob) {
+ float imtx_mirror_ob[4][4];
+ invert_m4_m4(imtx_mirror_ob, mmd->mirror_ob->obmat);
+ mul_m4_m4m4(ss->cache->clip_mirror_mtx, imtx_mirror_ob, ob->obmat);
+ }
}
}
}
@@ -6946,7 +4217,7 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo
case SCULPT_TOOL_CLAY_STRIPS:
return max_ff(initial_size * 0.30f, initial_size * powf(cache->pressure, 1.5f));
case SCULPT_TOOL_CLAY_THUMB: {
- float clay_stabilized_pressure = sculpt_clay_thumb_get_stabilized_pressure(cache);
+ float clay_stabilized_pressure = SCULPT_clay_thumb_get_stabilized_pressure(cache);
return initial_size * clay_stabilized_pressure;
}
default:
@@ -8131,7 +5402,7 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
sculpt_brush_exit_tex(sd);
}
-static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
+void SCULPT_OT_brush_stroke(wmOperatorType *ot)
{
/* Identifiers. */
ot->name = "Sculpt";
@@ -8159,677 +5430,6 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
"Clicks on the background do not start the stroke");
}
-/* Reset the copy of the mesh that is being sculpted on (currently just for the layer brush). */
-
-static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
-
- if (!ss) {
- return OPERATOR_FINISHED;
- }
- SCULPT_vertex_random_access_ensure(ss);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
-
- MEM_SAFE_FREE(ss->persistent_base);
-
- const int totvert = SCULPT_vertex_count_get(ss);
- ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert,
- "layer persistent base");
-
- for (int i = 0; i < totvert; i++) {
- copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i));
- SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no);
- ss->persistent_base[i].disp = 0.0f;
- }
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Set Persistent Base";
- ot->idname = "SCULPT_OT_set_persistent_base";
- ot->description = "Reset the copy of the mesh that is being sculpted on";
-
- /* API callbacks. */
- ot->exec = sculpt_set_persistent_base_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/************************* SCULPT_OT_optimize *************************/
-
-static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
-
- SCULPT_pbvh_clear(ob);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-/* The BVH gets less optimal more quickly with dynamic topology than
- * regular sculpting. There is no doubt more clever stuff we can do to
- * optimize it on the fly, but for now this gives the user a nicer way
- * to recalculate it than toggling modes. */
-static void SCULPT_OT_optimize(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Rebuild BVH";
- ot->idname = "SCULPT_OT_optimize";
- ot->description = "Recalculate the sculpt BVH to improve performance";
-
- /* API callbacks. */
- ot->exec = sculpt_optimize_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/********************* Dynamic topology symmetrize ********************/
-
-static bool sculpt_no_multires_poll(bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- if (SCULPT_mode_poll(C) && ob->sculpt && ob->sculpt->pbvh) {
- return BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_GRIDS;
- }
- return false;
-}
-
-static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
-{
- Main *bmain = CTX_data_main(C);
- Object *ob = CTX_data_active_object(C);
- const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- SculptSession *ss = ob->sculpt;
- PBVH *pbvh = ss->pbvh;
- const float dist = RNA_float_get(op->ptr, "merge_tolerance");
-
- if (!pbvh) {
- return OPERATOR_CANCELLED;
- }
-
- switch (BKE_pbvh_type(pbvh)) {
- case PBVH_BMESH:
- /* Dyntopo Symmetrize. */
-
- /* To simplify undo for symmetrize, all BMesh elements are logged
- * as deleted, then after symmetrize operation all BMesh elements
- * are logged as added (as opposed to attempting to store just the
- * parts that symmetrize modifies). */
- SCULPT_undo_push_begin(ob, "Dynamic topology symmetrize");
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
- BM_log_before_all_removed(ss->bm, ss->bm_log);
-
- BM_mesh_toolflags_set(ss->bm, true);
-
- /* Symmetrize and re-triangulate. */
- BMO_op_callf(ss->bm,
- (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
- "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b",
- sd->symmetrize_direction,
- dist,
- true);
- SCULPT_dynamic_topology_triangulate(ss->bm);
-
- /* Bisect operator flags edges (keep tags clean for edge queue). */
- BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
-
- BM_mesh_toolflags_set(ss->bm, false);
-
- /* Finish undo. */
- BM_log_all_added(ss->bm, ss->bm_log);
- SCULPT_undo_push_end();
-
- break;
- case PBVH_FACES:
- /* Mesh Symmetrize. */
- ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize");
- Mesh *mesh = ob->data;
-
- BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist);
-
- ED_sculpt_undo_geometry_end(ob);
- BKE_mesh_calc_normals(ob->data);
- BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
-
- break;
- case PBVH_GRIDS:
- return OPERATOR_CANCELLED;
- }
-
- /* Redraw. */
- SCULPT_pbvh_clear(ob);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_symmetrize(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Symmetrize";
- ot->idname = "SCULPT_OT_symmetrize";
- ot->description = "Symmetrize the topology modifications";
-
- /* API callbacks. */
- ot->exec = sculpt_symmetrize_exec;
- ot->poll = sculpt_no_multires_poll;
-
- RNA_def_float(ot->srna,
- "merge_tolerance",
- 0.001f,
- 0.0f,
- FLT_MAX,
- "Merge Distance",
- "Distance within which symmetrical vertices are merged",
- 0.0f,
- 1.0f);
-}
-
-/**** Toggle operator for turning sculpt mode on or off ****/
-
-static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
-{
- /* Create persistent sculpt mode data. */
- BKE_sculpt_toolsettings_data_ensure(scene);
-
- /* Create sculpt mode session data. */
- if (ob->sculpt != NULL) {
- BKE_sculptsession_free(ob);
- }
- ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
- ob->sculpt->mode_type = OB_MODE_SCULPT;
-
- BKE_sculpt_ensure_orig_mesh_data(scene, ob);
-
- BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
-
- /* This function expects a fully evaluated depsgraph. */
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
-
- /* Here we can detect geometry that was just added to Sculpt Mode as it has the
- * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */
- /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not
- * initialized, which is used is some operators that modify the mesh topology to perform certain
- * actions in the new polys. After these operations are finished, all polys should have a valid
- * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility
- * correctly. */
- /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new
- * objects, like moving the transform pivot position to the new area or masking existing
- * geometry. */
- SculptSession *ss = ob->sculpt;
- const int new_face_set = SCULPT_face_set_next_available_get(ss);
- for (int i = 0; i < ss->totfaces; i++) {
- if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) {
- ss->face_sets[i] = new_face_set;
- }
- }
-}
-
-void ED_object_sculptmode_enter_ex(Main *bmain,
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- const bool force_dyntopo,
- ReportList *reports)
-{
- const int mode_flag = OB_MODE_SCULPT;
- Mesh *me = BKE_mesh_from_object(ob);
-
- /* Enter sculpt mode. */
- ob->mode |= mode_flag;
-
- sculpt_init_session(bmain, depsgraph, scene, ob);
-
- if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f &&
- fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) {
- BKE_report(
- reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable");
- }
- else if (is_negative_m4(ob->obmat)) {
- BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable");
- }
-
- Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT);
- BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT);
-
- paint_cursor_start(paint, SCULPT_mode_poll_view3d);
-
- /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
- * As long as no data was added that is not supported. */
- if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
-
- const char *message_unsupported = NULL;
- if (me->totloop != me->totpoly * 3) {
- message_unsupported = TIP_("non-triangle face");
- }
- else if (mmd != NULL) {
- message_unsupported = TIP_("multi-res modifier");
- }
- else {
- enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob);
- if (flag == 0) {
- /* pass */
- }
- else if (flag & DYNTOPO_WARN_VDATA) {
- message_unsupported = TIP_("vertex data");
- }
- else if (flag & DYNTOPO_WARN_EDATA) {
- message_unsupported = TIP_("edge data");
- }
- else if (flag & DYNTOPO_WARN_LDATA) {
- message_unsupported = TIP_("face data");
- }
- else if (flag & DYNTOPO_WARN_MODIFIER) {
- message_unsupported = TIP_("constructive modifier");
- }
- else {
- BLI_assert(0);
- }
- }
-
- if ((message_unsupported == NULL) || force_dyntopo) {
- /* Needed because we may be entering this mode before the undo system loads. */
- wmWindowManager *wm = bmain->wm.first;
- bool has_undo = wm->undo_stack != NULL;
- /* Undo push is needed to prevent memory leak. */
- if (has_undo) {
- SCULPT_undo_push_begin(ob, "Dynamic topology enable");
- }
- SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
- if (has_undo) {
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
- SCULPT_undo_push_end();
- }
- }
- else {
- BKE_reportf(
- reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported);
- me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
- }
- }
-
- /* Flush object mode. */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
-}
-
-void ED_object_sculptmode_enter(struct bContext *C, Depsgraph *depsgraph, ReportList *reports)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports);
-}
-
-void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
-{
- const int mode_flag = OB_MODE_SCULPT;
- Mesh *me = BKE_mesh_from_object(ob);
-
- multires_flush_sculpt_updates(ob);
-
- /* Not needed for now. */
-#if 0
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
-#endif
-
- /* Always for now, so leaving sculpt mode always ensures scene is in
- * a consistent state. */
- if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
-
- if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
- /* Dynamic topology must be disabled before exiting sculpt
- * mode to ensure the undo stack stays in a consistent
- * state. */
- sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob);
-
- /* Store so we know to re-enable when entering sculpt mode. */
- me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
- }
-
- /* Leave sculpt mode. */
- ob->mode &= ~mode_flag;
-
- BKE_sculptsession_free(ob);
-
- paint_cursor_delete_textures();
-
- /* Never leave derived meshes behind. */
- BKE_object_free_derived_caches(ob);
-
- /* Flush object mode. */
- DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
-}
-
-void ED_object_sculptmode_exit(bContext *C, Depsgraph *depsgraph)
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
-}
-
-static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
-{
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- const int mode_flag = OB_MODE_SCULPT;
- const bool is_mode_set = (ob->mode & mode_flag) != 0;
-
- if (!is_mode_set) {
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
- return OPERATOR_CANCELLED;
- }
- }
-
- if (is_mode_set) {
- ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
- }
- else {
- if (depsgraph) {
- depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- }
- ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports);
- BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint);
-
- if (ob->mode & mode_flag) {
- Mesh *me = ob->data;
- /* Dyntopo adds its own undo step. */
- if ((me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) {
- /* Without this the memfile undo step is used,
- * while it works it causes lag when undoing the first undo step, see T71564. */
- wmWindowManager *wm = CTX_wm_manager(C);
- if (wm->op_undo_depth <= 1) {
- SCULPT_undo_push_begin(ob, op->type->name);
- }
- }
- }
- }
-
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
-
- WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
-
- WM_toolsystem_update_from_context_view3d(C);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Sculpt Mode";
- ot->idname = "SCULPT_OT_sculptmode_toggle";
- ot->description = "Toggle sculpt mode in 3D view";
-
- /* API callbacks. */
- ot->exec = sculpt_mode_toggle_exec;
- ot->poll = ED_operator_object_active_editable_mesh;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
-
- ss->preview_vert_index_count = 0;
- int totpoints = 0;
-
- /* This function is called from the cursor drawing code, so the PBVH may not be build yet. */
- if (!ss->pbvh) {
- return;
- }
-
- if (!ss->deform_modifiers_active) {
- return;
- }
-
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return;
- }
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
-
- if (!ss->pmap) {
- return;
- }
-
- float brush_co[3];
- copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss));
-
- BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
-
- /* Assuming an average of 6 edges per vertex in a triangulated mesh. */
- const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2;
-
- if (ss->preview_vert_index_list == NULL) {
- ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
- }
-
- GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
- int active_v = SCULPT_active_vertex_get(ss);
- BLI_gsqueue_push(not_visited_vertices, &active_v);
-
- while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
- int from_v;
- BLI_gsqueue_pop(not_visited_vertices, &from_v);
- SculptVertexNeighborIter ni;
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
- if (totpoints + (ni.size * 2) < max_preview_vertices) {
- int to_v = ni.index;
- ss->preview_vert_index_list[totpoints] = from_v;
- totpoints++;
- ss->preview_vert_index_list[totpoints] = to_v;
- totpoints++;
- if (BLI_BITMAP_TEST(visited_vertices, to_v)) {
- continue;
- }
- BLI_BITMAP_ENABLE(visited_vertices, to_v);
- const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v);
- if (len_squared_v3v3(brush_co, co) < radius * radius) {
- BLI_gsqueue_push(not_visited_vertices, &to_v);
- }
- }
- }
- SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
- }
-
- BLI_gsqueue_free(not_visited_vertices);
-
- MEM_freeN(visited_vertices);
-
- ss->preview_vert_index_count = totpoints;
-}
-
-static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
-
- ID *data;
- data = ob->data;
- if (data && ID_IS_LINKED(data)) {
- return OPERATOR_CANCELLED;
- }
-
- if (ob->type != OB_MESH) {
- return OPERATOR_CANCELLED;
- }
-
- Mesh *mesh = ob->data;
-
- const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
- if (mloopcol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
-
- const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
- if (MPropCol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
-
- MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
- MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
-
- for (int i = 0; i < mesh->totpoly; i++) {
- MPoly *c_poly = &polys[i];
- for (int j = 0; j < c_poly->totloop; j++) {
- int loop_index = c_poly->loopstart + j;
- MLoop *c_loop = &loops[c_poly->loopstart + j];
- float srgb_color[4];
- linearrgb_to_srgb_v4(srgb_color, vertcols[c_loop->v].color);
- loopcols[loop_index].r = (char)(srgb_color[0] * 255);
- loopcols[loop_index].g = (char)(srgb_color[1] * 255);
- loopcols[loop_index].b = (char)(srgb_color[2] * 255);
- loopcols[loop_index].a = (char)(srgb_color[3] * 255);
- }
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Sculpt Vertex Color to Vertex Color";
- ot->description = "Copy the Sculpt Vertex Color to a regular color layer";
- ot->idname = "SCULPT_OT_vertex_to_loop_colors";
-
- /* api callbacks */
- ot->poll = SCULPT_vertex_colors_poll;
- ot->exec = vertex_to_loop_colors_exec;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob = CTX_data_active_object(C);
-
- ID *data;
- data = ob->data;
- if (data && ID_IS_LINKED(data)) {
- return OPERATOR_CANCELLED;
- }
-
- if (ob->type != OB_MESH) {
- return OPERATOR_CANCELLED;
- }
-
- Mesh *mesh = ob->data;
-
- const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
- if (mloopcol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
-
- const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
- if (MPropCol_layer_n == -1) {
- return OPERATOR_CANCELLED;
- }
- MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
-
- MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
- MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
-
- for (int i = 0; i < mesh->totpoly; i++) {
- MPoly *c_poly = &polys[i];
- for (int j = 0; j < c_poly->totloop; j++) {
- int loop_index = c_poly->loopstart + j;
- MLoop *c_loop = &loops[c_poly->loopstart + j];
- vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f);
- vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f);
- vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f);
- vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f);
- srgb_to_linearrgb_v4(vertcols[c_loop->v].color, vertcols[c_loop->v].color);
- }
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Vertex Color to Sculpt Vertex Color";
- ot->description = "Copy the active loop color layer to the vertex color";
- ot->idname = "SCULPT_OT_loop_to_vertex_colors";
-
- /* api callbacks */
- ot->poll = SCULPT_vertex_colors_poll;
- ot->exec = loop_to_vertex_colors_exec;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-static int sculpt_sample_color_invoke(bContext *C,
- wmOperator *UNUSED(op),
- const wmEvent *UNUSED(e))
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
- int active_vertex = SCULPT_active_vertex_get(ss);
- const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex);
- if (!active_vertex_color) {
- return OPERATOR_CANCELLED;
- }
-
- float color_srgb[3];
- copy_v3_v3(color_srgb, active_vertex_color);
- IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb);
- BKE_brush_color_set(scene, brush, color_srgb);
-
- WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_sample_color(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Sample Color";
- ot->idname = "SCULPT_OT_sample_color";
- ot->description = "Sample the vertex color of the active vertex";
-
- /* api callbacks */
- ot->invoke = sculpt_sample_color_invoke;
- ot->poll = SCULPT_vertex_colors_poll;
-
- ot->flag = OPTYPE_REGISTER;
-}
-
/* Fake Neighbors. */
/* This allows the sculpt tools to work on meshes with multiple connected components as they had
* only one connected component. When initialized and enabled, the sculpt API will return extra
@@ -9105,356 +5705,10 @@ void SCULPT_fake_neighbors_free(Object *ob)
sculpt_pose_fake_neighbors_free(ss);
}
-/**
- * #sculpt_mask_by_color_delta_get returns values in the (0,1) range that are used to generate the
- * mask based on the difference between two colors (the active color and the color of any other
- * vertex). Ideally, a threshold of 0 should mask only the colors that are equal to the active
- * color and threshold of 1 should mask all colors. In order to avoid artifacts and produce softer
- * falloffs in the mask, the MASK_BY_COLOR_SLOPE defines the size of the transition values between
- * masked and unmasked vertices. The smaller this value is, the sharper the generated mask is going
- * to be.
- */
-#define MASK_BY_COLOR_SLOPE 0.25f
-
-static float sculpt_mask_by_color_delta_get(const float *color_a,
- const float *color_b,
- const float threshold,
- const bool invert)
-{
- float len = len_v3v3(color_a, color_b);
- /* Normalize len to the (0, 1) range. */
- len = len / M_SQRT3;
-
- if (len < threshold - MASK_BY_COLOR_SLOPE) {
- len = 1.0f;
- }
- else if (len >= threshold) {
- len = 0.0f;
- }
- else {
- len = (-len + threshold) / MASK_BY_COLOR_SLOPE;
- }
-
- if (invert) {
- return 1.0f - len;
- }
- return len;
-}
-
-static float sculpt_mask_by_color_final_mask_get(const float current_mask,
- const float new_mask,
- const bool invert,
- const bool preserve_mask)
-{
- if (preserve_mask) {
- if (invert) {
- return min_ff(current_mask, new_mask);
- }
- return max_ff(current_mask, new_mask);
- }
- return new_mask;
-}
-
-typedef struct MaskByColorContiguousFloodFillData {
- float threshold;
- bool invert;
- float *new_mask;
- float initial_color[3];
-} MaskByColorContiguousFloodFillData;
-
-static void do_mask_by_color_contiguous_update_nodes_cb(
- void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
-
- SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
- bool update_node = false;
-
- const bool invert = data->mask_by_color_invert;
- const bool preserve_mask = data->mask_by_color_preserve_mask;
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- const float current_mask = *vd.mask;
- const float new_mask = data->mask_by_color_floodfill[vd.index];
- *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
- if (current_mask == *vd.mask) {
- continue;
- }
- update_node = true;
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
- if (update_node) {
- BKE_pbvh_node_mark_redraw(data->nodes[n]);
- }
-}
-
-static bool sculpt_mask_by_color_contiguous_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
-{
- MaskByColorContiguousFloodFillData *data = userdata;
- const float *current_color = SCULPT_vertex_color_get(ss, to_v);
- float new_vertex_mask = sculpt_mask_by_color_delta_get(
- current_color, data->initial_color, data->threshold, data->invert);
- data->new_mask[to_v] = new_vertex_mask;
-
- if (is_duplicate) {
- data->new_mask[to_v] = data->new_mask[from_v];
- }
-
- float len = len_v3v3(current_color, data->initial_color);
- len = len / M_SQRT3;
- return len <= data->threshold;
-}
-
-static void sculpt_mask_by_color_contiguous(Object *object,
- const int vertex,
- const float threshold,
- const bool invert,
- const bool preserve_mask)
-{
- SculptSession *ss = object->sculpt;
- const int totvert = SCULPT_vertex_count_get(ss);
-
- float *new_mask = MEM_calloc_arrayN(totvert, sizeof(float), "new mask");
-
- if (invert) {
- for (int i = 0; i < totvert; i++) {
- new_mask[i] = 1.0f;
- }
- }
-
- SculptFloodFill flood;
- SCULPT_floodfill_init(ss, &flood);
- SCULPT_floodfill_add_initial(&flood, vertex);
-
- MaskByColorContiguousFloodFillData ffd;
- ffd.threshold = threshold;
- ffd.invert = invert;
- ffd.new_mask = new_mask;
- copy_v3_v3(ffd.initial_color, SCULPT_vertex_color_get(ss, vertex));
-
- SCULPT_floodfill_execute(ss, &flood, sculpt_mask_by_color_contiguous_floodfill_cb, &ffd);
- SCULPT_floodfill_free(&flood);
-
- int totnode;
- PBVHNode **nodes;
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-
- SculptThreadedTaskData data = {
- .ob = object,
- .nodes = nodes,
- .mask_by_color_floodfill = new_mask,
- .mask_by_color_vertex = vertex,
- .mask_by_color_threshold = threshold,
- .mask_by_color_invert = invert,
- .mask_by_color_preserve_mask = preserve_mask,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(
- 0, totnode, &data, do_mask_by_color_contiguous_update_nodes_cb, &settings);
-
- MEM_SAFE_FREE(nodes);
-
- MEM_freeN(new_mask);
-}
-
-static void do_mask_by_color_task_cb(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
-
- SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
- bool update_node = false;
-
- const float threshold = data->mask_by_color_threshold;
- const bool invert = data->mask_by_color_invert;
- const bool preserve_mask = data->mask_by_color_preserve_mask;
- const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
- const float current_mask = *vd.mask;
- const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert);
- *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
-
- if (current_mask == *vd.mask) {
- continue;
- }
- update_node = true;
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
- if (update_node) {
- BKE_pbvh_node_mark_redraw(data->nodes[n]);
- }
-}
-
-static void sculpt_mask_by_color_full_mesh(Object *object,
- const int vertex,
- const float threshold,
- const bool invert,
- const bool preserve_mask)
-{
- SculptSession *ss = object->sculpt;
-
- int totnode;
- PBVHNode **nodes;
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-
- SculptThreadedTaskData data = {
- .ob = object,
- .nodes = nodes,
- .mask_by_color_vertex = vertex,
- .mask_by_color_threshold = threshold,
- .mask_by_color_invert = invert,
- .mask_by_color_preserve_mask = preserve_mask,
- };
-
- TaskParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_mask_by_color_task_cb, &settings);
-
- MEM_SAFE_FREE(nodes);
-}
-
-static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
-
- /* Color data is not available in Multires. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
- return OPERATOR_CANCELLED;
- }
-
- if (!ss->vcol) {
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_vertex_random_access_ensure(ss);
-
- /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move,
- * so it needs to be updated here. */
- SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
-
- SCULPT_undo_push_begin(ob, "Mask by color");
-
- const int active_vertex = SCULPT_active_vertex_get(ss);
- const float threshold = RNA_float_get(op->ptr, "threshold");
- const bool invert = RNA_boolean_get(op->ptr, "invert");
- const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask");
-
- if (RNA_boolean_get(op->ptr, "contiguous")) {
- sculpt_mask_by_color_contiguous(ob, active_vertex, threshold, invert, preserve_mask);
- }
- else {
- sculpt_mask_by_color_full_mesh(ob, active_vertex, threshold, invert, preserve_mask);
- }
-
- BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
- SCULPT_undo_push_end();
-
- SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Mask by Color";
- ot->idname = "SCULPT_OT_mask_by_color";
- ot->description = "Creates a mask based on the sculpt vertex colors";
-
- /* api callbacks */
- ot->invoke = sculpt_mask_by_color_invoke;
- ot->poll = SCULPT_vertex_colors_poll;
-
- ot->flag = OPTYPE_REGISTER;
-
- ot->prop = RNA_def_boolean(
- ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas");
-
- ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask");
- ot->prop = RNA_def_boolean(
- ot->srna,
- "preserve_previous_mask",
- false,
- "Preserve Previous Mask",
- "Preserve the previous mask and add or subtract the new one generated by the colors");
-
- RNA_def_float(ot->srna,
- "threshold",
- 0.35f,
- 0.0f,
- 1.0f,
- "Threshold",
- "How much changes in color affect the mask generation",
- 0.0f,
- 1.0f);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
/** \name Operator Registration
* \{ */
-void ED_operatortypes_sculpt(void)
-{
- WM_operatortype_append(SCULPT_OT_brush_stroke);
- WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
- WM_operatortype_append(SCULPT_OT_set_persistent_base);
- WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle);
- WM_operatortype_append(SCULPT_OT_optimize);
- WM_operatortype_append(SCULPT_OT_symmetrize);
- WM_operatortype_append(SCULPT_OT_detail_flood_fill);
- WM_operatortype_append(SCULPT_OT_sample_detail_size);
- WM_operatortype_append(SCULPT_OT_set_detail_size);
- WM_operatortype_append(SCULPT_OT_mesh_filter);
- WM_operatortype_append(SCULPT_OT_mask_filter);
- WM_operatortype_append(SCULPT_OT_dirty_mask);
- WM_operatortype_append(SCULPT_OT_mask_expand);
- WM_operatortype_append(SCULPT_OT_set_pivot_position);
- WM_operatortype_append(SCULPT_OT_face_sets_create);
- WM_operatortype_append(SCULPT_OT_face_sets_change_visibility);
- WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors);
- WM_operatortype_append(SCULPT_OT_face_sets_init);
- WM_operatortype_append(SCULPT_OT_cloth_filter);
- WM_operatortype_append(SCULPT_OT_face_sets_edit);
- WM_operatortype_append(SCULPT_OT_face_set_lasso_gesture);
- WM_operatortype_append(SCULPT_OT_face_set_box_gesture);
- WM_operatortype_append(SCULPT_OT_trim_box_gesture);
- WM_operatortype_append(SCULPT_OT_trim_lasso_gesture);
- WM_operatortype_append(SCULPT_OT_project_line_gesture);
-
- WM_operatortype_append(SCULPT_OT_sample_color);
- WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors);
- WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors);
- WM_operatortype_append(SCULPT_OT_color_filter);
- WM_operatortype_append(SCULPT_OT_mask_by_color);
- WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit);
- WM_operatortype_append(SCULPT_OT_mask_init);
-
- WM_operatortype_append(SCULPT_OT_expand);
-}
-
/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_brushes.c b/source/blender/editors/sculpt_paint/sculpt_brushes.c
new file mode 100644
index 00000000000..8842d93410c
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_brushes.c
@@ -0,0 +1,2847 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ * Implements the Sculpt Mode tools
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_dial_2d.h"
+#include "BLI_ghash.h"
+#include "BLI_gsqueue.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_math_color.h"
+#include "BLI_math_color_blend.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "PIL_time.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_ccg.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_kelvinlet.h"
+#include "BKE_key.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_mirror.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_pbvh.h"
+#include "BKE_pointcache.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_subdiv_ccg.h"
+#include "BKE_subsurf.h"
+
+#include "DEG_depsgraph.h"
+
+#include "IMB_colormanagement.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* -------------------------------------------------------------------- */
+/** \name SculptProjectVector
+ *
+ * Fast-path for #project_plane_v3_v3v3
+ * \{ */
+
+typedef struct SculptProjectVector {
+ float plane[3];
+ float len_sq;
+ float len_sq_inv_neg;
+ bool is_valid;
+
+} SculptProjectVector;
+
+static bool plane_point_side_flip(const float co[3], const float plane[4], const bool flip)
+{
+ float d = plane_point_side_v3(plane, co);
+ if (flip) {
+ d = -d;
+ }
+ return d <= 0.0f;
+}
+
+/**
+ * \param plane: Direction, can be any length.
+ */
+static void sculpt_project_v3_cache_init(SculptProjectVector *spvc, const float plane[3])
+{
+ copy_v3_v3(spvc->plane, plane);
+ spvc->len_sq = len_squared_v3(spvc->plane);
+ spvc->is_valid = (spvc->len_sq > FLT_EPSILON);
+ spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f;
+}
+
+/**
+ * Calculate the projection.
+ */
+static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3], float r_vec[3])
+{
+#if 0
+ project_plane_v3_v3v3(r_vec, vec, spvc->plane);
+#else
+ /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */
+ madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg);
+#endif
+}
+
+static void calc_sculpt_plane(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3])
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (SCULPT_stroke_is_main_symmetry_pass(ss->cache) &&
+ (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache) ||
+ !(brush->flag & BRUSH_ORIGINAL_PLANE) || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
+ switch (brush->sculpt_plane) {
+ case SCULPT_DISP_DIR_VIEW:
+ copy_v3_v3(r_area_no, ss->cache->true_view_normal);
+ break;
+
+ case SCULPT_DISP_DIR_X:
+ ARRAY_SET_ITEMS(r_area_no, 1.0f, 0.0f, 0.0f);
+ break;
+
+ case SCULPT_DISP_DIR_Y:
+ ARRAY_SET_ITEMS(r_area_no, 0.0f, 1.0f, 0.0f);
+ break;
+
+ case SCULPT_DISP_DIR_Z:
+ ARRAY_SET_ITEMS(r_area_no, 0.0f, 0.0f, 1.0f);
+ break;
+
+ case SCULPT_DISP_DIR_AREA:
+ SCULPT_calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal);
+ normalize_v3(r_area_no);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* For flatten center. */
+ /* Flatten center has not been calculated yet if we are not using the area normal. */
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) {
+ SCULPT_calc_area_center(sd, ob, nodes, totnode, r_area_co);
+ }
+
+ /* For area normal. */
+ if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
+ (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
+ }
+ else {
+ copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
+ }
+
+ /* For flatten center. */
+ if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) &&
+ (brush->flag & BRUSH_ORIGINAL_PLANE)) {
+ copy_v3_v3(r_area_co, ss->cache->last_center);
+ }
+ else {
+ copy_v3_v3(ss->cache->last_center, r_area_co);
+ }
+ }
+ else {
+ /* For area normal. */
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
+
+ /* For flatten center. */
+ copy_v3_v3(r_area_co, ss->cache->last_center);
+
+ /* For area normal. */
+ flip_v3(r_area_no, ss->cache->mirror_symmetry_pass);
+
+ /* For flatten center. */
+ flip_v3(r_area_co, ss->cache->mirror_symmetry_pass);
+
+ /* For area normal. */
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_no);
+
+ /* For flatten center. */
+ mul_m4_v3(ss->cache->symm_rot_mat, r_area_co);
+
+ /* Shift the plane for the current tile. */
+ add_v3_v3(r_area_co, ss->cache->plane_offset);
+ }
+}
+
+static void sculpt_rake_rotate(const SculptSession *ss,
+ const float sculpt_co[3],
+ const float v_co[3],
+ float factor,
+ float r_delta[3])
+{
+ float vec_rot[3];
+
+#if 0
+ /* lerp */
+ sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+ mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot);
+ add_v3_v3(vec_rot, sculpt_co);
+ sub_v3_v3v3(r_delta, vec_rot, v_co);
+ mul_v3_fl(r_delta, factor);
+#else
+ /* slerp */
+ float q_interp[4];
+ sub_v3_v3v3(vec_rot, v_co, sculpt_co);
+
+ copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry);
+ pow_qt_fl_normalized(q_interp, factor);
+ mul_qt_v3(q_interp, vec_rot);
+
+ add_v3_v3(vec_rot, sculpt_co);
+ sub_v3_v3v3(r_delta, vec_rot, v_co);
+#endif
+}
+
+/**
+ * Align the grab delta to the brush normal.
+ *
+ * \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`.
+ */
+static void sculpt_project_v3_normal_align(SculptSession *ss,
+ const float normal_weight,
+ float grab_delta[3])
+{
+ /* Signed to support grabbing in (to make a hole) as well as out. */
+ const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta);
+
+ /* This scale effectively projects the offset so dragging follows the cursor,
+ * as the normal points towards the view, the scale increases. */
+ float len_view_scale;
+ {
+ float view_aligned_normal[3];
+ project_plane_v3_v3v3(
+ view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal);
+ len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm));
+ len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f;
+ }
+
+ mul_v3_fl(grab_delta, 1.0f - normal_weight);
+ madd_v3_v3fl(
+ grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Draw Brush
+ * \{ */
+
+static void do_draw_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ /* Offset vertex. */
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ const float bstrength = ss->cache->bstrength;
+
+ /* Offset with as much as possible factored in already. */
+ float effective_normal[3];
+ SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
+ mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
+ * initialize before threads so they can do curve mapping. */
+ BKE_curvemapping_init(brush->curve);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .offset = offset,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+static void do_fill_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ if (!SCULPT_plane_point_side(vd.co, test.plane_tool)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (!SCULPT_plane_trim(ss->cache, brush, val)) {
+ continue;
+ }
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+
+ float area_no[3];
+ float area_co[3];
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+
+ float displace;
+
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
+
+ displace = radius * offset;
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
+}
+
+static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ if (SCULPT_plane_point_side(vd.co, test.plane_tool)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (!SCULPT_plane_trim(ss->cache, brush, val)) {
+ continue;
+ }
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+
+ float area_no[3];
+ float area_co[3];
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+
+ float displace;
+
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
+
+ displace = -radius * offset;
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Clay Thumb Brush
+ * \{ */
+
+static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float(*mat)[4] = data->mat;
+ const float *area_no_sp = data->area_no_sp;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = data->clay_strength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ float plane_tilt[4];
+ float normal_tilt[3];
+ float imat[4][4];
+
+ invert_m4_m4(imat, mat);
+ rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss->cache->clay_thumb_front_angle));
+
+ /* Plane aligned to the geometry normal (back part of the brush). */
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
+ /* Tilted plane (front part of the brush). */
+ plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ float local_co[3];
+ mul_v3_m4v3(local_co, mat, vd.co);
+ float intr[3], intr_tilt[3];
+ float val[3];
+
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ closest_to_plane_normalized_v3(intr_tilt, plane_tilt, vd.co);
+
+ /* Mix the deformation of the aligned and the tilted plane based on the brush space vertex
+ * coordinates. */
+ /* We can also control the mix with a curve if it produces noticeable artifacts in the center
+ * of the brush. */
+ const float tilt_mix = local_co[1] > 0.0f ? 0.0f : 1.0f;
+ interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix);
+ sub_v3_v3v3(val, intr_tilt, vd.co);
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+float SCULPT_clay_thumb_get_stabilized_pressure(StrokeCache *cache)
+{
+ float final_pressure = 0.0f;
+ for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) {
+ final_pressure += cache->clay_pressure_stabilizer[i];
+ }
+ return final_pressure / SCULPT_CLAY_STABILIZER_LEN;
+}
+
+void SCULPT_do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+ const float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ const float displace = radius * (0.25f + offset);
+
+ /* Sampled geometry normal and area center. */
+ float area_no_sp[3];
+ float area_no[3];
+ float area_co[3];
+
+ float temp[3];
+ float mat[4][4];
+ float scale[4][4];
+ float tmat[4][4];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
+
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
+ }
+ else {
+ copy_v3_v3(area_no, area_no_sp);
+ }
+
+ /* Delay the first daub because grab delta is not setup. */
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ ss->cache->clay_thumb_front_angle = 0.0f;
+ return;
+ }
+
+ /* Simulate the clay accumulation by increasing the plane angle as more samples are added to the
+ * stroke. */
+ if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) {
+ ss->cache->clay_thumb_front_angle += 0.8f;
+ ss->cache->clay_thumb_front_angle = clamp_f(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f);
+ }
+
+ if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
+ return;
+ }
+
+ /* Displace the brush planes. */
+ copy_v3_v3(area_co, ss->cache->location);
+ mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ /* Initialize brush local-space matrix. */
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
+ mat[0][3] = 0.0f;
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
+ mat[1][3] = 0.0f;
+ copy_v3_v3(mat[2], area_no);
+ mat[2][3] = 0.0f;
+ copy_v3_v3(mat[3], ss->cache->location);
+ mat[3][3] = 1.0f;
+ normalize_m4(mat);
+
+ /* Scale brush local space matrix. */
+ scale_m4_fl(scale, ss->cache->radius);
+ mul_m4_m4m4(tmat, mat, scale);
+ invert_m4_m4(mat, tmat);
+
+ float clay_strength = ss->cache->bstrength *
+ SCULPT_clay_thumb_get_stabilized_pressure(ss->cache);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no_sp = area_no_sp,
+ .area_co = ss->cache->location,
+ .mat = mat,
+ .clay_strength = clay_strength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ float intr[3];
+ float val[3];
+
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (SCULPT_plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = ss->cache->radius;
+
+ float area_no[3];
+ float area_co[3];
+
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ float displace;
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor);
+
+ displace = radius * offset;
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Clay Brush
+ * \{ */
+
+typedef struct ClaySampleData {
+ float plane_dist[2];
+} ClaySampleData;
+
+static void calc_clay_surface_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ ClaySampleData *csd = tls->userdata_chunk;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+ float plane[4];
+
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, brush->falloff_shape);
+
+ /* Apply the brush normal radius to the test before sampling. */
+ float test_radius = sqrtf(test.radius_squared);
+ test_radius *= brush->normal_radius_factor;
+ test.radius_squared = test_radius * test_radius;
+ plane_from_point_normal_v3(plane, area_co, area_no);
+
+ if (is_zero_v4(plane)) {
+ return;
+ }
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ float plane_dist = dist_signed_to_plane_v3(vd.co, plane);
+ float plane_dist_abs = fabsf(plane_dist);
+ if (plane_dist > 0.0f) {
+ csd->plane_dist[0] = MIN2(csd->plane_dist[0], plane_dist_abs);
+ }
+ else {
+ csd->plane_dist[1] = MIN2(csd->plane_dist[1], plane_dist_abs);
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+}
+
+static void calc_clay_surface_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ ClaySampleData *join = chunk_join;
+ ClaySampleData *csd = chunk;
+ join->plane_dist[0] = MIN2(csd->plane_dist[0], join->plane_dist[0]);
+ join->plane_dist[1] = MIN2(csd->plane_dist[1], join->plane_dist[1]);
+}
+
+static void do_clay_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *area_no = data->area_no;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = fabsf(ss->cache->bstrength);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const float radius = fabsf(ss->cache->radius);
+ const float initial_radius = fabsf(ss->cache->initial_radius);
+ bool flip = ss->cache->bstrength < 0.0f;
+
+ float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ float displace;
+
+ float area_no[3];
+ float area_co[3];
+ float temp[3];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ SculptThreadedTaskData sample_data = {
+ .sd = NULL,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .totnode = totnode,
+ .area_no = area_no,
+ .area_co = ss->cache->location,
+ };
+
+ ClaySampleData csd = {{0}};
+
+ TaskParallelSettings sample_settings;
+ BKE_pbvh_parallel_range_settings(&sample_settings, true, totnode);
+ sample_settings.func_reduce = calc_clay_surface_reduce;
+ sample_settings.userdata_chunk = &csd;
+ sample_settings.userdata_chunk_size = sizeof(ClaySampleData);
+
+ BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
+
+ float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]);
+ d_offset = min_ff(radius, d_offset);
+ d_offset = d_offset / radius;
+ d_offset = 1.0f - d_offset;
+ displace = fabsf(initial_radius * (0.25f + offset + (d_offset * 0.15f)));
+ if (flip) {
+ displace = -displace;
+ }
+
+ mul_v3_v3v3(temp, area_no, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ copy_v3_v3(area_co, ss->cache->location);
+ add_v3_v3(area_co, temp);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no = area_no,
+ .area_co = area_co,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
+}
+
+static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float(*mat)[4] = data->mat;
+ const float *area_no_sp = data->area_no_sp;
+ const float *area_co = data->area_co;
+
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float(*proxy)[3];
+ const bool flip = (ss->cache->bstrength < 0.0f);
+ const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SCULPT_brush_test_init(ss, &test);
+ plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) {
+ continue;
+ }
+
+ if (!plane_point_side_flip(vd.co, test.plane_tool, flip)) {
+ continue;
+ }
+
+ float intr[3];
+ float val[3];
+ closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co);
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (!SCULPT_plane_trim(ss->cache, brush, val)) {
+ continue;
+ }
+ /* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ ss->cache->radius * test.dist,
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const bool flip = (ss->cache->bstrength < 0.0f);
+ const float radius = flip ? -ss->cache->radius : ss->cache->radius;
+ const float offset = SCULPT_brush_plane_offset_get(sd, ss);
+ const float displace = radius * (0.18f + offset);
+
+ /* The sculpt-plane normal (whatever its set to). */
+ float area_no_sp[3];
+
+ /* Geometry normal */
+ float area_no[3];
+ float area_co[3];
+
+ float temp[3];
+ float mat[4][4];
+ float scale[4][4];
+ float tmat[4][4];
+
+ SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co);
+ SCULPT_tilt_apply_to_normal(area_no_sp, ss->cache, brush->tilt_strength_factor);
+
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no);
+ }
+ else {
+ copy_v3_v3(area_no, area_no_sp);
+ }
+
+ /* Delay the first daub because grab delta is not setup. */
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ return;
+ }
+
+ if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
+ return;
+ }
+
+ mul_v3_v3v3(temp, area_no_sp, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(area_co, temp);
+
+ /* Clay Strips uses a cube test with falloff in the XY axis (not in Z) and a plane to deform the
+ * vertices. When in Add mode, vertices that are below the plane and inside the cube are move
+ * towards the plane. In this situation, there may be cases where a vertex is outside the cube
+ * but below the plane, so won't be deformed, causing artifacts. In order to prevent these
+ * artifacts, this displaces the test cube space in relation to the plane in order to
+ * deform more vertices that may be below it. */
+ /* The 0.7 and 1.25 factors are arbitrary and don't have any relation between them, they were set
+ * by doing multiple tests using the default "Clay Strips" brush preset. */
+ float area_co_displaced[3];
+ madd_v3_v3v3fl(area_co_displaced, area_co, area_no, -radius * 0.7f);
+
+ /* Initialize brush local-space matrix. */
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
+ mat[0][3] = 0.0f;
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
+ mat[1][3] = 0.0f;
+ copy_v3_v3(mat[2], area_no);
+ mat[2][3] = 0.0f;
+ copy_v3_v3(mat[3], area_co_displaced);
+ mat[3][3] = 1.0f;
+ normalize_m4(mat);
+
+ /* Scale brush local space matrix. */
+ scale_m4_fl(scale, ss->cache->radius);
+ mul_m4_m4m4(tmat, mat, scale);
+
+ /* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in
+ * Z this does not produce artifacts in the falloff cube and allows to deform extra vertices
+ * during big deformation while keeping the surface as uniform as possible. */
+ mul_v3_fl(tmat[2], 1.25f);
+
+ invert_m4_m4(mat, tmat);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .area_no_sp = area_no_sp,
+ .area_co = area_co,
+ .mat = mat,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
+}
+
+static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ SculptProjectVector *spvc = data->spvc;
+ const float *grab_delta = data->grab_delta;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+ const bool do_rake_rotation = ss->cache->is_rake_rotation_valid;
+ const bool do_pinch = (brush->crease_pinch_factor != 0.5f);
+ const float pinch = do_pinch ? (2.0f * (0.5f - brush->crease_pinch_factor) *
+ (len_v3(grab_delta) / ss->cache->radius)) :
+ 0.0f;
+
+ const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ KelvinletParams params;
+ BKE_kelvinlet_init_params(&params, ss->cache->radius, bstrength, 1.0f, 0.4f);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ float fade;
+ if (do_elastic) {
+ fade = 1.0f;
+ }
+ else {
+ fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ }
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ /* Negative pinch will inflate, helps maintain volume. */
+ if (do_pinch) {
+ float delta_pinch_init[3], delta_pinch[3];
+
+ sub_v3_v3v3(delta_pinch, vd.co, test.location);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal);
+ }
+
+ /* Important to calculate based on the grabbed location
+ * (intentionally ignore fade here). */
+ add_v3_v3(delta_pinch, grab_delta);
+
+ sculpt_project_v3(spvc, delta_pinch, delta_pinch);
+
+ copy_v3_v3(delta_pinch_init, delta_pinch);
+
+ float pinch_fade = pinch * fade;
+ /* When reducing, scale reduction back by how close to the center we are,
+ * so we don't pinch into nothingness. */
+ if (pinch > 0.0f) {
+ /* Square to have even less impact for close vertices. */
+ pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius));
+ }
+ mul_v3_fl(delta_pinch, 1.0f + pinch_fade);
+ sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch);
+ add_v3_v3(proxy[vd.i], delta_pinch);
+ }
+
+ if (do_rake_rotation) {
+ float delta_rotate[3];
+ sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate);
+ add_v3_v3(proxy[vd.i], delta_rotate);
+ }
+
+ if (do_elastic) {
+ float disp[3];
+ BKE_kelvinlet_grab_triscale(disp, &params, vd.co, ss->cache->location, proxy[vd.i]);
+ mul_v3_fl(disp, bstrength * 20.0f);
+ if (vd.mask) {
+ mul_v3_fl(disp, 1.0f - *vd.mask);
+ }
+ mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
+ copy_v3_v3(proxy[vd.i], disp);
+ }
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ const float bstrength = ss->cache->bstrength;
+ float grab_delta[3];
+
+ SculptProjectVector spvc;
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ if (bstrength < 0.0f) {
+ negate_v3(grab_delta);
+ }
+
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
+
+ /* Optionally pinch while painting. */
+ if (brush->crease_pinch_factor != 0.5f) {
+ sculpt_project_v3_cache_init(&spvc, grab_delta);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .spvc = &spvc,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
+}
+
+static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *cono = data->cono;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+ float tmp[3], cono[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
+ cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .cono = cono,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
+}
+
+static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float angle = data->angle;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ float vec[3], rot[3][3];
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
+ axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
+ mul_v3_m3v3(proxy[vd.i], rot, vec);
+ add_v3_v3(proxy[vd.i], ss->cache->location);
+ sub_v3_v3(proxy[vd.i], orig_data.co);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ static const int flip[8] = {1, -1, -1, 1, -1, 1, 1, -1};
+ const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .angle = angle,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
+}
+
+static void do_layer_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+
+ const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ const float bstrength = ss->cache->bstrength;
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ const int vi = vd.index;
+ float *disp_factor;
+ if (use_persistent_base) {
+ disp_factor = &ss->persistent_base[vi].disp;
+ }
+ else {
+ disp_factor = &ss->cache->layer_displacement_factor[vi];
+ }
+
+ /* When using persistent base, the layer brush (holding Control) invert mode resets the
+ * height of the layer to 0. This makes possible to clean edges of previously added layers
+ * on top of the base. */
+ /* The main direction of the layers is inverted using the regular brush strength with the
+ * brush direction property. */
+ if (use_persistent_base && ss->cache->invert) {
+ (*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) *
+ ((*disp_factor) > 0.0f ? -1.0f : 1.0f);
+ }
+ else {
+ (*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor));
+ }
+ if (vd.mask) {
+ const float clamp_mask = 1.0f - *vd.mask;
+ *disp_factor = clamp_f(*disp_factor, -clamp_mask, clamp_mask);
+ }
+ else {
+ *disp_factor = clamp_f(*disp_factor, -1.0f, 1.0f);
+ }
+
+ float final_co[3];
+ float normal[3];
+
+ if (use_persistent_base) {
+ SCULPT_vertex_persistent_normal_get(ss, vi, normal);
+ mul_v3_fl(normal, brush->height);
+ madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor);
+ }
+ else {
+ normal_short_to_float_v3(normal, orig_data.no);
+ mul_v3_fl(normal, brush->height);
+ madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor);
+ }
+
+ float vdisp[3];
+ sub_v3_v3v3(vdisp, final_co, vd.co);
+ mul_v3_fl(vdisp, fabsf(fade));
+ add_v3_v3v3(final_co, vd.co, vdisp);
+
+ SCULPT_clip(sd, ss, vd.co, final_co);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (ss->cache->layer_displacement_factor == NULL) {
+ ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
+ "layer displacement factor");
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
+}
+
+static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float val[3];
+
+ if (vd.fno) {
+ copy_v3_v3(val, vd.fno);
+ }
+ else {
+ normal_short_to_float_v3(val, vd.no);
+ }
+
+ mul_v3_fl(val, fade * ss->cache->radius);
+ mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
+}
+
+static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *cono = data->cono;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+ float tmp[3], cono[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
+ cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .cono = cono,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Crease & Blob Brush
+ * \{ */
+
+/**
+ * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB'
+ */
+static void do_crease_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ SculptProjectVector *spvc = data->spvc;
+ const float flippedbstrength = data->flippedbstrength;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ /* Offset vertex. */
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float val1[3];
+ float val2[3];
+
+ /* First we pinch. */
+ sub_v3_v3v3(val1, test.location, vd.co);
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(val1, val1, ss->cache->view_normal);
+ }
+
+ mul_v3_fl(val1, fade * flippedbstrength);
+
+ sculpt_project_v3(spvc, val1, val1);
+
+ /* Then we draw. */
+ mul_v3_v3fl(val2, offset, fade);
+
+ add_v3_v3v3(proxy[vd.i], val1, val2);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ const Scene *scene = ss->cache->vc->scene;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ float bstrength = ss->cache->bstrength;
+ float flippedbstrength, crease_correction;
+ float brush_alpha;
+
+ SculptProjectVector spvc;
+
+ /* Offset with as much as possible factored in already. */
+ mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* We divide out the squared alpha and multiply by the squared crease
+ * to give us the pinch strength. */
+ crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor;
+ brush_alpha = BKE_brush_alpha_get(scene, brush);
+ if (brush_alpha > 0.0f) {
+ crease_correction /= brush_alpha * brush_alpha;
+ }
+
+ /* We always want crease to pinch or blob to relax even when draw is negative. */
+ flippedbstrength = (bstrength < 0.0f) ? -crease_correction * bstrength :
+ crease_correction * bstrength;
+
+ if (brush->sculpt_tool == SCULPT_TOOL_BLOB) {
+ flippedbstrength *= -1.0f;
+ }
+
+ /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single
+ * point. Without this we get a 'flat' surface surrounding the pinch. */
+ sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .spvc = &spvc,
+ .offset = offset,
+ .flippedbstrength = flippedbstrength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
+}
+
+static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float(*stroke_xz)[3] = data->stroke_xz;
+
+ PBVHVertexIter vd;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ float x_object_space[3];
+ float z_object_space[3];
+ copy_v3_v3(x_object_space, stroke_xz[0]);
+ copy_v3_v3(z_object_space, stroke_xz[1]);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float disp_center[3];
+ float x_disp[3];
+ float z_disp[3];
+ /* Calculate displacement from the vertex to the brush center. */
+ sub_v3_v3v3(disp_center, test.location, vd.co);
+
+ /* Project the displacement into the X vector (aligned to the stroke). */
+ mul_v3_v3fl(x_disp, x_object_space, dot_v3v3(disp_center, x_object_space));
+
+ /* Project the displacement into the Z vector (aligned to the surface normal). */
+ mul_v3_v3fl(z_disp, z_object_space, dot_v3v3(disp_center, z_object_space));
+
+ /* Add the two projected vectors to calculate the final displacement.
+ * The Y component is removed. */
+ add_v3_v3v3(disp_center, x_disp, z_disp);
+
+ if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ project_plane_v3_v3v3(disp_center, disp_center, ss->cache->view_normal);
+ }
+ mul_v3_v3fl(proxy[vd.i], disp_center, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ float area_no[3];
+ float area_co[3];
+
+ float mat[4][4];
+ calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co);
+
+ /* delay the first daub because grab delta is not setup */
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ return;
+ }
+
+ if (is_zero_v3(ss->cache->grab_delta_symmetry)) {
+ return;
+ }
+
+ /* Initialize `mat`. */
+ cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry);
+ mat[0][3] = 0.0f;
+ cross_v3_v3v3(mat[1], area_no, mat[0]);
+ mat[1][3] = 0.0f;
+ copy_v3_v3(mat[2], area_no);
+ mat[2][3] = 0.0f;
+ copy_v3_v3(mat[3], ss->cache->location);
+ mat[3][3] = 1.0f;
+ normalize_m4(mat);
+
+ float stroke_xz[2][3];
+ normalize_v3_v3(stroke_xz[0], mat[0]);
+ normalize_v3_v3(stroke_xz[1], mat[2]);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .stroke_xz = stroke_xz,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
+}
+
+static void do_grab_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *grab_delta = data->grab_delta;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE;
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ if (grab_silhouette) {
+ float silhouette_test_dir[3];
+ normalize_v3_v3(silhouette_test_dir, grab_delta);
+ if (dot_v3v3(ss->cache->initial_normal, ss->cache->grab_delta_symmetry) < 0.0f) {
+ mul_v3_fl(silhouette_test_dir, -1.0f);
+ }
+ float vno[3];
+ normal_short_to_float_v3(vno, orig_data.no);
+ fade *= max_ff(dot_v3v3(vno, silhouette_test_dir), 0.0f);
+ }
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
+}
+
+static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *grab_delta = data->grab_delta;
+ const float *location = ss->cache->location;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ const float bstrength = ss->cache->bstrength;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ float dir;
+ if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) {
+ dir = 1.0f;
+ }
+ else {
+ dir = -1.0f;
+ }
+
+ if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) {
+ int symm = ss->cache->mirror_symmetry_pass;
+ if (ELEM(symm, 1, 2, 4, 7)) {
+ dir = -dir;
+ }
+ }
+
+ KelvinletParams params;
+ float force = len_v3(grab_delta) * dir * bstrength;
+ BKE_kelvinlet_init_params(
+ &params, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ float final_disp[3];
+ switch (brush->elastic_deform_type) {
+ case BRUSH_ELASTIC_DEFORM_GRAB:
+ BKE_kelvinlet_grab(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
+ break;
+ case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: {
+ BKE_kelvinlet_grab_biscale(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
+ break;
+ }
+ case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: {
+ BKE_kelvinlet_grab_triscale(final_disp, &params, orig_data.co, location, grab_delta);
+ mul_v3_fl(final_disp, bstrength * 20.0f);
+ break;
+ }
+ case BRUSH_ELASTIC_DEFORM_SCALE:
+ BKE_kelvinlet_scale(
+ final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
+ break;
+ case BRUSH_ELASTIC_DEFORM_TWIST:
+ BKE_kelvinlet_twist(
+ final_disp, &params, orig_data.co, location, ss->cache->sculpt_normal_symm);
+ break;
+ }
+
+ if (vd.mask) {
+ mul_v3_fl(final_disp, 1.0f - *vd.mask);
+ }
+
+ mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index));
+
+ copy_v3_v3(proxy[vd.i], final_disp);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float grab_delta[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .grab_delta = grab_delta,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
+}
+/** \} */
+
+static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float *offset = data->offset;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ /* Offset vertex. */
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ float offset[3];
+ const float bstrength = ss->cache->bstrength;
+
+ /* Offset with as much as possible factored in already. */
+ float effective_normal[3];
+ SCULPT_tilt_effective_normal_get(ss, brush, effective_normal);
+ mul_v3_v3fl(offset, effective_normal, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise
+ * initialize before threads so they can do curve mapping. */
+ BKE_curvemapping_init(brush->curve);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .offset = offset,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Topology Brush
+ * \{ */
+
+static void do_topology_slide_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+ float(*proxy)[3];
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+ float current_disp[3];
+ float current_disp_norm[3];
+ float final_disp[3] = {0.0f, 0.0f, 0.0f};
+
+ switch (brush->slide_deform_type) {
+ case BRUSH_SLIDE_DEFORM_DRAG:
+ sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ break;
+ case BRUSH_SLIDE_DEFORM_PINCH:
+ sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
+ break;
+ case BRUSH_SLIDE_DEFORM_EXPAND:
+ sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
+ break;
+ }
+
+ normalize_v3_v3(current_disp_norm, current_disp);
+ mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float vertex_disp[3];
+ float vertex_disp_norm[3];
+ sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
+ normalize_v3_v3(vertex_disp_norm, vertex_disp);
+ if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) {
+ madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp));
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ mul_v3_v3fl(proxy[vd.i], final_disp, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_relax_vertex(SculptSession *ss,
+ PBVHVertexIter *vd,
+ float factor,
+ bool filter_boundary_face_sets,
+ float *r_final_pos)
+{
+ float smooth_pos[3];
+ float final_disp[3];
+ float boundary_normal[3];
+ int avg_count = 0;
+ int neighbor_count = 0;
+ zero_v3(smooth_pos);
+ zero_v3(boundary_normal);
+ const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index);
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
+ neighbor_count++;
+ if (!filter_boundary_face_sets ||
+ (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) {
+
+ /* When the vertex to relax is boundary, use only connected boundary vertices for the average
+ * position. */
+ if (is_boundary) {
+ if (!SCULPT_vertex_is_boundary(ss, ni.index)) {
+ continue;
+ }
+ add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
+ avg_count++;
+
+ /* Calculate a normal for the constraint plane using the edges of the boundary. */
+ float to_neighbor[3];
+ sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co);
+ normalize_v3(to_neighbor);
+ add_v3_v3(boundary_normal, to_neighbor);
+ }
+ else {
+ add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
+ avg_count++;
+ }
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ /* Don't modify corner vertices. */
+ if (neighbor_count <= 2) {
+ copy_v3_v3(r_final_pos, vd->co);
+ return;
+ }
+
+ if (avg_count > 0) {
+ mul_v3_fl(smooth_pos, 1.0f / avg_count);
+ }
+ else {
+ copy_v3_v3(r_final_pos, vd->co);
+ return;
+ }
+
+ float plane[4];
+ float smooth_closest_plane[3];
+ float vno[3];
+
+ if (is_boundary && avg_count == 2) {
+ normalize_v3_v3(vno, boundary_normal);
+ }
+ else {
+ SCULPT_vertex_normal_get(ss, vd->index, vno);
+ }
+
+ if (is_zero_v3(vno)) {
+ copy_v3_v3(r_final_pos, vd->co);
+ return;
+ }
+
+ plane_from_point_normal_v3(plane, vd->co, vno);
+ closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos);
+ sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co);
+
+ mul_v3_fl(final_disp, factor);
+ add_v3_v3v3(r_final_pos, vd->co, final_disp);
+}
+
+static void do_topology_relax_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+
+ BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) {
+ continue;
+ }
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ orig_data.co,
+ sqrtf(test.dist),
+ orig_data.no,
+ NULL,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) {
+ return;
+ }
+
+ BKE_curvemapping_init(brush->curve);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ if (ss->cache->alt_smooth) {
+ SCULPT_boundary_info_ensure(ob);
+ for (int i = 0; i < 4; i++) {
+ BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
+ }
+ }
+ else {
+ BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
+ }
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Multires Displacement Eraser Brush
+ * \{ */
+
+static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
+
+ float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ float limit_co[3];
+ float disp[3];
+ SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co);
+ sub_v3_v3v3(disp, limit_co, vd.co);
+ mul_v3_v3fl(proxy[vd.i], disp, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ BKE_curvemapping_init(brush->curve);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_displacement_eraser_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Multires Displacement Smear Brush
+ * \{ */
+
+static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ float current_disp[3];
+ float current_disp_norm[3];
+ float interp_limit_surface_disp[3];
+
+ copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]);
+
+ switch (brush->smear_deform_type) {
+ case BRUSH_SMEAR_DEFORM_DRAG:
+ sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location);
+ break;
+ case BRUSH_SMEAR_DEFORM_PINCH:
+ sub_v3_v3v3(current_disp, ss->cache->location, vd.co);
+ break;
+ case BRUSH_SMEAR_DEFORM_EXPAND:
+ sub_v3_v3v3(current_disp, vd.co, ss->cache->location);
+ break;
+ }
+
+ normalize_v3_v3(current_disp_norm, current_disp);
+ mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength);
+
+ float weights_accum = 1.0f;
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float vertex_disp[3];
+ float vertex_disp_norm[3];
+ float neighbor_limit_co[3];
+ SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co);
+ sub_v3_v3v3(vertex_disp,
+ ss->cache->limit_surface_co[ni.index],
+ ss->cache->limit_surface_co[vd.index]);
+ const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index];
+ normalize_v3_v3(vertex_disp_norm, vertex_disp);
+
+ if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) {
+ continue;
+ }
+
+ const float disp_interp = clamp_f(
+ -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f);
+ madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp);
+ weights_accum += disp_interp;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum);
+
+ float new_co[3];
+ add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp);
+ interp_v3_v3v3(vd.co, vd.co, new_co, fade);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_displacement_smear_store_prev_disp_task_cb_ex(
+ void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ sub_v3_v3v3(ss->cache->prev_displacement[vd.index],
+ SCULPT_vertex_co_get(ss, vd.index),
+ ss->cache->limit_surface_co[vd.index]);
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+
+ BKE_curvemapping_init(brush->curve);
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ if (!ss->cache->prev_displacement) {
+ ss->cache->prev_displacement = MEM_malloc_arrayN(
+ totvert, sizeof(float[3]), "prev displacement");
+ ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co");
+ for (int i = 0; i < totvert; i++) {
+ SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]);
+ sub_v3_v3v3(ss->cache->prev_displacement[i],
+ SCULPT_vertex_co_get(ss, i),
+ ss->cache->limit_surface_co[i]);
+ }
+ }
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(
+ 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Topology Rake (Shared Utility)
+ * \{ */
+
+static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+
+ float direction[3];
+ copy_v3_v3(direction, ss->cache->grab_delta_symmetry);
+
+ float tmp[3];
+ mul_v3_v3fl(
+ tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
+ sub_v3_v3(direction, tmp);
+ normalize_v3(direction);
+
+ /* Cancel if there's no grab data. */
+ if (is_zero_v3(direction)) {
+ return;
+ }
+
+ const float bstrength = clamp_f(data->strength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+ const float fade =
+ bstrength *
+ SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) *
+ ss->cache->pressure;
+
+ float avg[3], val[3];
+
+ SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
+
+ sub_v3_v3v3(val, avg, vd.co);
+
+ madd_v3_v3v3fl(val, vd.co, val, fade);
+
+ SCULPT_clip(sd, ss, vd.co, val);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_bmesh_topology_rake(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ const float strength = clamp_f(bstrength, 0.0f, 1.0f);
+
+ /* Interactions increase both strength and quality. */
+ const int iterations = 3;
+
+ int iteration;
+ const int count = iterations * strength + 1;
+ const float factor = iterations * strength / count;
+
+ for (iteration = 0; iteration <= count; iteration++) {
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .strength = factor,
+ };
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+
+ BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sculpt Mask Brush
+ * \{ */
+
+static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
+
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (!sculpt_brush_test_sq_fn(&test, vd.co)) {
+ continue;
+ }
+
+ const float fade = SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
+
+ if (bstrength > 0.0f) {
+ (*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
+ }
+ else {
+ (*vd.mask) += fade * bstrength * (*vd.mask);
+ }
+ *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+}
+
+void SCULPT_do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
+}
+
+void SCULPT_do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ switch ((BrushMaskTool)brush->mask_tool) {
+ case BRUSH_MASK_DRAW:
+ SCULPT_do_mask_brush_draw(sd, ob, nodes, totnode);
+ break;
+ case BRUSH_MASK_SMOOTH:
+ SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true);
+ break;
+ }
+}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
index 9082408b8dd..f00b24d690a 100644
--- a/source/blender/editors/sculpt_paint/sculpt_detail.c
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -248,8 +248,10 @@ static int sample_detail(bContext *C, int mx, int my, int mode)
{
/* Find 3D view to pick from. */
bScreen *screen = CTX_wm_screen(C);
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my);
- ARegion *region = (area) ? BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my) : NULL;
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, (const int[2]){mx, my});
+ ARegion *region = (area) ?
+ BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}) :
+ NULL;
if (region == NULL) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index 4dd2a786922..35ffb214185 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -29,13 +29,13 @@
#include "DNA_meshdata_types.h"
#include "DNA_vec_types.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
#include "BLI_bitmap.h"
+#include "BLI_compiler_compat.h"
#include "BLI_gsqueue.h"
#include "BLI_threads.h"
-#include "BKE_paint.h"
-#include "BKE_pbvh.h"
-
struct AutomaskingCache;
struct KeyBlock;
struct Object;
@@ -300,6 +300,10 @@ void SCULPT_calc_brush_plane(struct Sculpt *sd,
void SCULPT_calc_area_normal(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]);
+void SCULPT_calc_area_normal_and_center(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3]);
+void SCULPT_calc_area_center(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3]);
int SCULPT_nearest_vertex_get(struct Sculpt *sd,
struct Object *ob,
@@ -1025,6 +1029,7 @@ typedef struct StrokeCache {
float scale[3];
int flag;
float clip_tolerance[3];
+ float clip_mirror_mtx[4][4];
float initial_mouse[2];
/* Variants */
@@ -1506,3 +1511,115 @@ void SCULPT_OT_dyntopo_detail_size_edit(struct wmOperatorType *ot);
/* Dyntopo. */
void SCULPT_OT_dynamic_topology_toggle(struct wmOperatorType *ot);
+
+/* sculpt_brushes.c */
+
+float SCULPT_clay_thumb_get_stabilized_pressure(struct StrokeCache *cache);
+
+void SCULPT_do_draw_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_do_fill_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_scrape_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_clay_thumb_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_flatten_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_clay_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_clay_strips_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_snake_hook_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_thumb_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_rotate_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_layer_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_inflate_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_nudge_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_crease_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_pinch_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_grab_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_elastic_deform_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_draw_sharp_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_slide_relax_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_do_displacement_smear_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_displacement_eraser_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_mask_brush_draw(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+void SCULPT_do_mask_brush(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ int totnode);
+
+void SCULPT_bmesh_topology_rake(struct Sculpt *sd,
+ struct Object *ob,
+ struct PBVHNode **nodes,
+ const int totnode,
+ float bstrength);
+
+/* end sculpt_brushes.c */
+
+/* sculpt_ops.c */
+void SCULPT_OT_brush_stroke(struct wmOperatorType *ot);
+
+/* end sculpt_ops.c */
diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c
new file mode 100644
index 00000000000..119d246a770
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_ops.c
@@ -0,0 +1,1141 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ * Implements the Sculpt Mode tools
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_array.h"
+#include "BLI_blenlib.h"
+#include "BLI_dial_2d.h"
+#include "BLI_ghash.h"
+#include "BLI_gsqueue.h"
+#include "BLI_hash.h"
+#include "BLI_link_utils.h"
+#include "BLI_linklist.h"
+#include "BLI_linklist_stack.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_math_color_blend.h"
+#include "BLI_memarena.h"
+#include "BLI_rand.h"
+#include "BLI_task.h"
+#include "BLI_utildefines.h"
+#include "atomic_ops.h"
+
+#include "BLT_translation.h"
+
+#include "PIL_time.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_listBase.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_attribute.h"
+#include "BKE_brush.h"
+#include "BKE_ccg.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_kelvinlet.h"
+#include "BKE_key.h"
+#include "BKE_lib_id.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_fair.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_mesh_mirror.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_pbvh.h"
+#include "BKE_pointcache.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_subdiv_ccg.h"
+#include "BKE_subsurf.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "IMB_colormanagement.h"
+
+#include "GPU_batch.h"
+#include "GPU_batch_presets.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_space_api.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Reset the copy of the mesh that is being sculpted on (currently just for the layer brush). */
+
+static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ if (!ss) {
+ return OPERATOR_FINISHED;
+ }
+ SCULPT_vertex_random_access_ensure(ss);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
+
+ MEM_SAFE_FREE(ss->persistent_base);
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert,
+ "layer persistent base");
+
+ for (int i = 0; i < totvert; i++) {
+ copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i));
+ SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no);
+ ss->persistent_base[i].disp = 0.0f;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Set Persistent Base";
+ ot->idname = "SCULPT_OT_set_persistent_base";
+ ot->description = "Reset the copy of the mesh that is being sculpted on";
+
+ /* API callbacks. */
+ ot->exec = sculpt_set_persistent_base_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/************************* SCULPT_OT_optimize *************************/
+
+static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ SCULPT_pbvh_clear(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+/* The BVH gets less optimal more quickly with dynamic topology than
+ * regular sculpting. There is no doubt more clever stuff we can do to
+ * optimize it on the fly, but for now this gives the user a nicer way
+ * to recalculate it than toggling modes. */
+static void SCULPT_OT_optimize(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Rebuild BVH";
+ ot->idname = "SCULPT_OT_optimize";
+ ot->description = "Recalculate the sculpt BVH to improve performance";
+
+ /* API callbacks. */
+ ot->exec = sculpt_optimize_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/********************* Dynamic topology symmetrize ********************/
+
+static bool sculpt_no_multires_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if (SCULPT_mode_poll(C) && ob->sculpt && ob->sculpt->pbvh) {
+ return BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_GRIDS;
+ }
+ return false;
+}
+
+static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ SculptSession *ss = ob->sculpt;
+ PBVH *pbvh = ss->pbvh;
+ const float dist = RNA_float_get(op->ptr, "merge_tolerance");
+
+ if (!pbvh) {
+ return OPERATOR_CANCELLED;
+ }
+
+ switch (BKE_pbvh_type(pbvh)) {
+ case PBVH_BMESH:
+ /* Dyntopo Symmetrize. */
+
+ /* To simplify undo for symmetrize, all BMesh elements are logged
+ * as deleted, then after symmetrize operation all BMesh elements
+ * are logged as added (as opposed to attempting to store just the
+ * parts that symmetrize modifies). */
+ SCULPT_undo_push_begin(ob, "Dynamic topology symmetrize");
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE);
+ BM_log_before_all_removed(ss->bm, ss->bm_log);
+
+ BM_mesh_toolflags_set(ss->bm, true);
+
+ /* Symmetrize and re-triangulate. */
+ BMO_op_callf(ss->bm,
+ (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
+ "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b",
+ sd->symmetrize_direction,
+ dist,
+ true);
+ SCULPT_dynamic_topology_triangulate(ss->bm);
+
+ /* Bisect operator flags edges (keep tags clean for edge queue). */
+ BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
+
+ BM_mesh_toolflags_set(ss->bm, false);
+
+ /* Finish undo. */
+ BM_log_all_added(ss->bm, ss->bm_log);
+ SCULPT_undo_push_end();
+
+ break;
+ case PBVH_FACES:
+ /* Mesh Symmetrize. */
+ ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize");
+ Mesh *mesh = ob->data;
+
+ BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist);
+
+ ED_sculpt_undo_geometry_end(ob);
+ BKE_mesh_calc_normals(ob->data);
+ BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
+
+ break;
+ case PBVH_GRIDS:
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Redraw. */
+ SCULPT_pbvh_clear(ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_symmetrize(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Symmetrize";
+ ot->idname = "SCULPT_OT_symmetrize";
+ ot->description = "Symmetrize the topology modifications";
+
+ /* API callbacks. */
+ ot->exec = sculpt_symmetrize_exec;
+ ot->poll = sculpt_no_multires_poll;
+
+ RNA_def_float(ot->srna,
+ "merge_tolerance",
+ 0.001f,
+ 0.0f,
+ FLT_MAX,
+ "Merge Distance",
+ "Distance within which symmetrical vertices are merged",
+ 0.0f,
+ 1.0f);
+}
+
+/**** Toggle operator for turning sculpt mode on or off ****/
+
+static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+ /* Create persistent sculpt mode data. */
+ BKE_sculpt_toolsettings_data_ensure(scene);
+
+ /* Create sculpt mode session data. */
+ if (ob->sculpt != NULL) {
+ BKE_sculptsession_free(ob);
+ }
+ ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+ ob->sculpt->mode_type = OB_MODE_SCULPT;
+
+ BKE_sculpt_ensure_orig_mesh_data(scene, ob);
+
+ BKE_scene_graph_evaluated_ensure(depsgraph, bmain);
+
+ /* This function expects a fully evaluated depsgraph. */
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false);
+
+ /* Here we can detect geometry that was just added to Sculpt Mode as it has the
+ * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */
+ /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not
+ * initialized, which is used is some operators that modify the mesh topology to perform certain
+ * actions in the new polys. After these operations are finished, all polys should have a valid
+ * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility
+ * correctly. */
+ /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new
+ * objects, like moving the transform pivot position to the new area or masking existing
+ * geometry. */
+ SculptSession *ss = ob->sculpt;
+ const int new_face_set = SCULPT_face_set_next_available_get(ss);
+ for (int i = 0; i < ss->totfaces; i++) {
+ if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) {
+ ss->face_sets[i] = new_face_set;
+ }
+ }
+}
+
+void ED_object_sculptmode_enter_ex(Main *bmain,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ const bool force_dyntopo,
+ ReportList *reports)
+{
+ const int mode_flag = OB_MODE_SCULPT;
+ Mesh *me = BKE_mesh_from_object(ob);
+
+ /* Enter sculpt mode. */
+ ob->mode |= mode_flag;
+
+ sculpt_init_session(bmain, depsgraph, scene, ob);
+
+ if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f &&
+ fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) {
+ BKE_report(
+ reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable");
+ }
+ else if (is_negative_m4(ob->obmat)) {
+ BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable");
+ }
+
+ Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT);
+ BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT);
+
+ paint_cursor_start(paint, SCULPT_mode_poll_view3d);
+
+ /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
+ * As long as no data was added that is not supported. */
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+
+ const char *message_unsupported = NULL;
+ if (me->totloop != me->totpoly * 3) {
+ message_unsupported = TIP_("non-triangle face");
+ }
+ else if (mmd != NULL) {
+ message_unsupported = TIP_("multi-res modifier");
+ }
+ else {
+ enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob);
+ if (flag == 0) {
+ /* pass */
+ }
+ else if (flag & DYNTOPO_WARN_VDATA) {
+ message_unsupported = TIP_("vertex data");
+ }
+ else if (flag & DYNTOPO_WARN_EDATA) {
+ message_unsupported = TIP_("edge data");
+ }
+ else if (flag & DYNTOPO_WARN_LDATA) {
+ message_unsupported = TIP_("face data");
+ }
+ else if (flag & DYNTOPO_WARN_MODIFIER) {
+ message_unsupported = TIP_("constructive modifier");
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ if ((message_unsupported == NULL) || force_dyntopo) {
+ /* Needed because we may be entering this mode before the undo system loads. */
+ wmWindowManager *wm = bmain->wm.first;
+ bool has_undo = wm->undo_stack != NULL;
+ /* Undo push is needed to prevent memory leak. */
+ if (has_undo) {
+ SCULPT_undo_push_begin(ob, "Dynamic topology enable");
+ }
+ SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
+ if (has_undo) {
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
+ SCULPT_undo_push_end();
+ }
+ }
+ else {
+ BKE_reportf(
+ reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported);
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+ }
+ }
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+}
+
+void ED_object_sculptmode_enter(struct bContext *C, Depsgraph *depsgraph, ReportList *reports)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports);
+}
+
+void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+ const int mode_flag = OB_MODE_SCULPT;
+ Mesh *me = BKE_mesh_from_object(ob);
+
+ multires_flush_sculpt_updates(ob);
+
+ /* Not needed for now. */
+#if 0
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+ const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
+#endif
+
+ /* Always for now, so leaving sculpt mode always ensures scene is in
+ * a consistent state. */
+ if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+
+ if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
+ /* Dynamic topology must be disabled before exiting sculpt
+ * mode to ensure the undo stack stays in a consistent
+ * state. */
+ sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob);
+
+ /* Store so we know to re-enable when entering sculpt mode. */
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+ }
+
+ /* Leave sculpt mode. */
+ ob->mode &= ~mode_flag;
+
+ BKE_sculptsession_free(ob);
+
+ paint_cursor_delete_textures();
+
+ /* Never leave derived meshes behind. */
+ BKE_object_free_derived_caches(ob);
+
+ /* Flush object mode. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
+}
+
+void ED_object_sculptmode_exit(bContext *C, Depsgraph *depsgraph)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
+}
+
+static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
+{
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ const int mode_flag = OB_MODE_SCULPT;
+ const bool is_mode_set = (ob->mode & mode_flag) != 0;
+
+ if (!is_mode_set) {
+ if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (is_mode_set) {
+ ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob);
+ }
+ else {
+ if (depsgraph) {
+ depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ }
+ ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports);
+ BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint);
+
+ if (ob->mode & mode_flag) {
+ Mesh *me = ob->data;
+ /* Dyntopo adds its own undo step. */
+ if ((me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) {
+ /* Without this the memfile undo step is used,
+ * while it works it causes lag when undoing the first undo step, see T71564. */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (wm->op_undo_depth <= 1) {
+ SCULPT_undo_push_begin(ob, op->type->name);
+ }
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
+
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+
+ WM_toolsystem_update_from_context_view3d(C);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Sculpt Mode";
+ ot->idname = "SCULPT_OT_sculptmode_toggle";
+ ot->description = "Toggle sculpt mode in 3D view";
+
+ /* API callbacks. */
+ ot->exec = sculpt_mode_toggle_exec;
+ ot->poll = ED_operator_object_active_editable_mesh;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+
+ ss->preview_vert_index_count = 0;
+ int totpoints = 0;
+
+ /* This function is called from the cursor drawing code, so the PBVH may not be build yet. */
+ if (!ss->pbvh) {
+ return;
+ }
+
+ if (!ss->deform_modifiers_active) {
+ return;
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
+
+ if (!ss->pmap) {
+ return;
+ }
+
+ float brush_co[3];
+ copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss));
+
+ BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
+
+ /* Assuming an average of 6 edges per vertex in a triangulated mesh. */
+ const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2;
+
+ if (ss->preview_vert_index_list == NULL) {
+ ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
+ }
+
+ GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
+ int active_v = SCULPT_active_vertex_get(ss);
+ BLI_gsqueue_push(not_visited_vertices, &active_v);
+
+ while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
+ int from_v;
+ BLI_gsqueue_pop(not_visited_vertices, &from_v);
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
+ if (totpoints + (ni.size * 2) < max_preview_vertices) {
+ int to_v = ni.index;
+ ss->preview_vert_index_list[totpoints] = from_v;
+ totpoints++;
+ ss->preview_vert_index_list[totpoints] = to_v;
+ totpoints++;
+ if (BLI_BITMAP_TEST(visited_vertices, to_v)) {
+ continue;
+ }
+ BLI_BITMAP_ENABLE(visited_vertices, to_v);
+ const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v);
+ if (len_squared_v3v3(brush_co, co) < radius * radius) {
+ BLI_gsqueue_push(not_visited_vertices, &to_v);
+ }
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ }
+
+ BLI_gsqueue_free(not_visited_vertices);
+
+ MEM_freeN(visited_vertices);
+
+ ss->preview_vert_index_count = totpoints;
+}
+
+static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ ID *data;
+ data = ob->data;
+ if (data && ID_IS_LINKED(data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (ob->type != OB_MESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Mesh *mesh = ob->data;
+
+ const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
+ if (mloopcol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
+
+ const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
+ if (MPropCol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
+
+ MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
+ MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
+
+ for (int i = 0; i < mesh->totpoly; i++) {
+ MPoly *c_poly = &polys[i];
+ for (int j = 0; j < c_poly->totloop; j++) {
+ int loop_index = c_poly->loopstart + j;
+ MLoop *c_loop = &loops[c_poly->loopstart + j];
+ float srgb_color[4];
+ linearrgb_to_srgb_v4(srgb_color, vertcols[c_loop->v].color);
+ loopcols[loop_index].r = (char)(srgb_color[0] * 255);
+ loopcols[loop_index].g = (char)(srgb_color[1] * 255);
+ loopcols[loop_index].b = (char)(srgb_color[2] * 255);
+ loopcols[loop_index].a = (char)(srgb_color[3] * 255);
+ }
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Sculpt Vertex Color to Vertex Color";
+ ot->description = "Copy the Sculpt Vertex Color to a regular color layer";
+ ot->idname = "SCULPT_OT_vertex_to_loop_colors";
+
+ /* api callbacks */
+ ot->poll = SCULPT_vertex_colors_poll;
+ ot->exec = vertex_to_loop_colors_exec;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+
+ ID *data;
+ data = ob->data;
+ if (data && ID_IS_LINKED(data)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (ob->type != OB_MESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Mesh *mesh = ob->data;
+
+ const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL);
+ if (mloopcol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n);
+
+ const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR);
+ if (MPropCol_layer_n == -1) {
+ return OPERATOR_CANCELLED;
+ }
+ MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n);
+
+ MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP);
+ MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY);
+
+ for (int i = 0; i < mesh->totpoly; i++) {
+ MPoly *c_poly = &polys[i];
+ for (int j = 0; j < c_poly->totloop; j++) {
+ int loop_index = c_poly->loopstart + j;
+ MLoop *c_loop = &loops[c_poly->loopstart + j];
+ vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f);
+ vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f);
+ vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f);
+ vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f);
+ srgb_to_linearrgb_v4(vertcols[c_loop->v].color, vertcols[c_loop->v].color);
+ }
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Vertex Color to Sculpt Vertex Color";
+ ot->description = "Copy the active loop color layer to the vertex color";
+ ot->idname = "SCULPT_OT_loop_to_vertex_colors";
+
+ /* api callbacks */
+ ot->poll = SCULPT_vertex_colors_poll;
+ ot->exec = loop_to_vertex_colors_exec;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int sculpt_sample_color_invoke(bContext *C,
+ wmOperator *UNUSED(op),
+ const wmEvent *UNUSED(e))
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+ int active_vertex = SCULPT_active_vertex_get(ss);
+ const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex);
+ if (!active_vertex_color) {
+ return OPERATOR_CANCELLED;
+ }
+
+ float color_srgb[3];
+ copy_v3_v3(color_srgb, active_vertex_color);
+ IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb);
+ BKE_brush_color_set(scene, brush, color_srgb);
+
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_sample_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Sample Color";
+ ot->idname = "SCULPT_OT_sample_color";
+ ot->description = "Sample the vertex color of the active vertex";
+
+ /* api callbacks */
+ ot->invoke = sculpt_sample_color_invoke;
+ ot->poll = SCULPT_vertex_colors_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/**
+ * #sculpt_mask_by_color_delta_get returns values in the (0,1) range that are used to generate the
+ * mask based on the difference between two colors (the active color and the color of any other
+ * vertex). Ideally, a threshold of 0 should mask only the colors that are equal to the active
+ * color and threshold of 1 should mask all colors. In order to avoid artifacts and produce softer
+ * falloffs in the mask, the MASK_BY_COLOR_SLOPE defines the size of the transition values between
+ * masked and unmasked vertices. The smaller this value is, the sharper the generated mask is going
+ * to be.
+ */
+#define MASK_BY_COLOR_SLOPE 0.25f
+
+static float sculpt_mask_by_color_delta_get(const float *color_a,
+ const float *color_b,
+ const float threshold,
+ const bool invert)
+{
+ float len = len_v3v3(color_a, color_b);
+ /* Normalize len to the (0, 1) range. */
+ len = len / M_SQRT3;
+
+ if (len < threshold - MASK_BY_COLOR_SLOPE) {
+ len = 1.0f;
+ }
+ else if (len >= threshold) {
+ len = 0.0f;
+ }
+ else {
+ len = (-len + threshold) / MASK_BY_COLOR_SLOPE;
+ }
+
+ if (invert) {
+ return 1.0f - len;
+ }
+ return len;
+}
+
+static float sculpt_mask_by_color_final_mask_get(const float current_mask,
+ const float new_mask,
+ const bool invert,
+ const bool preserve_mask)
+{
+ if (preserve_mask) {
+ if (invert) {
+ return min_ff(current_mask, new_mask);
+ }
+ return max_ff(current_mask, new_mask);
+ }
+ return new_mask;
+}
+
+typedef struct MaskByColorContiguousFloodFillData {
+ float threshold;
+ bool invert;
+ float *new_mask;
+ float initial_color[3];
+} MaskByColorContiguousFloodFillData;
+
+static void do_mask_by_color_contiguous_update_nodes_cb(
+ void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
+ bool update_node = false;
+
+ const bool invert = data->mask_by_color_invert;
+ const bool preserve_mask = data->mask_by_color_preserve_mask;
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ const float current_mask = *vd.mask;
+ const float new_mask = data->mask_by_color_floodfill[vd.index];
+ *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
+ if (current_mask == *vd.mask) {
+ continue;
+ }
+ update_node = true;
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ if (update_node) {
+ BKE_pbvh_node_mark_redraw(data->nodes[n]);
+ }
+}
+
+static bool sculpt_mask_by_color_contiguous_floodfill_cb(
+ SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+{
+ MaskByColorContiguousFloodFillData *data = userdata;
+ const float *current_color = SCULPT_vertex_color_get(ss, to_v);
+ float new_vertex_mask = sculpt_mask_by_color_delta_get(
+ current_color, data->initial_color, data->threshold, data->invert);
+ data->new_mask[to_v] = new_vertex_mask;
+
+ if (is_duplicate) {
+ data->new_mask[to_v] = data->new_mask[from_v];
+ }
+
+ float len = len_v3v3(current_color, data->initial_color);
+ len = len / M_SQRT3;
+ return len <= data->threshold;
+}
+
+static void sculpt_mask_by_color_contiguous(Object *object,
+ const int vertex,
+ const float threshold,
+ const bool invert,
+ const bool preserve_mask)
+{
+ SculptSession *ss = object->sculpt;
+ const int totvert = SCULPT_vertex_count_get(ss);
+
+ float *new_mask = MEM_calloc_arrayN(totvert, sizeof(float), "new mask");
+
+ if (invert) {
+ for (int i = 0; i < totvert; i++) {
+ new_mask[i] = 1.0f;
+ }
+ }
+
+ SculptFloodFill flood;
+ SCULPT_floodfill_init(ss, &flood);
+ SCULPT_floodfill_add_initial(&flood, vertex);
+
+ MaskByColorContiguousFloodFillData ffd;
+ ffd.threshold = threshold;
+ ffd.invert = invert;
+ ffd.new_mask = new_mask;
+ copy_v3_v3(ffd.initial_color, SCULPT_vertex_color_get(ss, vertex));
+
+ SCULPT_floodfill_execute(ss, &flood, sculpt_mask_by_color_contiguous_floodfill_cb, &ffd);
+ SCULPT_floodfill_free(&flood);
+
+ int totnode;
+ PBVHNode **nodes;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ SculptThreadedTaskData data = {
+ .ob = object,
+ .nodes = nodes,
+ .mask_by_color_floodfill = new_mask,
+ .mask_by_color_vertex = vertex,
+ .mask_by_color_threshold = threshold,
+ .mask_by_color_invert = invert,
+ .mask_by_color_preserve_mask = preserve_mask,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(
+ 0, totnode, &data, do_mask_by_color_contiguous_update_nodes_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+
+ MEM_freeN(new_mask);
+}
+
+static void do_mask_by_color_task_cb(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+
+ SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK);
+ bool update_node = false;
+
+ const float threshold = data->mask_by_color_threshold;
+ const bool invert = data->mask_by_color_invert;
+ const bool preserve_mask = data->mask_by_color_preserve_mask;
+ const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
+ const float current_mask = *vd.mask;
+ const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert);
+ *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask);
+
+ if (current_mask == *vd.mask) {
+ continue;
+ }
+ update_node = true;
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ if (update_node) {
+ BKE_pbvh_node_mark_redraw(data->nodes[n]);
+ }
+}
+
+static void sculpt_mask_by_color_full_mesh(Object *object,
+ const int vertex,
+ const float threshold,
+ const bool invert,
+ const bool preserve_mask)
+{
+ SculptSession *ss = object->sculpt;
+
+ int totnode;
+ PBVHNode **nodes;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ SculptThreadedTaskData data = {
+ .ob = object,
+ .nodes = nodes,
+ .mask_by_color_vertex = vertex,
+ .mask_by_color_threshold = threshold,
+ .mask_by_color_invert = invert,
+ .mask_by_color_preserve_mask = preserve_mask,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
+ BLI_task_parallel_range(0, totnode, &data, do_mask_by_color_task_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+}
+
+static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false);
+
+ /* Color data is not available in Multires. */
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!ss->vcol) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SCULPT_vertex_random_access_ensure(ss);
+
+ /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move,
+ * so it needs to be updated here. */
+ SculptCursorGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+
+ SCULPT_undo_push_begin(ob, "Mask by color");
+
+ const int active_vertex = SCULPT_active_vertex_get(ss);
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+ const bool invert = RNA_boolean_get(op->ptr, "invert");
+ const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask");
+
+ if (RNA_boolean_get(op->ptr, "contiguous")) {
+ sculpt_mask_by_color_contiguous(ob, active_vertex, threshold, invert, preserve_mask);
+ }
+ else {
+ sculpt_mask_by_color_full_mesh(ob, active_vertex, threshold, invert, preserve_mask);
+ }
+
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
+ SCULPT_undo_push_end();
+
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCULPT_OT_mask_by_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Mask by Color";
+ ot->idname = "SCULPT_OT_mask_by_color";
+ ot->description = "Creates a mask based on the sculpt vertex colors";
+
+ /* api callbacks */
+ ot->invoke = sculpt_mask_by_color_invoke;
+ ot->poll = SCULPT_vertex_colors_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ ot->prop = RNA_def_boolean(
+ ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas");
+
+ ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask");
+ ot->prop = RNA_def_boolean(
+ ot->srna,
+ "preserve_previous_mask",
+ false,
+ "Preserve Previous Mask",
+ "Preserve the previous mask and add or subtract the new one generated by the colors");
+
+ RNA_def_float(ot->srna,
+ "threshold",
+ 0.35f,
+ 0.0f,
+ 1.0f,
+ "Threshold",
+ "How much changes in color affect the mask generation",
+ 0.0f,
+ 1.0f);
+}
+
+void ED_operatortypes_sculpt(void)
+{
+ WM_operatortype_append(SCULPT_OT_brush_stroke);
+ WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
+ WM_operatortype_append(SCULPT_OT_set_persistent_base);
+ WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle);
+ WM_operatortype_append(SCULPT_OT_optimize);
+ WM_operatortype_append(SCULPT_OT_symmetrize);
+ WM_operatortype_append(SCULPT_OT_detail_flood_fill);
+ WM_operatortype_append(SCULPT_OT_sample_detail_size);
+ WM_operatortype_append(SCULPT_OT_set_detail_size);
+ WM_operatortype_append(SCULPT_OT_mesh_filter);
+ WM_operatortype_append(SCULPT_OT_mask_filter);
+ WM_operatortype_append(SCULPT_OT_dirty_mask);
+ WM_operatortype_append(SCULPT_OT_mask_expand);
+ WM_operatortype_append(SCULPT_OT_set_pivot_position);
+ WM_operatortype_append(SCULPT_OT_face_sets_create);
+ WM_operatortype_append(SCULPT_OT_face_sets_change_visibility);
+ WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors);
+ WM_operatortype_append(SCULPT_OT_face_sets_init);
+ WM_operatortype_append(SCULPT_OT_cloth_filter);
+ WM_operatortype_append(SCULPT_OT_face_sets_edit);
+ WM_operatortype_append(SCULPT_OT_face_set_lasso_gesture);
+ WM_operatortype_append(SCULPT_OT_face_set_box_gesture);
+ WM_operatortype_append(SCULPT_OT_trim_box_gesture);
+ WM_operatortype_append(SCULPT_OT_trim_lasso_gesture);
+ WM_operatortype_append(SCULPT_OT_project_line_gesture);
+
+ WM_operatortype_append(SCULPT_OT_sample_color);
+ WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors);
+ WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors);
+ WM_operatortype_append(SCULPT_OT_color_filter);
+ WM_operatortype_append(SCULPT_OT_mask_by_color);
+ WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit);
+ WM_operatortype_append(SCULPT_OT_mask_init);
+
+ WM_operatortype_append(SCULPT_OT_expand);
+}
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 91083fa9682..847cba32c69 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -1079,6 +1079,9 @@ static void graph_region_draw(const bContext *C, ARegion *region)
/* time-scrubbing */
ED_time_scrub_draw(region, scene, sc->flag & SC_SHOW_SECONDS, true);
+ /* current frame indicator */
+ ED_time_scrub_draw_current_frame(region, scene, sc->flag & SC_SHOW_SECONDS);
+
/* scrollers */
UI_view2d_scrollers_draw(v2d, NULL);
@@ -1126,6 +1129,9 @@ static void dopesheet_region_draw(const bContext *C, ARegion *region)
/* time-scrubbing */
ED_time_scrub_draw(region, scene, sc->flag & SC_SHOW_SECONDS, true);
+ /* current frame indicator */
+ ED_time_scrub_draw_current_frame(region, scene, sc->flag & SC_SHOW_SECONDS);
+
/* scrollers */
UI_view2d_scrollers_draw(v2d, NULL);
}
diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc
index 86c4b78dea4..f6c449a0584 100644
--- a/source/blender/editors/space_file/asset_catalog_tree_view.cc
+++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc
@@ -679,7 +679,7 @@ using namespace blender::ed::asset_browser;
FileAssetCatalogFilterSettingsHandle *file_create_asset_catalog_filter_settings()
{
- AssetCatalogFilterSettings *filter_settings = OBJECT_GUARDED_NEW(AssetCatalogFilterSettings);
+ AssetCatalogFilterSettings *filter_settings = MEM_new<AssetCatalogFilterSettings>(__func__);
return reinterpret_cast<FileAssetCatalogFilterSettingsHandle *>(filter_settings);
}
@@ -688,7 +688,8 @@ void file_delete_asset_catalog_filter_settings(
{
AssetCatalogFilterSettings **filter_settings = reinterpret_cast<AssetCatalogFilterSettings **>(
filter_settings_handle);
- OBJECT_GUARDED_SAFE_DELETE(*filter_settings, AssetCatalogFilterSettings);
+ MEM_delete(*filter_settings);
+ *filter_settings = nullptr;
}
bool file_set_asset_catalog_filter_settings(
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 8178e54e023..a1472a2c1b3 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -2624,7 +2624,8 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
matches = file_select_match(sfile, params->file, matched_file);
/* *After* file_select_match! */
- BLI_filename_make_safe(params->file);
+ const bool allow_tokens = (params->flag & FILE_PATH_TOKENS_ALLOW) != 0;
+ BLI_filename_make_safe_ex(params->file, allow_tokens);
if (matches) {
/* replace the pattern (or filename that the user typed in,
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index e3ac5840da3..f9783d1b19f 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -275,6 +275,9 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile)
if ((prop = RNA_struct_find_property(op->ptr, "filter_usd"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_USD : 0;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "filter_obj"))) {
+ params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_OBJECT_IO : 0;
+ }
if ((prop = RNA_struct_find_property(op->ptr, "filter_volume"))) {
params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_VOLUME : 0;
}
@@ -318,6 +321,10 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile)
params->flag |= RNA_boolean_get(op->ptr, "active_collection") ? FILE_ACTIVE_COLLECTION : 0;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "allow_path_tokens"))) {
+ params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_PATH_TOKENS_ALLOW : 0;
+ }
+
if ((prop = RNA_struct_find_property(op->ptr, "display_type"))) {
params->display = RNA_property_enum_get(op->ptr, prop);
}
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index 4db1eb5214e..286580b5629 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -126,6 +126,8 @@ void GRAPH_OT_paste(struct wmOperatorType *ot);
void GRAPH_OT_duplicate(struct wmOperatorType *ot);
void GRAPH_OT_delete(struct wmOperatorType *ot);
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_sample(struct wmOperatorType *ot);
void GRAPH_OT_bake(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index ecafc75fc06..fe4cffcb3b8 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -470,6 +470,8 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_smooth);
WM_operatortype_append(GRAPH_OT_clean);
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_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 0bb5e8b8d9c..733313dd06b 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -313,8 +313,7 @@ static int graph_slider_invoke(bContext *C, wmOperator *op, const wmEvent *event
ED_slider_init(gso->slider, event);
if (gso->bezt_arr_list.first == NULL) {
- WM_report(RPT_WARNING,
- "Fcurve Slider: Can't work on baked channels. Unbake them and try again.");
+ WM_report(RPT_ERROR, "Cannot find keys to operate on.");
graph_slider_exit(C, op);
return OPERATOR_CANCELLED;
}
@@ -552,3 +551,256 @@ void GRAPH_OT_decimate(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Blend To Neighbor Operator
+ * \{ */
+
+static void blend_to_neighbor_graph_keys(bAnimContext *ac, float factor)
+{
+ ListBase anim_data = {NULL, NULL};
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
+
+ bAnimListElem *ale;
+
+ /* Loop through filtered data and blend keys. */
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ ListBase segments = find_fcurve_segments(fcu);
+ LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
+ blend_to_neighbor_fcurve_segment(fcu, segment, factor);
+ }
+ BLI_freelistN(&segments);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
+static void blend_to_neighbor_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 Neighbor"));
+
+ 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_neighbor_modal_update(bContext *C, wmOperator *op)
+{
+ tGraphSliderOp *gso = op->customdata;
+
+ blend_to_neighbor_draw_status_header(C, gso);
+
+ /* Reset keyframe data to the state at invoke. */
+ reset_bezts(gso);
+
+ const float factor = ED_slider_factor_get(gso->slider);
+ RNA_property_float_set(op->ptr, gso->factor_prop, factor);
+ blend_to_neighbor_graph_keys(&gso->ac, factor);
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+}
+
+static int blend_to_neighbor_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_neighbor_modal_update;
+ gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
+ blend_to_neighbor_draw_status_header(C, gso);
+
+ return invoke_result;
+}
+
+static int blend_to_neighbor_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_neighbor_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_neighbor(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Blend To Neighbor";
+ ot->idname = "GRAPH_OT_blend_to_neighbor";
+ ot->description = "Blend selected keyframes to their left or right neighbor";
+
+ /* API callbacks. */
+ ot->invoke = blend_to_neighbor_invoke;
+ ot->modal = graph_slider_modal;
+ ot->exec = blend_to_neighbor_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,
+ "Blend",
+ "The blend factor with 0.5 being the current frame",
+ 0.0f,
+ 1.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Breakdown Operator
+ * \{ */
+
+static void breakdown_graph_keys(bAnimContext *ac, float factor)
+{
+ ListBase anim_data = {NULL, NULL};
+ ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype);
+
+ bAnimListElem *ale;
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ FCurve *fcu = (FCurve *)ale->key_data;
+ ListBase segments = find_fcurve_segments(fcu);
+ LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
+ breakdown_fcurve_segment(fcu, segment, factor);
+ }
+ BLI_freelistN(&segments);
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
+static void breakdown_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_("Breakdown"));
+
+ 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 breakdown_modal_update(bContext *C, wmOperator *op)
+{
+ tGraphSliderOp *gso = op->customdata;
+
+ breakdown_draw_status_header(C, gso);
+
+ /* Reset keyframe data to the state at invoke. */
+ reset_bezts(gso);
+ breakdown_graph_keys(&gso->ac, ED_slider_factor_get(gso->slider));
+ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+}
+
+static int breakdown_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 = breakdown_modal_update;
+ breakdown_draw_status_header(C, gso);
+
+ return invoke_result;
+}
+
+static int breakdown_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");
+
+ breakdown_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_breakdown(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Breakdown";
+ ot->idname = "GRAPH_OT_breakdown";
+ ot->description = "Move selected keyframes to an inbetween position relative to adjacent keys";
+
+ /* API callbacks. */
+ ot->invoke = breakdown_invoke;
+ ot->modal = graph_slider_modal;
+ ot->exec = breakdown_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",
+ "Favor either the left or the right key",
+ 0.0f,
+ 1.0f);
+}
+
+/** \} */
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index f9160774c41..23d07c9b45b 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1499,6 +1499,13 @@ static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
}
}
+static void image_operator_prop_allow_tokens(wmOperatorType *ot)
+{
+ PropertyRNA *prop = RNA_def_boolean(
+ ot->srna, "allow_path_tokens", true, "", "Allow the path to contain substitution tokens");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+}
+
void IMAGE_OT_open(wmOperatorType *ot)
{
/* identifiers */
@@ -1516,6 +1523,7 @@ void IMAGE_OT_open(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
+ image_operator_prop_allow_tokens(ot);
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
@@ -1767,7 +1775,13 @@ static int image_save_options_init(Main *bmain,
opts->im_format.views_format = ima->views_format;
}
- BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath));
+ 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));
+ }
+ else {
+ BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath));
+ }
/* sanitize all settings */
@@ -1804,14 +1818,10 @@ static int image_save_options_init(Main *bmain,
BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
}
- /* append UDIM numbering if not present */
- if (ima->source == IMA_SRC_TILED) {
- char udim[6];
- ImageTile *tile = ima->tiles.first;
- BLI_snprintf(udim, sizeof(udim), ".%d", tile->tile_number);
-
+ /* append UDIM marker if not present */
+ if (ima->source == IMA_SRC_TILED && strstr(opts->filepath, "<UDIM>") == NULL) {
int len = strlen(opts->filepath);
- STR_CONCAT(opts->filepath, len, udim);
+ STR_CONCAT(opts->filepath, len, ".<UDIM>");
}
}
@@ -2070,6 +2080,7 @@ void IMAGE_OT_save_as(wmOperatorType *ot)
"Copy",
"Create a new image file without modifying the current image in blender");
+ image_operator_prop_allow_tokens(ot);
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
@@ -2584,6 +2595,11 @@ static int image_new_exec(bContext *C, wmOperator *op)
else if (sima) {
ED_space_image_set(bmain, sima, ima, false);
}
+ else {
+ /* #BKE_image_add_generated creates one user by default, remove it if image is not linked to
+ * anything. ref. T94599. */
+ id_us_min(&ima->id);
+ }
BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE);
diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c
index 87bff913ff2..84b85b396fe 100644
--- a/source/blender/editors/space_image/image_sequence.c
+++ b/source/blender/editors/space_image/image_sequence.c
@@ -115,79 +115,17 @@ static int image_cmp_frame(const void *a, const void *b)
return 0;
}
-/*
- * Checks whether the given filepath refers to a UDIM texture.
- * If yes, the range from 1001 to the highest tile is returned, otherwise 0.
- *
- * If the result is positive, the filepath will be overwritten with that of
- * the 1001 tile.
- *
- * udim_tiles may get filled even if the result ultimately is false!
- */
-static bool image_get_udim(char *filepath, ListBase *udim_tiles, int *udim_start, int *udim_range)
-{
- char filename[FILE_MAX], dirname[FILE_MAXDIR];
- BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
-
- ushort digits;
- char base_head[FILE_MAX], base_tail[FILE_MAX];
- int id = BLI_path_sequence_decode(filename, base_head, base_tail, &digits);
-
- if (id < 1001 || id > IMA_UDIM_MAX) {
- return false;
- }
-
- bool is_udim = true;
- int min_udim = IMA_UDIM_MAX + 1;
- int max_udim = 0;
-
- struct direntry *dir;
- uint totfile = BLI_filelist_dir_contents(dirname, &dir);
- for (int i = 0; i < totfile; i++) {
- if (!(dir[i].type & S_IFREG)) {
- continue;
- }
- char head[FILE_MAX], tail[FILE_MAX];
- id = BLI_path_sequence_decode(dir[i].relname, head, tail, &digits);
-
- if (digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) ||
- !(STREQLEN(base_tail, tail, FILE_MAX))) {
- continue;
- }
-
- if (id < 1001 || id > IMA_UDIM_MAX) {
- is_udim = false;
- break;
- }
-
- BLI_addtail(udim_tiles, BLI_genericNodeN(POINTER_FROM_INT(id)));
- min_udim = min_ii(min_udim, id);
- max_udim = max_ii(max_udim, id);
- }
- BLI_filelist_free(dir, totfile);
-
- if (is_udim && min_udim <= IMA_UDIM_MAX) {
- char primary_filename[FILE_MAX];
- BLI_path_sequence_encode(primary_filename, base_head, base_tail, digits, min_udim);
- BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename);
-
- *udim_start = min_udim;
- *udim_range = max_udim - min_udim + 1;
- return true;
- }
- return false;
-}
-
/**
* From a list of frames, compute the start (offset) and length of the sequence
- * of contiguous frames. If UDIM is detect, it will return UDIM tiles as well.
+ * of contiguous frames. If `detect_udim` is set, it will return UDIM tiles as well.
*/
static void image_detect_frame_range(ImageFrameRange *range, const bool detect_udim)
{
/* UDIM */
if (detect_udim) {
int udim_start, udim_range;
- bool result = image_get_udim(range->filepath, &range->udim_tiles, &udim_start, &udim_range);
+ bool result = BKE_image_get_tile_info(
+ range->filepath, &range->udim_tiles, &udim_start, &udim_range);
if (result) {
range->offset = udim_start;
diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc
index bcf26743030..005ae0214cd 100644
--- a/source/blender/editors/space_info/info_stats.cc
+++ b/source/blender/editors/space_info/info_stats.cc
@@ -43,6 +43,7 @@
#include "BLT_translation.h"
+#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_blender_version.h"
#include "BKE_context.h"
@@ -351,7 +352,7 @@ static void stats_object_pose(const Object *ob, SceneStats *stats)
LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
stats->totbone++;
if (pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
- if (pchan->bone->layer & arm->layer) {
+ if (BKE_pose_is_layer_visible(arm, pchan)) {
stats->totbonesel++;
}
}
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index bbfd886ce56..5bb5320655b 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -36,6 +36,7 @@
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_scene.h"
#include "BKE_tracking.h"
@@ -135,24 +136,11 @@ static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA
static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
-#if 0
- /* XXX no context access here. */
- bNode *node = (bNode*)ptr->data;
- CurveMapping *cumap = node->storage;
-
- if (cumap) {
- cumap->flag |= CUMA_DRAW_CFRA;
- if (node->custom1 < node->custom2) {
- cumap->sample[0] = (float)(CFRA - node->custom1) / (float)(node->custom2 - node->custom1);
- }
- }
-#endif
-
uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false);
- uiLayout *row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Start"), ICON_NONE);
- uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE);
+ uiLayout *col = uiLayoutColumn(layout, true);
+ uiItemR(col, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Start"), ICON_NONE);
+ uiItemR(col, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE);
}
static void node_buts_colorramp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1558,7 +1546,8 @@ static void node_property_update_default(Main *bmain, Scene *UNUSED(scene), Poin
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
static void node_socket_template_properties_update(bNodeType *ntype, bNodeSocketTemplate *stemp)
@@ -1652,12 +1641,6 @@ void ED_node_init_butfuncs()
node_template_properties_update(ntype);
}
NODE_TYPES_END;
-
- /* tree type icons */
- ntreeType_Composite->ui_icon = ICON_NODE_COMPOSITING;
- ntreeType_Shader->ui_icon = ICON_NODE_MATERIAL;
- ntreeType_Texture->ui_icon = ICON_NODE_TEXTURE;
- ntreeType_Geometry->ui_icon = ICON_NODETREE;
}
void ED_init_custom_node_type(bNodeType *UNUSED(ntype))
diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc
index e1ba36e81c0..45126e9cee0 100644
--- a/source/blender/editors/space_node/link_drag_search.cc
+++ b/source/blender/editors/space_node/link_drag_search.cc
@@ -29,6 +29,8 @@
#include "WM_api.h"
+#include "ED_node.h"
+
#include "node_intern.hh"
using blender::nodes::SocketLinkOperation;
@@ -77,7 +79,7 @@ static void add_group_input_node_fn(nodes::LinkSearchOpParams &params)
bNode &group_input = params.add_node("NodeGroupInput");
/* This is necessary to create the new sockets in the other input nodes. */
- ntreeUpdateTree(CTX_data_main(&params.C), &params.node_tree);
+ ED_node_tree_propagate_change(&params.C, CTX_data_main(&params.C), &params.node_tree);
/* Hide the new input in all other group input nodes, to avoid making them taller. */
LISTBASE_FOREACH (bNode *, node, &params.node_tree.nodes) {
@@ -103,6 +105,26 @@ static void add_group_input_node_fn(nodes::LinkSearchOpParams &params)
nodeAddLink(&params.node_tree, &group_input, socket, &params.node, &params.socket);
}
+static void add_existing_group_input_fn(nodes::LinkSearchOpParams &params,
+ const bNodeSocket &interface_socket)
+{
+ const int group_input_index = BLI_findindex(&params.node_tree.inputs, &interface_socket);
+ bNode &group_input = params.add_node("NodeGroupInput");
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &group_input.outputs) {
+ socket->flag |= SOCK_HIDDEN;
+ }
+
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&group_input.outputs, group_input_index);
+ if (socket == nullptr) {
+ /* Adding sockets can fail in some cases. There's no good reason not to be safe here. */
+ return;
+ }
+
+ socket->flag &= ~SOCK_HIDDEN;
+ nodeAddLink(&params.node_tree, &group_input, socket, &params.node, &params.socket);
+}
+
/**
* Call the callback to gather compatible socket connections for all node types, and the operations
* that will actually make the connections. Also add some custom operations like connecting a group
@@ -134,6 +156,22 @@ static void gather_socket_link_operations(bNodeTree &node_tree,
if (is_node_group && socket.in_out == SOCK_IN) {
search_link_ops.append({IFACE_("Group Input"), add_group_input_node_fn});
+
+ int weight = -1;
+ LISTBASE_FOREACH (const bNodeSocket *, interface_socket, &node_tree.inputs) {
+ eNodeSocketDatatype from = (eNodeSocketDatatype)interface_socket->type;
+ eNodeSocketDatatype to = (eNodeSocketDatatype)socket.type;
+ if (node_tree.typeinfo->validate_link && !node_tree.typeinfo->validate_link(from, to)) {
+ continue;
+ }
+ search_link_ops.append(
+ {std::string(IFACE_("Group Input ")) + UI_MENU_ARROW_SEP + interface_socket->name,
+ [interface_socket](nodes::LinkSearchOpParams &params) {
+ add_existing_group_input_fn(params, *interface_socket);
+ },
+ weight});
+ weight--;
+ }
}
}
@@ -203,9 +241,7 @@ static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2)
/* Ideally it would be possible to tag the node tree in some way so it updates only after the
* translate operation is finished, but normally moving nodes around doesn't cause updates. */
- ntreeUpdateTree(&bmain, snode.edittree);
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, &bmain, snode.edittree);
/* Start translation operator with the new node. */
wmOperatorType *ot = WM_operatortype_find("TRANSFORM_OT_translate", true);
@@ -288,4 +324,4 @@ void invoke_node_link_drag_add_menu(bContext &C,
UI_popup_block_invoke_ex(&C, create_search_popup_block, storage, nullptr, false);
}
-} // namespace blender::ed::space_node \ No newline at end of file
+} // namespace blender::ed::space_node
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index c6a5e8e68c0..0aa9cd5511a 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -36,6 +36,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
@@ -83,15 +84,8 @@ bNode *node_add_node(const bContext &C, const char *idname, int type, float locx
nodeSetSelected(node, true);
- ntreeUpdateTree(&bmain, snode.edittree);
ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr);
-
- snode_update(snode, node);
-
- if (snode.nodetree->type == NTREE_TEXTURE) {
- ntreeTexCheckCyclics(snode.edittree);
- }
-
+ ED_node_tree_propagate_change(&C, &bmain, snode.edittree);
return node;
}
@@ -136,7 +130,7 @@ static bNodeSocketLink *add_reroute_insert_socket_link(ListBase *lb,
{
bNodeSocketLink *socklink, *prev;
- socklink = (bNodeSocketLink *)MEM_callocN(sizeof(bNodeSocketLink), "socket link");
+ socklink = MEM_cnew<bNodeSocketLink>("socket link");
socklink->sock = sock;
socklink->link = link;
copy_v2_v2(socklink->point, point);
@@ -281,10 +275,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op)
BLI_freelistN(&input_links);
/* always last */
- ntreeUpdateTree(CTX_data_main(C), &ntree);
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
-
+ ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree);
return OPERATOR_FINISHED;
}
@@ -383,14 +374,10 @@ static int node_add_group_exec(bContext *C, wmOperator *op)
group_node->id = &node_group->id;
id_us_plus(group_node->id);
+ BKE_ntree_update_tag_node_property(snode->edittree, group_node);
nodeSetActive(ntree, group_node);
- ntreeUpdateTree(bmain, node_group);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
-
+ ED_node_tree_propagate_change(C, bmain, nullptr);
return OPERATOR_FINISHED;
}
@@ -479,12 +466,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op)
id_us_plus(&object->id);
nodeSetActive(ntree, object_node);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
-
- ED_node_tag_update_nodetree(bmain, ntree, object_node);
+ ED_node_tree_propagate_change(C, bmain, ntree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
@@ -587,14 +569,9 @@ static int node_add_texture_exec(bContext *C, wmOperator *op)
id_us_plus(&texture->id);
nodeSetActive(ntree, texture_node);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, ntree);
DEG_relations_tag_update(bmain);
- ED_node_tag_update_nodetree(bmain, ntree, texture_node);
-
return OPERATOR_FINISHED;
}
@@ -701,14 +678,9 @@ static int node_add_collection_exec(bContext *C, wmOperator *op)
id_us_plus(&collection->id);
nodeSetActive(ntree, collection_node);
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, bmain, ntree);
DEG_relations_tag_update(bmain);
- ED_node_tag_update_nodetree(bmain, ntree, collection_node);
-
return OPERATOR_FINISHED;
}
@@ -834,8 +806,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
}
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, bmain, snode.edittree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
@@ -937,8 +908,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op)
node->id = mask;
id_us_plus(mask);
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, bmain, snode.edittree);
DEG_relations_tag_update(bmain);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index d68f16f6197..2d3c42b16d1 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -176,35 +176,6 @@ void ED_node_tag_update_id(ID *id)
}
}
-void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree, bNode *node)
-{
- if (!ntree) {
- return;
- }
-
- bool do_tag_update = true;
- if (node != nullptr) {
- if (!node_connected_to_output(*bmain, *ntree, *node)) {
- do_tag_update = false;
- }
- }
-
- /* Look through all datablocks to support groups. */
- if (do_tag_update) {
- FOREACH_NODETREE_BEGIN (bmain, tntree, id) {
- /* Check if nodetree uses the group. */
- if (ntreeHasTree(tntree, ntree)) {
- ED_node_tag_update_id(id);
- }
- }
- FOREACH_NODETREE_END;
- }
-
- if (ntree->type == NTREE_TEXTURE) {
- ntreeTexCheckCyclics(ntree);
- }
-}
-
static bool compare_nodes(const bNode *a, const bNode *b)
{
/* These tell if either the node or any of the parent nodes is selected.
@@ -365,6 +336,10 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
PointerRNA nodeptr;
RNA_pointer_create(&ntree.id, &RNA_Node, &node, &nodeptr);
+ const bool node_options = node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS);
+ const bool inputs_first = node.inputs.first &&
+ !(node.outputs.first || (node.flag & NODE_PREVIEW) || node_options);
+
/* Get "global" coordinates. */
float2 loc = node_to_view(node, float2(0));
/* Round the node origin because text contents are always pixel-aligned. */
@@ -377,7 +352,7 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
dy -= NODE_DY;
/* Add a little bit of padding above the top socket. */
- if (node.outputs.first || node.inputs.first) {
+ if (node.outputs.first || inputs_first) {
dy -= NODE_DYS / 2;
}
@@ -478,7 +453,7 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node,
}
/* Buttons rect? */
- if (node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS)) {
+ if (node_options) {
dy -= NODE_DYS / 2;
uiLayout *layout = UI_block_layout(&block,
@@ -2405,7 +2380,6 @@ static void node_update_nodetree(const bContext &C,
{
/* Make sure socket "used" tags are correct, for displaying value buttons. */
SpaceNode *snode = CTX_wm_space_node(&C);
- ntreeTagUsedSockets(&ntree);
count_multi_input_socket_links(ntree, *snode);
@@ -2414,9 +2388,11 @@ static void node_update_nodetree(const bContext &C,
bNode &node = *nodes[i];
uiBlock &block = *blocks[i];
if (node.type == NODE_FRAME) {
- frame_node_prepare_for_draw(node, nodes);
+ /* Frame sizes are calculated after all other nodes have calculating their #totr. */
+ continue;
}
- else if (node.type == NODE_REROUTE) {
+
+ if (node.type == NODE_REROUTE) {
reroute_node_prepare_for_draw(node);
}
else {
@@ -2428,6 +2404,13 @@ static void node_update_nodetree(const bContext &C,
}
}
}
+
+ /* Now calculate the size of frame nodes, which can depend on the size of other nodes. */
+ for (const int i : nodes.index_range()) {
+ if (nodes[i]->type == NODE_FRAME) {
+ frame_node_prepare_for_draw(*nodes[i], nodes);
+ }
+ }
}
static void frame_node_draw_label(const bNodeTree &ntree,
diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc
index fb90e2bfe50..e83bfb43847 100644
--- a/source/blender/editors/space_node/node_edit.cc
+++ b/source/blender/editors/space_node/node_edit.cc
@@ -38,6 +38,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_workspace.h"
@@ -78,6 +79,7 @@
#define USE_ESC_COMPO
using blender::float2;
+using blender::Map;
/* ***************** composite job manager ********************** */
@@ -342,7 +344,7 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
"Compositing",
WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS,
WM_JOB_TYPE_COMPOSITE);
- CompoJob *cj = (CompoJob *)MEM_callocN(sizeof(CompoJob), "compo job");
+ CompoJob *cj = MEM_cnew<CompoJob>("compo job");
/* customdata for preview thread */
cj->bmain = bmain;
@@ -383,31 +385,11 @@ bool composite_node_editable(bContext *C)
return false;
}
-void snode_dag_update(bContext &C, SpaceNode &snode)
+static void send_notifiers_after_tree_change(ID *id, bNodeTree *ntree)
{
- Main *bmain = CTX_data_main(&C);
+ WM_main_add_notifier(NC_NODE | NA_EDITED, nullptr);
- /* for groups, update all ID's using this */
- if ((snode.edittree->id.flag & LIB_EMBEDDED_DATA) == 0) {
- FOREACH_NODETREE_BEGIN (bmain, tntree, id) {
- if (ntreeHasTree(tntree, snode.edittree)) {
- DEG_id_tag_update(id, 0);
- }
- }
- FOREACH_NODETREE_END;
- }
-
- DEG_id_tag_update(snode.id, 0);
- DEG_id_tag_update(&snode.nodetree->id, 0);
-}
-
-void snode_notify(bContext &C, SpaceNode &snode)
-{
- ID *id = snode.id;
-
- WM_event_add_notifier(&C, NC_NODE | NA_EDITED, nullptr);
-
- if (ED_node_is_shader(&snode)) {
+ if (ntree->type == NTREE_SHADER) {
if (GS(id->name) == ID_MA) {
WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
}
@@ -418,17 +400,38 @@ void snode_notify(bContext &C, SpaceNode &snode)
WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
}
}
- else if (ED_node_is_compositor(&snode)) {
- WM_event_add_notifier(&C, NC_SCENE | ND_NODES, id);
+ else if (ntree->type == NTREE_COMPOSIT) {
+ WM_main_add_notifier(NC_SCENE | ND_NODES, id);
}
- else if (ED_node_is_texture(&snode)) {
- WM_event_add_notifier(&C, NC_TEXTURE | ND_NODES, id);
+ else if (ntree->type == NTREE_TEXTURE) {
+ WM_main_add_notifier(NC_TEXTURE | ND_NODES, id);
}
- else if (ED_node_is_geometry(&snode)) {
+ else if (ntree->type == NTREE_GEOMETRY) {
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id);
}
}
+void ED_node_tree_propagate_change(const bContext *C, Main *bmain, bNodeTree *root_ntree)
+{
+ if (C != nullptr) {
+ SpaceNode *snode = CTX_wm_space_node(C);
+ if (snode != nullptr && root_ntree != nullptr) {
+ send_notifiers_after_tree_change(snode->id, root_ntree);
+ }
+ }
+
+ NodeTreeUpdateExtraParams params = {nullptr};
+ params.tree_changed_fn = [](ID *id, bNodeTree *ntree, void *UNUSED(user_data)) {
+ send_notifiers_after_tree_change(id, ntree);
+ DEG_id_tag_update(&ntree->id, ID_RECALC_COPY_ON_WRITE);
+ };
+ params.tree_output_changed_fn = [](ID *UNUSED(id), bNodeTree *ntree, void *UNUSED(user_data)) {
+ DEG_id_tag_update(&ntree->id, ID_RECALC_NTREE_OUTPUT);
+ };
+
+ BKE_ntree_update_main_tree(bmain, root_ntree, &params);
+}
+
void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo)
{
if (typeinfo) {
@@ -477,7 +480,7 @@ void ED_node_shader_default(const bContext *C, ID *id)
}
ma->nodetree = ntreeCopyTree(bmain, ma_default->nodetree);
- ntreeUpdateTree(bmain, ma->nodetree);
+ BKE_ntree_update_main_tree(bmain, ma->nodetree, nullptr);
}
else if (ELEM(GS(id->name), ID_WO, ID_LA)) {
/* Emission */
@@ -517,7 +520,7 @@ void ED_node_shader_default(const bContext *C, ID *id)
output->locx = 300.0f;
output->locy = 300.0f;
nodeSetActive(ntree, output);
- ntreeUpdateTree(bmain, ntree);
+ BKE_ntree_update_main_tree(bmain, ntree, nullptr);
}
else {
printf("ED_node_shader_default called on wrong ID type.\n");
@@ -555,7 +558,7 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce)
bNodeSocket *tosock = (bNodeSocket *)out->inputs.first;
nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
- ntreeUpdateTree(CTX_data_main(C), sce->nodetree);
+ BKE_ntree_update_main_tree(CTX_data_main(C), sce->nodetree, nullptr);
}
void ED_node_texture_default(const bContext *C, Tex *tex)
@@ -583,7 +586,7 @@ void ED_node_texture_default(const bContext *C, Tex *tex)
bNodeSocket *tosock = (bNodeSocket *)out->inputs.first;
nodeAddLink(tex->nodetree, in, fromsock, out, tosock);
- ntreeUpdateTree(CTX_data_main(C), tex->nodetree);
+ BKE_ntree_update_main_tree(CTX_data_main(C), tex->nodetree, nullptr);
}
/**
@@ -628,28 +631,6 @@ void snode_set_context(const bContext &C)
}
}
-void snode_update(SpaceNode &snode, bNode *node)
-{
- /* XXX this only updates nodes in the current node space tree path.
- * The function supposedly should update any potential group node linking to changed tree,
- * this really requires a working depsgraph ...
- */
-
- /* update all edited group nodes */
- bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last;
- if (path) {
- bNodeTree *ngroup = path->nodetree;
- for (path = path->prev; path; path = path->prev) {
- nodeUpdateID(path->nodetree, (ID *)ngroup);
- ngroup = path->nodetree;
- }
- }
-
- if (node) {
- nodeUpdate(snode.edittree, node);
- }
-}
-
void ED_node_set_active(
Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
{
@@ -697,14 +678,10 @@ void ED_node_set_active(
}
node->flag |= NODE_DO_OUTPUT;
- if (was_output == 0) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
- }
- }
- else if (do_update) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
}
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
+
if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
/* If active texture changed, free glsl materials. */
LISTBASE_FOREACH (Material *, ma, &bmain->materials) {
@@ -750,7 +727,7 @@ void ED_node_set_active(
if (r_active_texture_changed) {
*r_active_texture_changed = true;
}
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
WM_main_add_notifier(NC_IMAGE, nullptr);
}
@@ -767,7 +744,7 @@ void ED_node_set_active(
node->flag |= NODE_DO_OUTPUT;
if (was_output == 0) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/* Adding a node doesn't link this yet. */
@@ -782,11 +759,11 @@ void ED_node_set_active(
}
node->flag |= NODE_DO_OUTPUT;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
}
else if (do_update) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
}
else if (ntree->type == NTREE_TEXTURE) {
@@ -931,7 +908,7 @@ static void node_resize_init(bContext *C,
{
SpaceNode *snode = CTX_wm_space_node(C);
- NodeSizeWidget *nsw = (NodeSizeWidget *)MEM_callocN(sizeof(NodeSizeWidget), __func__);
+ NodeSizeWidget *nsw = MEM_cnew<NodeSizeWidget>(__func__);
op->customdata = nsw;
nsw->mxstart = snode->runtime->cursor[0] * UI_DPI_FAC;
@@ -1274,7 +1251,8 @@ bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link)
/* ****************** Duplicate *********************** */
-static void node_duplicate_reparent_recursive(bNode *node)
+static void node_duplicate_reparent_recursive(const Map<const bNode *, bNode *> &node_map,
+ bNode *node)
{
bNode *parent;
@@ -1284,15 +1262,15 @@ static void node_duplicate_reparent_recursive(bNode *node)
for (parent = node->parent; parent; parent = parent->parent) {
if (parent->flag & SELECT) {
if (!(parent->flag & NODE_TEST)) {
- node_duplicate_reparent_recursive(parent);
+ node_duplicate_reparent_recursive(node_map, parent);
}
break;
}
}
/* reparent node copy to parent copy */
if (parent) {
- nodeDetachNode(node->new_node);
- nodeAttachNode(node->new_node, parent->new_node);
+ nodeDetachNode(node_map.lookup(node));
+ nodeAttachNode(node_map.lookup(node), node_map.lookup(parent));
}
}
@@ -1302,17 +1280,18 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = snode->edittree;
const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
- bool do_tag_update = false;
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
bNode *lastnode = (bNode *)ntree->nodes.last;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & SELECT) {
- BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT);
-
- /* To ensure redraws or re-renders happen. */
- ED_node_tag_update_id(snode->id);
+ bNode *new_node = blender::bke::node_copy_with_mapping(
+ ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
+ node_map.add_new(node, new_node);
}
/* make sure we don't copy new nodes again! */
@@ -1321,8 +1300,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
}
}
- /* Copy links between selected nodes.
- * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */
+ /* Copy links between selected nodes. */
bNodeLink *lastlink = (bNodeLink *)ntree->links.last;
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
/* This creates new links between copied nodes.
@@ -1330,13 +1308,13 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
*/
if (link->tonode && (link->tonode->flag & NODE_SELECT) &&
(keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT)))) {
- bNodeLink *newlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "bNodeLink");
+ bNodeLink *newlink = MEM_cnew<bNodeLink>("bNodeLink");
newlink->flag = link->flag;
- newlink->tonode = link->tonode->new_node;
- newlink->tosock = link->tosock->new_sock;
+ newlink->tonode = node_map.lookup(link->tonode);
+ newlink->tosock = socket_map.lookup(link->tosock);
if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) {
- newlink->fromnode = link->fromnode->new_node;
- newlink->fromsock = link->fromsock->new_sock;
+ newlink->fromnode = node_map.lookup(link->fromnode);
+ newlink->fromsock = socket_map.lookup(link->fromsock);
}
else {
/* input node not copied, this keeps the original input linked */
@@ -1360,7 +1338,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
/* reparent copied nodes */
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if ((node->flag & SELECT) && !(node->flag & NODE_TEST)) {
- node_duplicate_reparent_recursive(node);
+ node_duplicate_reparent_recursive(node_map, node);
}
/* only has to check old nodes */
@@ -1373,13 +1351,11 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & SELECT) {
/* has been set during copy above */
- bNode *newnode = node->new_node;
+ bNode *newnode = node_map.lookup(node);
nodeSetSelected(node, false);
node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE);
nodeSetSelected(newnode, true);
-
- do_tag_update |= (do_tag_update || node_connected_to_output(*bmain, *ntree, *newnode));
}
/* make sure we don't copy new nodes again! */
@@ -1388,13 +1364,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(*C, *snode);
- if (do_tag_update) {
- snode_dag_update(*C, *snode);
- }
-
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1485,8 +1455,7 @@ static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1653,7 +1622,7 @@ static int node_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op))
node_flag_toggle_exec(snode, NODE_PREVIEW);
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1732,7 +1701,7 @@ static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -1760,23 +1729,17 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
- bool do_tag_update = false;
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
if ((node->flag & SELECT) && !node->typeinfo->no_muting) {
node->flag ^= NODE_MUTED;
- snode_update(*snode, node);
- do_tag_update |= (do_tag_update ||
- node_connected_to_output(*bmain, *snode->edittree, *node));
+ BKE_ntree_update_tag_node_mute(snode->edittree, node);
}
}
- snode_notify(*C, *snode);
- if (do_tag_update) {
- snode_dag_update(*C, *snode);
- }
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1802,24 +1765,16 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
- bool do_tag_update = false;
ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) {
if (node->flag & SELECT) {
- do_tag_update |= (do_tag_update ||
- node_connected_to_output(*bmain, *snode->edittree, *node));
nodeRemoveNode(bmain, snode->edittree, node, true);
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(*C, *snode);
- if (do_tag_update) {
- snode_dag_update(*C, *snode);
- }
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1863,10 +1818,7 @@ static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1901,10 +1853,7 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), snode->edittree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
return OPERATOR_FINISHED;
}
@@ -1951,7 +1900,7 @@ static int node_output_file_add_socket_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "file_path", file_path);
ntreeCompositOutputFileAddSocket(ntree, node, file_path, &scene->r.im_format);
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -2000,7 +1949,7 @@ static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *U
return OPERATOR_CANCELLED;
}
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
return OPERATOR_FINISHED;
}
@@ -2067,7 +2016,7 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op)
nimf->active_input++;
}
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
return OPERATOR_FINISHED;
}
@@ -2153,47 +2102,48 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op))
BKE_node_clipboard_clear();
BKE_node_clipboard_init(ntree);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & SELECT) {
/* No ID refcounting, this node is virtual,
* detached from any actual Blender data currently. */
- bNode *new_node = BKE_node_copy_store_new_pointers(
- nullptr, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN);
- BKE_node_clipboard_add_node(new_node);
+ bNode *new_node = blender::bke::node_copy_with_mapping(nullptr,
+ *node,
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_MAIN,
+ false,
+ socket_map);
+ node_map.add_new(node, new_node);
}
}
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- if (node->flag & SELECT) {
- bNode *new_node = node->new_node;
-
- /* ensure valid pointers */
- if (new_node->parent) {
- /* parent pointer must be redirected to new node or detached if parent is
- * not copied */
- if (new_node->parent->flag & NODE_SELECT) {
- new_node->parent = new_node->parent->new_node;
- }
- else {
- nodeDetachNode(new_node);
- }
+ for (bNode *new_node : node_map.values()) {
+ BKE_node_clipboard_add_node(new_node);
+
+ /* Parent pointer must be redirected to new node or detached if parent is not copied. */
+ if (new_node->parent) {
+ if (node_map.contains(new_node->parent)) {
+ new_node->parent = node_map.lookup(new_node->parent);
+ }
+ else {
+ nodeDetachNode(new_node);
}
}
}
- /* Copy links between selected nodes.
- * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */
-
+ /* Copy links between selected nodes. */
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
- /* This creates new links between copied nodes. */
- if (link->tonode && (link->tonode->flag & NODE_SELECT) && link->fromnode &&
- (link->fromnode->flag & NODE_SELECT)) {
- bNodeLink *newlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "bNodeLink");
+ BLI_assert(link->tonode);
+ BLI_assert(link->fromnode);
+ if (link->tonode->flag & NODE_SELECT && link->fromnode->flag & NODE_SELECT) {
+ bNodeLink *newlink = MEM_cnew<bNodeLink>(__func__);
newlink->flag = link->flag;
- newlink->tonode = link->tonode->new_node;
- newlink->tosock = link->tosock->new_sock;
- newlink->fromnode = link->fromnode->new_node;
- newlink->fromsock = link->fromsock->new_sock;
+ newlink->tonode = node_map.lookup(link->tonode);
+ newlink->tosock = socket_map.lookup(link->tosock);
+ newlink->fromnode = node_map.lookup(link->fromnode);
+ newlink->fromsock = socket_map.lookup(link->fromsock);
BKE_node_clipboard_add_link(newlink);
}
@@ -2288,35 +2238,38 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
}
mul_v2_fl(center, 1.0 / num_nodes);
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
/* copy nodes from clipboard */
LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) {
- bNode *new_node = BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT);
+ bNode *new_node = blender::bke::node_copy_with_mapping(
+ ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
+ node_map.add_new(node, new_node);
+ }
+ for (bNode *new_node : node_map.values()) {
/* pasted nodes are selected */
nodeSetSelected(new_node, true);
- }
- /* reparent copied nodes */
- LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) {
- bNode *new_node = node->new_node;
+ /* The parent pointer must be redirected to new node. */
if (new_node->parent) {
- new_node->parent = new_node->parent->new_node;
+ if (node_map.contains(new_node->parent)) {
+ new_node->parent = node_map.lookup(new_node->parent);
+ }
}
}
LISTBASE_FOREACH (bNodeLink *, link, clipboard_links_lb) {
nodeAddLink(ntree,
- link->fromnode->new_node,
- link->fromsock->new_sock,
- link->tonode->new_node,
- link->tosock->new_sock);
+ node_map.lookup(link->fromnode),
+ socket_map.lookup(link->fromsock),
+ node_map.lookup(link->tonode),
+ socket_map.lookup(link->tosock));
}
Main *bmain = CTX_data_main(C);
- ntreeUpdateTree(bmain, snode->edittree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, snode->edittree);
/* Pasting nodes can create arbitrary new relations, because nodes can reference IDs. */
DEG_relations_tag_update(bmain);
@@ -2384,10 +2337,7 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op)
/* make the new socket active */
sock->flag |= SELECT;
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2434,10 +2384,7 @@ static int ntree_socket_remove_exec(bContext *C, wmOperator *op)
active_sock->flag |= SELECT;
}
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2488,7 +2435,7 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op)
/* Need the extra update here because the loop above does not check for valid links in the node
* group we're currently editing. */
- ntree->update |= NTREE_UPDATE_GROUP | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_interface(ntree);
/* Deactivate sockets. */
LISTBASE_FOREACH (bNodeSocket *, socket_iter, sockets) {
@@ -2497,10 +2444,7 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op)
/* Make the new socket active. */
iosock->flag |= SELECT;
- ntreeUpdateTree(main, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, main, ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2611,11 +2555,8 @@ static int ntree_socket_move_exec(bContext *C, wmOperator *op)
}
}
- ntree->update |= NTREE_UPDATE_GROUP;
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ BKE_ntree_update_tag_interface(ntree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
@@ -2846,7 +2787,7 @@ static int viewer_border_exec(bContext *C, wmOperator *op)
btree->flag |= NTREE_VIEWER_BORDER;
}
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, btree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
}
else {
@@ -2886,7 +2827,7 @@ static int clear_viewer_border_exec(bContext *C, wmOperator *UNUSED(op))
bNodeTree *btree = snode->nodetree;
btree->flag &= ~NTREE_VIEWER_BORDER;
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), btree);
WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr);
return OPERATOR_FINISHED;
@@ -2931,7 +2872,7 @@ static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op))
ntreeCompositCryptomatteAddSocket(ntree, node);
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
return OPERATOR_FINISHED;
}
@@ -2977,7 +2918,7 @@ static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(o
return OPERATOR_CANCELLED;
}
- snode_notify(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc
index 4890c3e39cf..6f96e08d749 100644
--- a/source/blender/editors/space_node/node_geometry_attribute_search.cc
+++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc
@@ -125,8 +125,8 @@ void node_geometry_add_attribute_search_button(const bContext &UNUSED(C),
0.0f,
"");
- AttributeSearchData *data = OBJECT_GUARDED_NEW(
- AttributeSearchData, {&node_tree, &node, (bNodeSocket *)socket_ptr.data});
+ AttributeSearchData *data = MEM_new<AttributeSearchData>(
+ __func__, AttributeSearchData{&node_tree, &node, (bNodeSocket *)socket_ptr.data});
UI_but_func_search_set_results_are_suggestions(but, true);
UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP);
diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc
index 704ffe1e478..f6802e64049 100644
--- a/source/blender/editors/space_node/node_group.cc
+++ b/source/blender/editors/space_node/node_group.cc
@@ -32,6 +32,7 @@
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
+#include "BLI_vector.hh"
#include "BLT_translation.h"
@@ -40,6 +41,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "DEG_depsgraph_build.h"
@@ -61,6 +63,8 @@
#include "node_intern.hh" /* own include */
using blender::float2;
+using blender::Map;
+using blender::Vector;
/* -------------------------------------------------------------------- */
/** \name Local Utilities
@@ -216,24 +220,21 @@ static void animation_basepath_change_free(AnimationBasePathChange *basepath_cha
MEM_freeN(basepath_change);
}
-/* returns 1 if its OK */
-static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
+/**
+ * \return True if successful.
+ */
+static bool node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
{
- /* Clear new pointers, set in #ntreeCopyTree_ex_new_pointers. */
- LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
- node->new_node = nullptr;
- }
-
ListBase anim_basepaths = {nullptr, nullptr};
- LinkNode *nodes_delayed_free = nullptr;
- bNodeTree *ngroup = (bNodeTree *)gnode->id;
+ Vector<bNode *> nodes_delayed_free;
+ const bNodeTree *ngroup = reinterpret_cast<const bNodeTree *>(gnode->id);
/* wgroup is a temporary copy of the NodeTree we're merging in
* - all of wgroup's nodes are copied across to their new home
* - ngroup (i.e. the source NodeTree) is left unscathed
* - temp copy. do change ID usercount for the copies
*/
- bNodeTree *wgroup = ntreeCopyTree_ex_new_pointers(ngroup, bmain, true);
+ bNodeTree *wgroup = ntreeCopyTree(bmain, ngroup);
/* Add the nodes into the ntree */
LISTBASE_FOREACH_MUTABLE (bNode *, node, &wgroup->nodes) {
@@ -242,7 +243,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
*/
if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
/* We must delay removal since sockets will reference this node. see: T52092 */
- BLI_linklist_prepend(&nodes_delayed_free, node);
+ nodes_delayed_free.append(node);
}
/* keep track of this node's RNA "base" path (the part of the path identifying the node)
@@ -258,6 +259,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
/* migrate node */
BLI_remlink(&wgroup->nodes, node);
BLI_addtail(&ntree->nodes, node);
+ BKE_ntree_update_tag_node_new(ntree, node);
/* ensure unique node name in the node tree */
nodeUniqueName(ntree, node);
@@ -284,6 +286,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &wgroup->links) {
BLI_remlink(&wgroup->links, link);
BLI_addtail(&ntree->links, link);
+ BKE_ntree_update_tag_link_added(ntree, link);
}
bNodeLink *glinks_last = (bNodeLink *)ntree->links.last;
@@ -385,17 +388,14 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
}
}
- while (nodes_delayed_free) {
- bNode *node = (bNode *)BLI_linklist_pop(&nodes_delayed_free);
+ for (bNode *node : nodes_delayed_free) {
nodeRemoveNode(bmain, ntree, node, false);
}
/* delete the group instance and dereference group tree */
nodeRemoveNode(bmain, ntree, gnode, true);
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
-
- return 1;
+ return true;
}
static int node_group_ungroup_exec(bContext *C, wmOperator *op)
@@ -412,16 +412,13 @@ static int node_group_ungroup_exec(bContext *C, wmOperator *op)
}
if (gnode->id && node_group_ungroup(bmain, snode->edittree, gnode)) {
- ntreeUpdateTree(bmain, snode->nodetree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), nullptr);
}
else {
BKE_report(op->reports, RPT_WARNING, "Cannot ungroup");
return OPERATOR_CANCELLED;
}
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
-
return OPERATOR_FINISHED;
}
@@ -457,13 +454,11 @@ static bool node_group_separate_selected(
nodeSetSelected(node, false);
}
- /* clear new pointers, set in BKE_node_copy_ex(). */
- LISTBASE_FOREACH (bNode *, node, &ngroup.nodes) {
- node->new_node = nullptr;
- }
-
ListBase anim_basepaths = {nullptr, nullptr};
+ Map<const bNode *, bNode *> node_map;
+ Map<const bNodeSocket *, bNodeSocket *> socket_map;
+
/* add selected nodes into the ntree */
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup.nodes) {
if (!(node->flag & NODE_SELECT)) {
@@ -479,7 +474,9 @@ static bool node_group_separate_selected(
bNode *newnode;
if (make_copy) {
/* make a copy */
- newnode = BKE_node_copy_store_new_pointers(&ngroup, node, LIB_ID_COPY_DEFAULT);
+ newnode = blender::bke::node_copy_with_mapping(
+ &ngroup, *node, LIB_ID_COPY_DEFAULT, true, socket_map);
+ node_map.add_new(node, newnode);
}
else {
/* use the existing node */
@@ -528,10 +525,10 @@ static bool node_group_separate_selected(
/* make a copy of internal links */
if (fromselect && toselect) {
nodeAddLink(&ntree,
- link->fromnode->new_node,
- link->fromsock->new_sock,
- link->tonode->new_node,
- link->tosock->new_sock);
+ node_map.lookup(link->fromnode),
+ socket_map.lookup(link->fromsock),
+ node_map.lookup(link->tonode),
+ socket_map.lookup(link->tosock));
}
}
else {
@@ -558,9 +555,9 @@ static bool node_group_separate_selected(
}
}
- ntree.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_all(&ntree);
if (!make_copy) {
- ngroup.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_all(&ngroup);
}
return true;
@@ -614,10 +611,7 @@ static int node_group_separate_exec(bContext *C, wmOperator *op)
/* switch to parent tree */
ED_node_tree_pop(snode);
- ntreeUpdateTree(CTX_data_main(C), snode->nodetree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), nullptr);
return OPERATOR_FINISHED;
}
@@ -812,6 +806,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
/* change node-collection membership */
BLI_remlink(&ntree.nodes, node);
BLI_addtail(&ngroup->nodes, node);
+ BKE_ntree_update_tag_node_removed(&ntree);
+ BKE_ntree_update_tag_node_new(ngroup, node);
/* ensure unique node name in the ngroup */
nodeUniqueName(ngroup, node);
@@ -983,11 +979,6 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree,
}
}
}
-
- /* update of the group tree */
- ngroup->update |= NTREE_UPDATE | NTREE_UPDATE_LINKS;
- /* update of the tree containing the group instance node */
- ntree.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
}
static bNode *node_group_make_from_selected(const bContext &C,
@@ -1016,9 +1007,6 @@ static bNode *node_group_make_from_selected(const bContext &C,
node_group_make_insert_selected(C, ntree, gnode);
- /* update of the tree containing the group instance node */
- ntree.update |= NTREE_UPDATE_NODES;
-
return gnode;
}
@@ -1047,14 +1035,10 @@ static int node_group_make_exec(bContext *C, wmOperator *op)
LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
sort_multi_input_socket_links(snode, *node, nullptr, nullptr);
}
- ntreeUpdateTree(bmain, ngroup);
}
}
- ntreeUpdateTree(bmain, &ntree);
-
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, bmain, nullptr);
/* We broke relations in node tree, need to rebuild them in the graphs. */
DEG_relations_tag_update(bmain);
@@ -1107,12 +1091,7 @@ static int node_group_insert_exec(bContext *C, wmOperator *op)
nodeSetActive(ntree, gnode);
ED_node_tree_push(snode, ngroup, gnode);
- ntreeUpdateTree(bmain, ngroup);
-
- ntreeUpdateTree(bmain, ntree);
-
- snode_notify(*C, *snode);
- snode_dag_update(*C, *snode);
+ ED_node_tree_propagate_change(C, bmain, nullptr);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh
index 2e55bb0cb28..52dde965114 100644
--- a/source/blender/editors/space_node/node_intern.hh
+++ b/source/blender/editors/space_node/node_intern.hh
@@ -235,7 +235,6 @@ void sort_multi_input_socket_links(SpaceNode &snode,
bNode &node,
bNodeLink *drag_link,
const blender::float2 *cursor);
-bool node_connected_to_output(Main &bmain, bNodeTree &ntree, bNode &node);
void NODE_OT_link(wmOperatorType *ot);
void NODE_OT_link_make(wmOperatorType *ot);
@@ -252,12 +251,8 @@ void NODE_OT_link_viewer(wmOperatorType *ot);
void NODE_OT_insert_offset(wmOperatorType *ot);
-void snode_notify(bContext &C, SpaceNode &snode);
-void snode_dag_update(bContext &C, SpaceNode &snode);
void snode_set_context(const bContext &C);
-void snode_update(SpaceNode &snode, bNode *node);
-/** Operator poll callback. */
bool composite_node_active(bContext *C);
/** Operator poll callback. */
bool composite_node_editable(bContext *C);
diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc
index 90b53258d5e..4055dfdbf9e 100644
--- a/source/blender/editors/space_node/node_relationships.cc
+++ b/source/blender/editors/space_node/node_relationships.cc
@@ -34,6 +34,7 @@
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_screen.h"
#include "ED_node.h" /* own include */
@@ -73,121 +74,6 @@ using blender::StringRefNull;
using blender::Vector;
/* -------------------------------------------------------------------- */
-/** \name Relations Helpers
- * \{ */
-
-static bool ntree_has_drivers(bNodeTree &ntree)
-{
- const AnimData *adt = BKE_animdata_from_id(&ntree.id);
- if (adt == nullptr) {
- return false;
- }
- return !BLI_listbase_is_empty(&adt->drivers);
-}
-
-static bool ntree_check_nodes_connected_dfs(bNodeTree &ntree, bNode &from, bNode &to)
-{
- if (from.flag & NODE_TEST) {
- return false;
- }
- from.flag |= NODE_TEST;
- LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
- if (link->fromnode == &from) {
- if (link->tonode == &to) {
- return true;
- }
-
- if (ntree_check_nodes_connected_dfs(ntree, *link->tonode, to)) {
- return true;
- }
- }
- }
- return false;
-}
-
-static bool ntree_check_nodes_connected(bNodeTree &ntree, bNode &from, bNode &to)
-{
- if (&from == &to) {
- return true;
- }
- ntreeNodeFlagSet(&ntree, NODE_TEST, false);
- return ntree_check_nodes_connected_dfs(ntree, from, to);
-}
-
-static bool node_group_has_output_dfs(bNode &node)
-{
- bNodeTree *ntree = (bNodeTree *)node.id;
- if (ntree->id.tag & LIB_TAG_DOIT) {
- return false;
- }
- ntree->id.tag |= LIB_TAG_DOIT;
- LISTBASE_FOREACH (bNode *, current_node, &ntree->nodes) {
- if (current_node->type == NODE_GROUP) {
- if (current_node->id && node_group_has_output_dfs(*current_node)) {
- return true;
- }
- }
- if (current_node->flag & NODE_DO_OUTPUT && current_node->type != NODE_GROUP_OUTPUT) {
- return true;
- }
- }
- return false;
-}
-
-static bool node_group_has_output(Main &bmain, bNode &node)
-{
- BLI_assert(ELEM(node.type, NODE_GROUP, NODE_CUSTOM_GROUP));
- bNodeTree *ntree = (bNodeTree *)node.id;
- if (ntree == nullptr) {
- return false;
- }
- BKE_main_id_tag_listbase(&bmain.nodetrees, LIB_TAG_DOIT, false);
- return node_group_has_output_dfs(node);
-}
-
-bool node_connected_to_output(Main &bmain, bNodeTree &ntree, bNode &node)
-{
- /* Special case for drivers: if node tree has any drivers we assume it is
- * always to be tagged for update when node changes. Otherwise we will be
- * doomed to do some deep and nasty deep search of indirect dependencies,
- * which will be too complicated without real benefit.
- */
- if (ntree_has_drivers(ntree)) {
- return true;
- }
- LISTBASE_FOREACH (bNode *, current_node, &ntree.nodes) {
- /* Special case for group nodes -- if modified node connected to a group
- * with active output inside we consider refresh is needed.
- *
- * We could make check more grained here by taking which socket the node
- * is connected to and so eventually.
- */
- if (ELEM(current_node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
- if (current_node->id != nullptr && ntree_has_drivers((bNodeTree &)current_node->id)) {
- return true;
- }
- if (ntree_check_nodes_connected(ntree, node, *current_node) &&
- node_group_has_output(bmain, *current_node)) {
- return true;
- }
- }
- if (current_node->flag & NODE_DO_OUTPUT) {
- if (ntree_check_nodes_connected(ntree, node, *current_node)) {
- return true;
- }
- }
- if (current_node->type == GEO_NODE_VIEWER) {
- if (ntree_check_nodes_connected(ntree, node, *current_node)) {
- return true;
- }
- }
- }
- return false;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Add Node
* \{ */
@@ -214,9 +100,9 @@ static void clear_picking_highlight(ListBase *links)
}
}
-static bNodeLink *create_drag_link(Main &bmain, SpaceNode &snode, bNode &node, bNodeSocket &sock)
+static bNodeLink *create_drag_link(bNode &node, bNodeSocket &sock)
{
- bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), __func__);
+ bNodeLink *oplink = MEM_cnew<bNodeLink>(__func__);
if (sock.in_out == SOCK_OUT) {
oplink->fromnode = &node;
oplink->fromsock = &sock;
@@ -226,27 +112,17 @@ static bNodeLink *create_drag_link(Main &bmain, SpaceNode &snode, bNode &node, b
oplink->tosock = &sock;
}
oplink->flag |= NODE_LINK_VALID;
- oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, *snode.edittree, node)) {
- oplink->flag |= NODE_LINK_TEST;
- }
oplink->flag |= NODE_LINK_DRAGGED;
return oplink;
}
-static void pick_link(const bContext &C,
- wmOperator &op,
- bNodeLinkDrag &nldrag,
- SpaceNode &snode,
- bNode *node,
- bNodeLink &link_to_pick)
+static void pick_link(
+ wmOperator &op, bNodeLinkDrag &nldrag, SpaceNode &snode, bNode *node, bNodeLink &link_to_pick)
{
clear_picking_highlight(&snode.edittree->links);
RNA_boolean_set(op.ptr, "has_link_picked", true);
- Main *bmain = CTX_data_main(&C);
- bNodeLink *link = create_drag_link(
- *bmain, snode, *link_to_pick.fromnode, *link_to_pick.fromsock);
+ bNodeLink *link = create_drag_link(*link_to_pick.fromnode, *link_to_pick.fromsock);
nldrag.links.append(link);
nodeRemLink(snode.edittree, &link_to_pick);
@@ -258,7 +134,7 @@ static void pick_link(const bContext &C,
/* Send changed event to original link->tonode. */
if (node) {
- snode_update(snode, node);
+ BKE_ntree_update_tag_node_property(snode.edittree, node);
}
}
@@ -324,7 +200,7 @@ static void pick_input_link_by_link_intersect(const bContext &C,
ED_area_tag_redraw(CTX_wm_area(&C));
if (!node_find_indicated_socket(*snode, &node, &socket, cursor, SOCK_IN)) {
- pick_link(C, op, nldrag, *snode, node, *link_to_pick);
+ pick_link(op, nldrag, *snode, node, *link_to_pick);
}
}
}
@@ -566,7 +442,7 @@ static void snode_autoconnect(Main &bmain,
}
if (numlinks > 0) {
- ntreeUpdateTree(&bmain, ntree);
+ BKE_ntree_update_main_tree(&bmain, ntree, nullptr);
}
}
@@ -640,7 +516,7 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree,
(eNodeSocketDatatype)src_socket.type);
BLI_assert(data_type != CD_AUTO_FROM_NAME);
storage->data_type = data_type;
- nodeUpdate(&ntree, &viewer_node);
+ viewer_node.typeinfo->updatefunc(&ntree, &viewer_node);
return viewer_socket;
}
}
@@ -810,7 +686,7 @@ static int link_socket_to_viewer(const bContext &C,
else {
link_to_change->fromnode = &bnode_to_view;
link_to_change->fromsock = &bsocket_to_view;
- btree.update |= NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_link_changed(&btree);
}
remove_links_to_unavailable_viewer_sockets(btree, *viewer_bnode);
@@ -819,10 +695,7 @@ static int link_socket_to_viewer(const bContext &C,
ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(&C), &snode, viewer_bnode);
}
- ntreeUpdateTree(CTX_data_main(&C), &btree);
- snode_update(snode, viewer_bnode);
- DEG_id_tag_update(&btree.id, 0);
-
+ ED_node_tree_propagate_change(&C, CTX_data_main(&C), &btree);
return OPERATOR_FINISHED;
}
@@ -863,7 +736,7 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- snode_notify(*C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
return OPERATOR_FINISHED;
}
@@ -1041,17 +914,10 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
SpaceNode &snode = *CTX_wm_space_node(&C);
bNodeTree &ntree = *snode.edittree;
bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op.customdata;
- bool do_tag_update = false;
/* avoid updates while applying links */
ntree.is_updating = true;
for (bNodeLink *link : nldrag->links) {
- /* See note below, but basically TEST flag means that the link
- * was connected to output (or to a node which affects the
- * output).
- */
- do_tag_update |= (link->flag & NODE_LINK_TEST) != 0;
-
link->flag &= ~NODE_LINK_DRAGGED;
if (apply_links && link->tosock && link->fromsock) {
@@ -1067,18 +933,10 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
/* add link to the node tree */
BLI_addtail(&ntree.links, link);
-
- ntree.update |= NTREE_UPDATE_LINKS;
-
- /* tag tonode for update */
- link->tonode->update |= NODE_UPDATE;
+ BKE_ntree_update_tag_link_added(&ntree, link);
/* we might need to remove a link */
node_remove_extra_links(snode, *link);
-
- if (link->tonode) {
- do_tag_update |= (do_tag_update || node_connected_to_output(*bmain, ntree, *link->tonode));
- }
}
else {
nodeRemLink(&ntree, link);
@@ -1086,11 +944,7 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links)
}
ntree.is_updating = false;
- ntreeUpdateTree(bmain, &ntree);
- snode_notify(C, snode);
- if (do_tag_update) {
- snode_dag_update(C, snode);
- }
+ ED_node_tree_propagate_change(&C, bmain, &ntree);
/* Ensure draglink tooltip is disabled. */
draw_draglink_tooltip_deactivate(*CTX_wm_region(&C), *nldrag);
@@ -1250,8 +1104,7 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
-static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
- SpaceNode &snode,
+static std::unique_ptr<bNodeLinkDrag> node_link_init(SpaceNode &snode,
float2 cursor,
const bool detach)
{
@@ -1270,23 +1123,12 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
/* detach current links and store them in the operator data */
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) {
if (link->fromsock == sock) {
- bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
+ bNodeLink *oplink = MEM_cnew<bNodeLink>("drag link op link");
*oplink = *link;
oplink->next = oplink->prev = nullptr;
oplink->flag |= NODE_LINK_VALID;
oplink->flag |= NODE_LINK_DRAGGED;
- /* The link could be disconnected and in that case we
- * wouldn't be able to check whether tag update is
- * needed or not when releasing mouse button. So we
- * cache whether the link affects output or not here
- * using TEST flag.
- */
- oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, *snode.edittree, *link->tonode)) {
- oplink->flag |= NODE_LINK_TEST;
- }
-
nldrag->links.append(oplink);
nodeRemLink(snode.edittree, link);
}
@@ -1296,7 +1138,7 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
/* dragged links are fixed on output side */
nldrag->in_out = SOCK_OUT;
/* create a new link */
- nldrag->links.append(create_drag_link(bmain, snode, *node, *sock));
+ nldrag->links.append(create_drag_link(*node, *sock));
}
return nldrag;
}
@@ -1324,22 +1166,18 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
}
if (link_to_pick != nullptr && !nldrag->from_multi_input_socket) {
- bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link");
+ bNodeLink *oplink = MEM_cnew<bNodeLink>("drag link op link");
*oplink = *link_to_pick;
oplink->next = oplink->prev = nullptr;
oplink->flag |= NODE_LINK_VALID;
oplink->flag |= NODE_LINK_DRAGGED;
- oplink->flag &= ~NODE_LINK_TEST;
- if (node_connected_to_output(bmain, *snode.edittree, *link_to_pick->tonode)) {
- oplink->flag |= NODE_LINK_TEST;
- }
nldrag->links.append(oplink);
nodeRemLink(snode.edittree, link_to_pick);
/* send changed event to original link->tonode */
if (node) {
- snode_update(snode, node);
+ BKE_ntree_update_tag_node_property(snode.edittree, node);
}
}
}
@@ -1347,7 +1185,7 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain,
/* dragged links are fixed on input side */
nldrag->in_out = SOCK_IN;
/* create a new link */
- nldrag->links.append(create_drag_link(bmain, snode, *node, *sock));
+ nldrag->links.append(create_drag_link(*node, *sock));
}
return nldrag;
}
@@ -1370,7 +1208,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
ED_preview_kill_jobs(CTX_wm_manager(C), &bmain);
- std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(bmain, snode, cursor, detach);
+ std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(snode, cursor, detach);
if (nldrag) {
UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op);
@@ -1473,9 +1311,7 @@ static int node_make_link_exec(bContext *C, wmOperator *op)
node_deselect_all_input_sockets(snode, false);
node_deselect_all_output_sockets(snode, false);
- ntreeUpdateTree(CTX_data_main(C), snode.edittree);
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
return OPERATOR_FINISHED;
}
@@ -1532,7 +1368,6 @@ static int cut_links_exec(bContext *C, wmOperator *op)
Main &bmain = *CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
ARegion &region = *CTX_wm_region(C);
- bool do_tag_update = false;
int i = 0;
float mcoords[256][2];
@@ -1567,23 +1402,14 @@ static int cut_links_exec(bContext *C, wmOperator *op)
found = true;
}
- do_tag_update |= (do_tag_update ||
- node_connected_to_output(bmain, *snode.edittree, *link->tonode));
-
- snode_update(snode, link->tonode);
bNode *to_node = link->tonode;
nodeRemLink(snode.edittree, link);
sort_multi_input_socket_links(snode, *to_node, nullptr, nullptr);
}
}
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
if (found) {
- ntreeUpdateTree(CTX_data_main(C), snode.edittree);
- snode_notify(*C, snode);
- if (do_tag_update) {
- snode_dag_update(*C, snode);
- }
-
return OPERATOR_FINISHED;
}
@@ -1629,7 +1455,6 @@ static int mute_links_exec(bContext *C, wmOperator *op)
Main &bmain = *CTX_data_main(C);
SpaceNode &snode = *CTX_wm_space_node(C);
ARegion &region = *CTX_wm_region(C);
- bool do_tag_update = false;
int i = 0;
float mcoords[256][2];
@@ -1671,10 +1496,6 @@ static int mute_links_exec(bContext *C, wmOperator *op)
}
if (node_links_intersect(*link, mcoords, i)) {
- do_tag_update |= (do_tag_update ||
- node_connected_to_output(bmain, *snode.edittree, *link->tonode));
-
- snode_update(snode, link->tonode);
nodeMuteLinkToggle(snode.edittree, link);
}
}
@@ -1687,12 +1508,7 @@ static int mute_links_exec(bContext *C, wmOperator *op)
link->flag &= ~NODE_LINK_TEST;
}
- ntreeUpdateTree(CTX_data_main(C), snode.edittree);
- snode_notify(*C, snode);
- if (do_tag_update) {
- snode_dag_update(*C, snode);
- }
-
+ ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree);
return OPERATOR_FINISHED;
}
@@ -1743,11 +1559,7 @@ static int detach_links_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- ntreeUpdateTree(CTX_data_main(C), &ntree);
-
- snode_notify(*C, snode);
- snode_dag_update(*C, snode);
-
+ ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree);
return OPERATOR_FINISHED;
}
@@ -2653,8 +2465,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
/* set up insert offset data, it needs stuff from here */
if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
- NodeInsertOfsData *iofsd = (NodeInsertOfsData *)MEM_callocN(sizeof(NodeInsertOfsData),
- __func__);
+ NodeInsertOfsData *iofsd = MEM_cnew<NodeInsertOfsData>(__func__);
iofsd->insert = select;
iofsd->prev = link->fromnode;
@@ -2663,10 +2474,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
snode->runtime->iofsd = iofsd;
}
- ntreeUpdateTree(bmain, snode->edittree); /* needed for pointers */
- snode_update(*snode, select);
- ED_node_tag_update_id((ID *)snode->edittree);
- ED_node_tag_update_id(snode->id);
+ ED_node_tree_propagate_change(nullptr, bmain, snode->edittree);
}
}
}
diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc
index 386178596af..492237477c1 100644
--- a/source/blender/editors/space_node/node_templates.cc
+++ b/source/blender/editors/space_node/node_templates.cc
@@ -37,6 +37,7 @@
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
+#include "BKE_node_tree_update.h"
#include "RNA_access.h"
@@ -84,7 +85,7 @@ static void node_link_item_apply(Main *bmain, bNode *node, NodeLinkItem *item)
{
if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
node->id = (ID *)item->ngroup;
- ntreeUpdateTree(bmain, item->ngroup);
+ BKE_ntree_update_main_tree(bmain, item->ngroup, nullptr);
}
else {
/* nothing to do for now */
@@ -179,10 +180,8 @@ static void node_socket_disconnect(Main *bmain,
nodeRemLink(ntree, sock_to->link);
sock_to->flag |= SOCK_COLLAPSED;
- nodeUpdate(ntree, node_to);
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, node_to);
+ BKE_ntree_update_tag_node_property(ntree, node_to);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/* remove all nodes connected to this socket, if they aren't connected to other nodes */
@@ -195,10 +194,8 @@ static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bN
node_remove_linked(bmain, ntree, sock_to->link->fromnode);
sock_to->flag |= SOCK_COLLAPSED;
- nodeUpdate(ntree, node_to);
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, node_to);
+ BKE_ntree_update_tag_node_property(ntree, node_to);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/* add new node connected to this socket, or replace an existing one */
@@ -299,11 +296,9 @@ static void node_socket_add_replace(const bContext *C,
node_remove_linked(bmain, ntree, node_prev);
}
- nodeUpdate(ntree, node_from);
- nodeUpdate(ntree, node_to);
- ntreeUpdateTree(CTX_data_main(C), ntree);
-
- ED_node_tag_update_nodetree(CTX_data_main(C), ntree, node_to);
+ BKE_ntree_update_tag_node_property(ntree, node_from);
+ BKE_ntree_update_tag_node_property(ntree, node_to);
+ ED_node_tree_propagate_change(nullptr, bmain, ntree);
}
/****************************** Node Link Menu *******************************/
@@ -704,7 +699,7 @@ void uiTemplateNodeLink(
uiBut *but;
float socket_col[4];
- arg = (NodeLinkArg *)MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
+ arg = MEM_new<NodeLinkArg>("NodeLinkArg");
arg->ntree = ntree;
arg->node = node;
arg->sock = input;
diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc
index df629a983e3..12f390c47cd 100644
--- a/source/blender/editors/space_node/node_view.cc
+++ b/source/blender/editors/space_node/node_view.cc
@@ -255,7 +255,7 @@ static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *
return OPERATOR_CANCELLED;
}
- nvm = (NodeViewMove *)MEM_callocN(sizeof(NodeViewMove), "NodeViewMove struct");
+ nvm = MEM_cnew<NodeViewMove>("NodeViewMove struct");
op->customdata = nvm;
nvm->mvalo[0] = event->mval[0];
nvm->mvalo[1] = event->mval[1];
@@ -643,7 +643,7 @@ static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- info = (ImageSampleInfo *)MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
+ info = MEM_cnew<ImageSampleInfo>("ImageSampleInfo");
info->art = region->type;
info->draw_handle = ED_region_draw_cb_activate(
region->type, sample_draw, info, REGION_DRAW_POST_PIXEL);
diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc
index 4cc0bed1928..54a72a4b53d 100644
--- a/source/blender/editors/space_node/space_node.cc
+++ b/source/blender/editors/space_node/space_node.cc
@@ -63,7 +63,7 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
BLI_listbase_clear(&snode->treepath);
if (ntree) {
- bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path");
+ bNodeTreePath *path = MEM_cnew<bNodeTreePath>("node tree path");
path->nodetree = ntree;
path->parent_key = NODE_INSTANCE_KEY_BASE;
@@ -96,7 +96,7 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from)
void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode)
{
- bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path");
+ bNodeTreePath *path = MEM_cnew<bNodeTreePath>("node tree path");
bNodeTreePath *prev_path = (bNodeTreePath *)snode->treepath.last;
path->nodetree = ntree;
if (gnode) {
@@ -220,7 +220,7 @@ float2 space_node_group_offset(const SpaceNode &snode)
static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
- SpaceNode *snode = (SpaceNode *)MEM_callocN(sizeof(SpaceNode), "initnode");
+ SpaceNode *snode = MEM_cnew<SpaceNode>("initnode");
snode->spacetype = SPACE_NODE;
snode->flag = SNODE_SHOW_GPENCIL | SNODE_USE_ALPHA;
@@ -238,21 +238,21 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s
NODE_TREE_TYPES_END;
/* header */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "header for node");
+ ARegion *region = MEM_cnew<ARegion>("header for node");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_HEADER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
/* buttons/list view */
- region = (ARegion *)MEM_callocN(sizeof(ARegion), "buttons for node");
+ region = MEM_cnew<ARegion>("buttons for node");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_UI;
region->alignment = RGN_ALIGN_RIGHT;
/* toolbar */
- region = (ARegion *)MEM_callocN(sizeof(ARegion), "node tools");
+ region = MEM_cnew<ARegion>("node tools");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_TOOLS;
@@ -261,7 +261,7 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s
region->flag = RGN_FLAG_HIDDEN;
/* main region */
- region = (ARegion *)MEM_callocN(sizeof(ARegion), "main region for node");
+ region = MEM_cnew<ARegion>("main region for node");
BLI_addtail(&snode->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
@@ -309,10 +309,23 @@ static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *area)
SpaceNode *snode = (SpaceNode *)area->spacedata.first;
if (snode->runtime == nullptr) {
- snode->runtime = (SpaceNode_Runtime *)MEM_callocN(sizeof(SpaceNode_Runtime), __func__);
+ snode->runtime = MEM_new<SpaceNode_Runtime>(__func__);
}
}
+static bool any_node_uses_id(const bNodeTree *ntree, const ID *id)
+{
+ if (ELEM(nullptr, ntree, id)) {
+ return false;
+ }
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->id == id) {
+ return true;
+ }
+ }
+ return false;
+}
+
static void node_area_listener(const wmSpaceTypeListenerParams *params)
{
ScrArea *area = params->area;
@@ -436,10 +449,9 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
case NC_IMAGE:
if (wmn->action == NA_EDITED) {
if (ED_node_is_compositor(snode)) {
- /* note that nodeUpdateID is already called by BKE_image_signal() on all
- * scenes so really this is just to know if the images is used in the compo else
- * painting on images could become very slow when the compositor is open. */
- if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) {
+ /* Without this check drawing on an image could become very slow when the compositor is
+ * open. */
+ if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) {
ED_area_tag_refresh(area);
}
}
@@ -449,7 +461,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params)
case NC_MOVIECLIP:
if (wmn->action == NA_EDITED) {
if (ED_node_is_compositor(snode)) {
- if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) {
+ if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) {
ED_area_tag_refresh(area);
}
}
@@ -971,7 +983,7 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item,
void ED_spacetype_node()
{
- SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype node");
+ SpaceType *st = MEM_cnew<SpaceType>("spacetype node");
ARegionType *art;
st->spaceid = SPACE_NODE;
@@ -994,7 +1006,7 @@ void ED_spacetype_node()
st->space_subtype_set = node_space_subtype_set;
/* regions: main window */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region");
+ art = MEM_cnew<ARegionType>("spacetype node region");
art->regionid = RGN_TYPE_WINDOW;
art->init = node_main_region_init;
art->draw = node_main_region_draw;
@@ -1008,7 +1020,7 @@ void ED_spacetype_node()
BLI_addhead(&st->regiontypes, art);
/* regions: header */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region");
+ art = MEM_cnew<ARegionType>("spacetype node region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
@@ -1019,7 +1031,7 @@ void ED_spacetype_node()
BLI_addhead(&st->regiontypes, art);
/* regions: listview/buttons */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region");
+ art = MEM_cnew<ARegionType>("spacetype node region");
art->regionid = RGN_TYPE_UI;
art->prefsizex = UI_SIDEBAR_PANEL_WIDTH;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
@@ -1030,7 +1042,7 @@ void ED_spacetype_node()
BLI_addhead(&st->regiontypes, art);
/* regions: toolbar */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region");
+ art = MEM_cnew<ARegionType>("spacetype view3d tools region");
art->regionid = RGN_TYPE_TOOLS;
art->prefsizex = 58; /* XXX */
art->prefsizey = 50; /* XXX */
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index a4d5f2635d4..85fee590447 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -123,7 +123,7 @@ static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode
/* Find tree element to drop into, with additional before and after reorder support. */
static TreeElement *outliner_drop_insert_find(bContext *C,
- const wmEvent *event,
+ const int xy[2],
TreeElementInsertType *r_insert_type)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
@@ -136,8 +136,11 @@ static TreeElement *outliner_drop_insert_find(bContext *C,
return NULL;
}
- UI_view2d_region_to_view(
- &region->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]);
+ int mval[2];
+ mval[0] = xy[0] - region->winrct.xmin;
+ mval[1] = xy[1] - region->winrct.ymin;
+
+ UI_view2d_region_to_view(&region->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]);
te_hovered = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]);
if (te_hovered) {
@@ -216,10 +219,10 @@ static bool is_pchan_element(TreeElement *te)
}
static TreeElement *outliner_drop_insert_collection_find(bContext *C,
- const wmEvent *event,
+ const int xy[2],
TreeElementInsertType *r_insert_type)
{
- TreeElement *te = outliner_drop_insert_find(C, event, r_insert_type);
+ TreeElement *te = outliner_drop_insert_find(C, xy, r_insert_type);
if (!te) {
return NULL;
}
@@ -707,7 +710,7 @@ static bool datastack_drop_init(bContext *C, const wmEvent *event, StackDropData
return false;
}
- TreeElement *te_target = outliner_drop_insert_find(C, event, &drop_data->insert_type);
+ TreeElement *te_target = outliner_drop_insert_find(C, event->xy, &drop_data->insert_type);
if (!te_target) {
return false;
}
@@ -1088,14 +1091,12 @@ static Collection *collection_parent_from_ID(ID *id)
return NULL;
}
-static bool collection_drop_init(bContext *C,
- wmDrag *drag,
- const wmEvent *event,
- CollectionDrop *data)
+static bool collection_drop_init(
+ bContext *C, wmDrag *drag, const int xy[2], const bool is_link, CollectionDrop *data)
{
/* Get collection to drop into. */
TreeElementInsertType insert_type;
- TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type);
+ TreeElement *te = outliner_drop_insert_collection_find(C, xy, &insert_type);
if (!te) {
return false;
}
@@ -1123,7 +1124,7 @@ static bool collection_drop_init(bContext *C,
/* Get collection to drag out of. */
ID *parent = drag_id->from_parent;
Collection *from_collection = collection_parent_from_ID(parent);
- if (event->ctrl) {
+ if (is_link) {
from_collection = NULL;
}
@@ -1164,7 +1165,7 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
&space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false);
CollectionDrop data;
- if (!event->shift && collection_drop_init(C, drag, event, &data)) {
+ if (!event->shift && collection_drop_init(C, drag, event->xy, event->ctrl, &data)) {
TreeElement *te = data.te;
TreeStoreElem *tselem = TREESTORE(te);
if (!data.from || event->ctrl) {
@@ -1201,13 +1202,14 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event
static char *collection_drop_tooltip(bContext *C,
wmDrag *drag,
- const int UNUSED(xy[2]),
+ const int xy[2],
wmDropBox *UNUSED(drop))
{
- wmWindowManager *wm = CTX_wm_manager(C);
- const wmEvent *event = wm->winactive ? wm->winactive->eventstate : NULL;
+ wmWindow *win = CTX_wm_window(C);
+ const wmEvent *event = win ? win->eventstate : NULL;
+
CollectionDrop data;
- if (event && !event->shift && collection_drop_init(C, drag, event, &data)) {
+ if (event && !event->shift && collection_drop_init(C, drag, xy, event->ctrl, &data)) {
TreeElement *te = data.te;
if (!data.from || event->ctrl) {
return BLI_strdup(TIP_("Link inside Collection"));
@@ -1260,7 +1262,7 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
wmDrag *drag = lb->first;
CollectionDrop data;
- if (!collection_drop_init(C, drag, event, &data)) {
+ if (!collection_drop_init(C, drag, event->xy, event->ctrl, &data)) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 9d4b14a1f57..8ddd58bcc18 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -38,6 +38,7 @@
#include "BLT_translation.h"
+#include "BKE_action.h"
#include "BKE_animsys.h"
#include "BKE_appdir.h"
#include "BKE_armature.h"
@@ -48,6 +49,7 @@
#include "BKE_lib_query.h"
#include "BKE_lib_remap.h"
#include "BKE_main.h"
+#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_workspace.h"
@@ -627,8 +629,6 @@ static bool outliner_id_remap_find_tree_element(bContext *C,
TreeStoreElem *tselem = TREESTORE(te);
if ((tselem->type == TSE_SOME_ID) && tselem->id) {
- printf("found id %s (%p)!\n", tselem->id->name, tselem->id);
-
RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name));
RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2);
RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2);
@@ -654,7 +654,7 @@ static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent *
outliner_id_remap_find_tree_element(C, op, &space_outliner->tree, fmval[1]);
}
- return WM_operator_props_dialog_popup(C, op, 200);
+ return WM_operator_props_dialog_popup(C, op, 400);
}
static const EnumPropertyItem *outliner_id_itemf(bContext *C,
@@ -703,6 +703,9 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
+ /* Changing ID type wont make sense, would return early with "Invalid old/new ID pair" anyways.
+ */
+ RNA_def_property_flag(prop, PROP_HIDDEN);
prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace");
RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf);
@@ -1262,7 +1265,8 @@ static TreeElement *outliner_show_active_get_element(bContext *C,
TreeElement *te_obact = te;
if (obact->mode & OB_MODE_POSE) {
- bPoseChannel *pchan = CTX_data_active_pose_bone(C);
+ Object *obpose = BKE_object_pose_armature_get(obact);
+ bPoseChannel *pchan = BKE_pose_channel_active(obpose, false);
if (pchan) {
te = outliner_find_posechannel(&te_obact->subtree, pchan);
}
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 01f0feec771..bcd455de9a4 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -817,7 +817,7 @@ static void id_override_library_create_fn(bContext *C,
ID *id_reference = NULL;
bool is_override_instancing_object = false;
if (tsep != NULL && tsep->type == TSE_SOME_ID && tsep->id != NULL &&
- GS(tsep->id->name) == ID_OB) {
+ GS(tsep->id->name) == ID_OB && !ID_IS_OVERRIDE_LIBRARY(tsep->id)) {
Object *ob = (Object *)tsep->id;
if (ob->type == OB_EMPTY && &ob->instance_collection->id == id_root) {
BLI_assert(GS(id_root->name) == ID_GR);
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 616953e720a..9f31e55439d 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -627,6 +627,19 @@ static void seq_build_proxy(bContext *C, Sequence *seq)
ED_area_tag_redraw(CTX_wm_area(C));
}
+static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene,
+ ListBase *seqbase,
+ Sequence *seq_movie,
+ Sequence *seq_sound)
+{
+ if (ELEM(NULL, seq_movie, seq_sound) || seq_sound->len <= seq_movie->len) {
+ return;
+ }
+
+ SEQ_transform_set_right_handle_frame(seq_sound, SEQ_transform_get_right_handle_frame(seq_movie));
+ SEQ_time_update_sequence(scene, seqbase, seq_sound);
+}
+
static void sequencer_add_movie_multiple_strips(bContext *C,
wmOperator *op,
SeqLoadData *load_data)
@@ -689,6 +702,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C,
else {
load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp;
}
+ sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound);
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
seq_build_proxy(C, seq_movie);
@@ -740,6 +754,7 @@ static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoa
load_data->start_frame += audio_frame_offset;
seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, audio_skip);
}
+ sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound);
seq_load_apply_generic_options(C, op, seq_sound);
seq_load_apply_generic_options(C, op, seq_movie);
seq_build_proxy(C, seq_movie);
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index 61cc70830af..02f7f1d71c4 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -60,15 +60,14 @@ using namespace blender::ed::spreadsheet;
static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
- SpaceSpreadsheet *spreadsheet_space = (SpaceSpreadsheet *)MEM_callocN(sizeof(SpaceSpreadsheet),
- "spreadsheet space");
+ SpaceSpreadsheet *spreadsheet_space = MEM_cnew<SpaceSpreadsheet>("spreadsheet space");
spreadsheet_space->spacetype = SPACE_SPREADSHEET;
spreadsheet_space->filter_flag = SPREADSHEET_FILTER_ENABLE;
{
/* Header. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet header");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet header");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_HEADER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
@@ -76,7 +75,7 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
{
/* Footer. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet footer region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet footer region");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_FOOTER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
@@ -84,16 +83,15 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
{
/* Dataset Region */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet dataset region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet dataset region");
BLI_addtail(&spreadsheet_space->regionbase, region);
- region->regiontype = RGN_TYPE_CHANNELS;
+ region->regiontype = RGN_TYPE_TOOLS;
region->alignment = RGN_ALIGN_LEFT;
- region->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
}
{
/* Properties region. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet right region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet right region");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_UI;
region->alignment = RGN_ALIGN_RIGHT;
@@ -102,7 +100,7 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U
{
/* Main window. */
- ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet main region");
+ ARegion *region = MEM_cnew<ARegion>("spreadsheet main region");
BLI_addtail(&spreadsheet_space->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
}
@@ -114,7 +112,7 @@ static void spreadsheet_free(SpaceLink *sl)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
- delete sspreadsheet->runtime;
+ MEM_delete(sspreadsheet->runtime);
LISTBASE_FOREACH_MUTABLE (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) {
spreadsheet_row_filter_free(row_filter);
@@ -131,7 +129,7 @@ static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area)
{
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)area->spacedata.first;
if (sspreadsheet->runtime == nullptr) {
- sspreadsheet->runtime = new SpaceSpreadsheet_Runtime();
+ sspreadsheet->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__);
}
}
@@ -140,10 +138,11 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
const SpaceSpreadsheet *sspreadsheet_old = (SpaceSpreadsheet *)sl;
SpaceSpreadsheet *sspreadsheet_new = (SpaceSpreadsheet *)MEM_dupallocN(sspreadsheet_old);
if (sspreadsheet_old->runtime) {
- sspreadsheet_new->runtime = new SpaceSpreadsheet_Runtime(*sspreadsheet_old->runtime);
+ sspreadsheet_new->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__,
+ *sspreadsheet_old->runtime);
}
else {
- sspreadsheet_new->runtime = new SpaceSpreadsheet_Runtime();
+ sspreadsheet_new->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__);
}
BLI_listbase_clear(&sspreadsheet_new->row_filters);
@@ -621,7 +620,7 @@ static void spreadsheet_right_region_listener(const wmRegionListenerParams *UNUS
void ED_spacetype_spreadsheet()
{
- SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet");
+ SpaceType *st = MEM_cnew<SpaceType>("spacetype spreadsheet");
ARegionType *art;
st->spaceid = SPACE_SPREADSHEET;
@@ -636,7 +635,7 @@ void ED_spacetype_spreadsheet()
st->id_remap = spreadsheet_id_remap;
/* regions: main window */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet region");
art->regionid = RGN_TYPE_WINDOW;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
@@ -646,7 +645,7 @@ void ED_spacetype_spreadsheet()
BLI_addhead(&st->regiontypes, art);
/* regions: header */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet header region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet header region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = 0;
@@ -659,7 +658,7 @@ void ED_spacetype_spreadsheet()
BLI_addhead(&st->regiontypes, art);
/* regions: footer */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet footer region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet footer region");
art->regionid = RGN_TYPE_FOOTER;
art->prefsizey = HEADERY;
art->keymapflag = 0;
@@ -672,7 +671,7 @@ void ED_spacetype_spreadsheet()
BLI_addhead(&st->regiontypes, art);
/* regions: right panel buttons */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet right region");
+ art = MEM_cnew<ARegionType>("spacetype spreadsheet right region");
art->regionid = RGN_TYPE_UI;
art->prefsizex = UI_SIDEBAR_PANEL_WIDTH;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
@@ -687,10 +686,10 @@ void ED_spacetype_spreadsheet()
register_row_filter_panels(*art);
/* regions: channels */
- art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spreadsheet dataset region");
- art->regionid = RGN_TYPE_CHANNELS;
+ art = MEM_cnew<ARegionType>("spreadsheet dataset region");
+ art->regionid = RGN_TYPE_TOOLS;
art->prefsizex = 150 + V2D_SCROLL_WIDTH;
- art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D;
+ art->keymapflag = ED_KEYMAP_UI;
art->init = ED_region_panels_init;
art->draw = spreadsheet_dataset_region_draw;
art->listener = spreadsheet_dataset_region_listener;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
index 7551593ef38..ee623083db7 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc
@@ -66,8 +66,7 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type)
SpreadsheetColumnID *spreadsheet_column_id_new()
{
- SpreadsheetColumnID *column_id = (SpreadsheetColumnID *)MEM_callocN(sizeof(SpreadsheetColumnID),
- __func__);
+ SpreadsheetColumnID *column_id = MEM_cnew<SpreadsheetColumnID>(__func__);
return column_id;
}
@@ -88,8 +87,7 @@ void spreadsheet_column_id_free(SpreadsheetColumnID *column_id)
SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id)
{
- SpreadsheetColumn *column = (SpreadsheetColumn *)MEM_callocN(sizeof(SpreadsheetColumn),
- __func__);
+ SpreadsheetColumn *column = MEM_cnew<SpreadsheetColumn>(__func__);
column->id = column_id;
return column;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
index e55a7cae6a6..5cec016b727 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc
@@ -50,8 +50,7 @@ namespace blender::ed::spreadsheet {
static SpreadsheetContextObject *spreadsheet_context_object_new()
{
- SpreadsheetContextObject *context = (SpreadsheetContextObject *)MEM_callocN(
- sizeof(SpreadsheetContextObject), __func__);
+ SpreadsheetContextObject *context = MEM_cnew<SpreadsheetContextObject>(__func__);
context->base.type = SPREADSHEET_CONTEXT_OBJECT;
return context;
}
@@ -77,8 +76,7 @@ static void spreadsheet_context_object_free(SpreadsheetContextObject *context)
static SpreadsheetContextModifier *spreadsheet_context_modifier_new()
{
- SpreadsheetContextModifier *context = (SpreadsheetContextModifier *)MEM_callocN(
- sizeof(SpreadsheetContextModifier), __func__);
+ SpreadsheetContextModifier *context = MEM_cnew<SpreadsheetContextModifier>(__func__);
context->base.type = SPREADSHEET_CONTEXT_MODIFIER;
return context;
}
@@ -111,8 +109,7 @@ static void spreadsheet_context_modifier_free(SpreadsheetContextModifier *contex
static SpreadsheetContextNode *spreadsheet_context_node_new()
{
- SpreadsheetContextNode *context = (SpreadsheetContextNode *)MEM_callocN(
- sizeof(SpreadsheetContextNode), __func__);
+ SpreadsheetContextNode *context = MEM_cnew<SpreadsheetContextNode>(__func__);
context->base.type = SPREADSHEET_CONTEXT_NODE;
return context;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
index 854c3d4aba6..db8265a33ce 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc
@@ -25,7 +25,7 @@ namespace blender::ed::spreadsheet {
void spreadsheet_data_set_region_panels_register(ARegionType &region_type)
{
- PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ PanelType *panel_type = MEM_cnew<PanelType>(__func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_data_set");
strcpy(panel_type->label, N_("Data Set"));
strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index a6a0266fcc1..36c7f1057df 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -311,8 +311,7 @@ IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
SpreadsheetRowFilter *spreadsheet_row_filter_new()
{
- SpreadsheetRowFilter *row_filter = (SpreadsheetRowFilter *)MEM_callocN(
- sizeof(SpreadsheetRowFilter), __func__);
+ SpreadsheetRowFilter *row_filter = MEM_cnew<SpreadsheetRowFilter>(__func__);
row_filter->flag = (SPREADSHEET_ROW_FILTER_UI_EXPAND | SPREADSHEET_ROW_FILTER_ENABLED);
row_filter->operation = SPREADSHEET_ROW_FILTER_LESS;
row_filter->threshold = 0.01f;
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
index bcced7b5937..56722104b4f 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc
@@ -331,7 +331,7 @@ static void set_filter_expand_flag(const bContext *UNUSED(C), Panel *panel, shor
void register_row_filter_panels(ARegionType &region_type)
{
{
- PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ PanelType *panel_type = MEM_cnew<PanelType>(__func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_row_filters");
strcpy(panel_type->label, N_("Filters"));
strcpy(panel_type->category, "Filters");
@@ -342,7 +342,7 @@ void register_row_filter_panels(ARegionType &region_type)
}
{
- PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__);
+ PanelType *panel_type = MEM_cnew<PanelType>(__func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_filter");
strcpy(panel_type->label, "");
strcpy(panel_type->category, "Filters");
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index 41eddd32854..7f0f30624cb 100644
--- a/source/blender/editors/space_topbar/space_topbar.c
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -35,6 +35,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_screen.h"
+#include "BKE_undo_system.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -236,6 +237,59 @@ static void recent_files_menu_register(void)
WM_menutype_add(mt);
}
+static void undo_history_draw_menu(const bContext *C, Menu *menu)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (wm->undo_stack == NULL) {
+ return;
+ }
+ int undo_step_count = 0;
+ for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next) {
+ if (us->skip) {
+ continue;
+ }
+ undo_step_count += 1;
+ }
+
+ uiLayout *split = uiLayoutSplit(menu->layout, 0.0f, false);
+ uiLayout *column = NULL;
+
+ const int col_size = 20 + (undo_step_count / 12);
+ int i = 0;
+
+ undo_step_count = 0;
+ for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) {
+ if (us->skip) {
+ continue;
+ }
+ if (!(undo_step_count % col_size)) {
+ column = uiLayoutColumn(split, false);
+ }
+ const bool is_active = (us == wm->undo_stack->step_active);
+ uiLayout *row = uiLayoutRow(column, false);
+ uiLayoutSetEnabled(row, !is_active);
+ uiItemIntO(row,
+ IFACE_(us->name),
+ is_active ? ICON_LAYER_ACTIVE : ICON_NONE,
+ "ED_OT_undo_history",
+ "item",
+ i);
+ undo_step_count += 1;
+ }
+}
+
+static void undo_history_menu_register(void)
+{
+ MenuType *mt;
+
+ mt = MEM_callocN(sizeof(MenuType), __func__);
+ strcpy(mt->idname, "TOPBAR_MT_undo_history");
+ strcpy(mt->label, N_("Undo History"));
+ strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ mt->draw = undo_history_draw_menu;
+ WM_menutype_add(mt);
+}
+
void ED_spacetype_topbar(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype topbar");
@@ -278,6 +332,7 @@ void ED_spacetype_topbar(void)
BLI_addhead(&st->regiontypes, art);
recent_files_menu_register();
+ undo_history_menu_register();
BKE_spacetype_register(st);
}
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index b79303551a1..5451aa5a2e0 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -1552,7 +1552,7 @@ static void v3d_posearmature_buts(uiLayout *layout, Object *ob)
PointerRNA pchanptr;
uiLayout *col;
- pchan = BKE_pose_channel_active(ob);
+ pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (!pchan) {
uiItemL(layout, IFACE_("No Bone Active"), ICON_NONE);
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index a7d170982ed..b1f19581543 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1581,6 +1581,7 @@ void view3d_main_region_draw(const bContext *C, ARegion *region)
view3d_draw_view(C, region);
+ DRW_cache_free_old_subdiv();
DRW_cache_free_old_batches(bmain);
BKE_image_free_old_gputextures(bmain);
GPU_pass_cache_garbage_collect();
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 830f7cbeff1..80089815284 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -3216,7 +3216,7 @@ static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op))
if (obact->mode & OB_MODE_POSE) {
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact);
- bPoseChannel *pcham_act = BKE_pose_channel_active(obact_eval);
+ bPoseChannel *pcham_act = BKE_pose_channel_active_if_layer_visible(obact_eval);
if (pcham_act) {
BLI_strncpy(v3d->ob_center_bone, pcham_act->name, sizeof(v3d->ob_center_bone));
}
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
index 83d3286c8b3..31ae8a92f81 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_armature.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
@@ -134,7 +134,7 @@ static bool WIDGETGROUP_armature_spline_poll(const bContext *C, wmGizmoGroupType
if (ob) {
const bArmature *arm = ob->data;
if (arm->drawtype == ARM_B_BONE) {
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && pchan->bone->segments > 1) {
return true;
}
@@ -148,7 +148,7 @@ static void WIDGETGROUP_armature_spline_setup(const bContext *C, wmGizmoGroup *g
{
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = BKE_object_pose_armature_get(OBACT(view_layer));
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true);
@@ -187,7 +187,7 @@ static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmGizmoGroup
}
struct BoneSplineWidgetGroup *bspline_group = gzgroup->customdata;
- bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
/* Handles */
for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) {
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 8f3d13176a3..4107cc3a71c 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -914,6 +914,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
case TC_SEQ_DATA:
special_aftertrans_update__sequencer(C, t);
break;
+ case TC_SEQ_IMAGE_DATA:
+ special_aftertrans_update__sequencer_image(C, t);
+ break;
case TC_TRACKING_DATA:
special_aftertrans_update__movieclip(C, t);
break;
@@ -930,7 +933,6 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
case TC_OBJECT_TEXSPACE:
case TC_PAINT_CURVE_VERTS:
case TC_PARTICLE_VERTS:
- case TC_SEQ_IMAGE_DATA:
case TC_NONE:
default:
break;
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index 5ed8182857d..12f3b39927e 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -304,6 +304,7 @@ void special_aftertrans_update__sequencer(bContext *C, TransInfo *t);
/* transform_convert_sequencer_image.c */
void createTransSeqImageData(TransInfo *t);
void recalcData_sequencer_image(TransInfo *t);
+void special_aftertrans_update__sequencer_image(bContext *C, TransInfo *t);
/* transform_convert_tracking.c */
void createTransTrackingData(bContext *C, TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 63aada0f797..5d0a3bd9dd1 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -427,7 +427,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob)
/* Rule: allow multiple Bones
* (but they must be selected, and only one ik-solver per chain should get added) */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->layer & arm->layer) {
+ if (BKE_pose_is_layer_visible(arm, pchan)) {
if (pchan->bone->flag & (BONE_SELECTED | BONE_TRANSFORM_MIRROR)) {
/* Rule: no IK for solitary (unconnected) bones. */
for (bonec = pchan->bone->childbase.first; bonec; bonec = bonec->next) {
diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c
index 1a25cfd1efb..e26172cd764 100644
--- a/source/blender/editors/transform/transform_convert_mask.c
+++ b/source/blender/editors/transform/transform_convert_mask.c
@@ -472,12 +472,7 @@ void special_aftertrans_update__mask(bContext *C, TransInfo *t)
}
if (t->scene->nodetree) {
- /* tracks can be used for stabilization nodes,
- * flush update for such nodes */
- // if (nodeUpdateID(t->scene->nodetree, &mask->id))
- {
- WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
- }
+ WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
}
/* TODO: don't key all masks. */
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c
index da11666d445..e8cdfaf1f40 100644
--- a/source/blender/editors/transform/transform_convert_node.c
+++ b/source/blender/editors/transform/transform_convert_node.c
@@ -31,6 +31,7 @@
#include "BKE_context.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_report.h"
#include "ED_node.h"
@@ -246,7 +247,7 @@ void special_aftertrans_update__node(bContext *C, TransInfo *t)
nodeRemoveNode(bmain, ntree, node, true);
}
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(C, bmain, ntree);
}
}
diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c
index d5a59885014..3a5770c2863 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -38,8 +38,12 @@
#include "SEQ_transform.h"
#include "SEQ_utils.h"
+#include "ED_keyframing.h"
+
#include "UI_view2d.h"
+#include "RNA_access.h"
+
#include "transform.h"
#include "transform_convert.h"
@@ -215,3 +219,44 @@ void recalcData_sequencer_image(TransInfo *t)
SEQ_relations_invalidate_cache_preprocessed(t->scene, seq);
}
}
+
+void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *t)
+{
+ if (t->state == TRANS_CANCEL) {
+ return;
+ }
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ int i;
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+
+ for (i = 0, td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
+ TransDataSeq *tdseq = td->extra;
+ Sequence *seq = tdseq->seq;
+ StripTransform *transform = seq->strip->transform;
+ Scene *scene = t->scene;
+
+ RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform, &ptr);
+
+ if (t->mode == TFM_ROTATION) {
+ prop = RNA_struct_find_property(&ptr, "rotation");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ }
+ if (t->mode == TFM_TRANSLATION) {
+ prop = RNA_struct_find_property(&ptr, "offset_x");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ prop = RNA_struct_find_property(&ptr, "offset_y");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ }
+ if (t->mode == TFM_RESIZE) {
+ prop = RNA_struct_find_property(&ptr, "scale_x");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ prop = RNA_struct_find_property(&ptr, "scale_y");
+ ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA);
+ }
+ }
+}
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index dc37f2796bf..f2d0fb7ac2f 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -29,8 +29,10 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
#include "ED_clip.h"
@@ -793,8 +795,12 @@ void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
/* Tracks can be used for stabilization nodes,
* flush update for such nodes.
*/
- nodeUpdateID(t->scene->nodetree, &clip->id);
- WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
+ if (t->context != NULL) {
+ Main *bmain = CTX_data_main(C);
+ BKE_ntree_update_tag_id_changed(bmain, &clip->id);
+ BKE_ntree_update_main(bmain, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL);
+ }
}
}
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index d2e7f9f83df..2ab4cdff5e6 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -1042,7 +1042,7 @@ void ElementResize(const TransInfo *t,
applyNumInput(&num_evil, values_final_evil);
float ratio = values_final_evil[0];
- *td->val = td->ival * ratio * gps->runtime.multi_frame_falloff;
+ *td->val = td->ival * fabs(ratio) * gps->runtime.multi_frame_falloff;
CLAMP_MIN(*td->val, 0.001f);
}
}
diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c
index 5f2a2e472c5..84ca5d3ae54 100644
--- a/source/blender/editors/transform/transform_mode_timetranslate.c
+++ b/source/blender/editors/transform/transform_mode_timetranslate.c
@@ -62,27 +62,28 @@ static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR])
float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival;
float val = ival + t->values_final[0];
- float snap_val = val;
- snapFrameTransform(t, autosnap, ival, val, &snap_val);
+ snapFrameTransform(t, autosnap, ival, val, &val);
+ float delta_x = val - ival;
if (ELEM(autosnap, SACTSNAP_SECOND, SACTSNAP_TSTEP)) {
/* Convert to seconds. */
const Scene *scene = t->scene;
const double secf = FPS;
- snap_val /= secf;
+ delta_x /= secf;
+ val /= secf;
}
if (autosnap == SACTSNAP_FRAME) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", snap_val, val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", delta_x, val);
}
else if (autosnap == SACTSNAP_SECOND) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", snap_val, val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", delta_x, val);
}
else if (autosnap == SACTSNAP_TSTEP) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", snap_val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", delta_x);
}
else {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", snap_val);
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", delta_x);
}
}
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index 19d0c6d39a3..b8b043c650f 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -225,11 +225,12 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
if (t->spacetype == SPACE_GRAPH) {
/* WORKAROUND:
* Special case where snapping is done in #recalData.
- * Update the header based on the first element. */
+ * Update the header based on the #center_local. */
const short autosnap = getAnimEdit_SnapMode(t);
- float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival;
+ float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->center_local[0];
float val = ival + dvec[0];
- snapFrameTransform(t, autosnap, ival, val, &dvec[0]);
+ snapFrameTransform(t, autosnap, ival, val, &val);
+ dvec[0] = val - ival;
}
if (t->con.mode & CON_APPLY) {
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index fa2485c33c2..5ac5bccd69c 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -513,7 +513,7 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
if (ob) {
if (ob->mode & OB_MODE_POSE) {
- const bPoseChannel *pchan = BKE_pose_channel_active(ob);
+ const bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob);
if (pchan && gimbal_axis_pose(ob, pchan, r_mat)) {
break;
}
@@ -1224,7 +1224,7 @@ int getTransformOrientation_ex(ViewLayer *view_layer,
float imat[3][3], mat[3][3];
bool ok = false;
- if (activeOnly && (pchan = BKE_pose_channel_active(ob))) {
+ if (activeOnly && (pchan = BKE_pose_channel_active_if_layer_visible(ob))) {
add_v3_v3(normal, pchan->pose_mat[2]);
add_v3_v3(plane, pchan->pose_mat[1]);
ok = true;
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 9cdec357afd..40be8e6e641 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -505,9 +505,9 @@ void applySnapping(TransInfo *t, float *vec)
if (t->tsnap.targetSnap) {
t->tsnap.targetSnap(t);
}
- }
- t->tsnap.last = current;
+ t->tsnap.last = current;
+ }
if (validSnap(t)) {
t->tsnap.applySnap(t, vec);
@@ -693,6 +693,15 @@ static void initSnappingMode(TransInfo *t)
bm_face_is_snap_target,
POINTER_FROM_UINT((BM_ELEM_SELECT | BM_ELEM_HIDDEN)));
}
+ else {
+ /* Ignore hidden geometry in the general case. */
+ ED_transform_snap_object_context_set_editmesh_callbacks(
+ t->tsnap.object_context,
+ (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled,
+ (bool (*)(BMEdge *, void *))BM_elem_cb_check_hflag_disabled,
+ (bool (*)(BMFace *, void *))BM_elem_cb_check_hflag_disabled,
+ POINTER_FROM_UINT(BM_ELEM_HIDDEN));
+ }
}
}
else if (t->spacetype == SPACE_SEQ) {
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 350d3a2676c..e3a2d1f6531 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -146,7 +146,7 @@ struct SnapObjectContext {
* If NULL the BMesh should be used. */
static Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide)
{
- Mesh *me_eval = ob_eval->data;
+ Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
bool use_hide = false;
if (BKE_object_is_in_editmode(ob_eval)) {
if (edit_mode_type == SNAP_GEOM_EDIT) {
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index aca99f81e7b..c6fa5acfff5 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -64,6 +64,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -759,81 +760,16 @@ void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_un
/* -------------------------------------------------------------------- */
/** \name Undo History Operator
+ *
+ * See `TOPBAR_MT_undo_history` which is used to access this operator.
* \{ */
-/* create enum based on undo items */
-static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem)
-{
- EnumPropertyItem item_tmp = {0}, *item = NULL;
- int i = 0;
-
- wmWindowManager *wm = CTX_wm_manager(C);
- if (wm->undo_stack == NULL) {
- return NULL;
- }
-
- for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) {
- if (us->skip == false) {
- item_tmp.identifier = us->name;
- item_tmp.name = IFACE_(us->name);
- if (us == wm->undo_stack->step_active) {
- item_tmp.icon = ICON_LAYER_ACTIVE;
- }
- else {
- item_tmp.icon = ICON_NONE;
- }
- item_tmp.value = i;
- RNA_enum_item_add(&item, totitem, &item_tmp);
- }
- }
- RNA_enum_item_end(&item, totitem);
-
- return item;
-}
-
-static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- int totitem = 0;
-
- {
- const EnumPropertyItem *item = rna_undo_itemf(C, &totitem);
-
- if (totitem > 0) {
- uiPopupMenu *pup = UI_popup_menu_begin(
- C, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
- uiLayout *layout = UI_popup_menu_layout(pup);
- uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
- uiLayout *column = NULL;
- const int col_size = 20 + totitem / 12;
- int i, c;
- bool add_col = true;
-
- for (c = 0, i = totitem; i--;) {
- if (add_col && !(c % col_size)) {
- column = uiLayoutColumn(split, false);
- add_col = false;
- }
- if (item[i].identifier) {
- uiItemIntO(column, item[i].name, item[i].icon, op->type->idname, "item", item[i].value);
- c++;
- add_col = true;
- }
- }
-
- MEM_freeN((void *)item);
-
- UI_popup_menu_end(C, pup);
- }
- }
- return OPERATOR_CANCELLED;
-}
-
/* NOTE: also check #ed_undo_step() in top if you change notifiers. */
static int undo_history_exec(bContext *C, wmOperator *op)
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
if (RNA_property_is_set(op->ptr, prop)) {
- int item = RNA_property_int_get(op->ptr, prop);
+ const int item = RNA_property_int_get(op->ptr, prop);
const int ret = ed_undo_step_by_index(C, item, op->reports);
if (ret & OPERATOR_FINISHED) {
ed_undo_refresh_for_op(C);
@@ -845,14 +781,15 @@ static int undo_history_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static bool undo_history_poll(bContext *C)
+static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- if (!ed_undo_is_init_and_screenactive_poll(C)) {
- return false;
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ return undo_history_exec(C, op);
}
- UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack;
- /* More than just original state entry. */
- return BLI_listbase_count_at_most(&undo_stack->steps, 2) > 1;
+
+ WM_menu_name_call(C, "TOPBAR_MT_undo_history", WM_OP_INVOKE_DEFAULT);
+ return OPERATOR_FINISHED;
}
void ED_OT_undo_history(wmOperatorType *ot)
@@ -865,7 +802,7 @@ void ED_OT_undo_history(wmOperatorType *ot)
/* api callbacks */
ot->invoke = undo_history_invoke;
ot->exec = undo_history_exec;
- ot->poll = undo_history_poll;
+ ot->poll = ed_undo_is_init_and_screenactive_poll;
RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX);
}
diff --git a/source/blender/editors/util/ed_util_imbuf.c b/source/blender/editors/util/ed_util_imbuf.c
index 38ae98c678f..2e983eeff39 100644
--- a/source/blender/editors/util/ed_util_imbuf.c
+++ b/source/blender/editors/util/ed_util_imbuf.c
@@ -278,13 +278,13 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
/* XXX node curve integration. */
#if 0
{
- ScrArea *sa, *cur = curarea;
+ ScrArea *area, *cur = curarea;
node_curvemap_sample(fp); /* sends global to node editor */
- for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_NODE) {
- areawinset(sa->win);
- scrarea_do_windraw(sa);
+ for (area = G.curscreen->areabase.first; area; area = area->next) {
+ if (area->spacetype == SPACE_NODE) {
+ areawinset(area->win);
+ scrarea_do_windraw(area);
}
}
node_curvemap_sample(NULL); /* clears global in node editor */
@@ -385,12 +385,12 @@ static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *e
static void ed_imbuf_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa == NULL) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area == NULL) {
return;
}
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_IMAGE: {
image_sample_apply(C, op, event);
break;
@@ -432,9 +432,9 @@ void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info)
info->zfp);
if (info->sample_size > 1) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_IMAGE) {
+ if (area && area->spacetype == SPACE_IMAGE) {
const wmWindow *win = CTX_wm_window(C);
const wmEvent *event = win->eventstate;
@@ -482,11 +482,11 @@ void ED_imbuf_sample_exit(bContext *C, wmOperator *op)
int ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
- ScrArea *sa = CTX_wm_area(C);
- if (sa) {
- switch (sa->spacetype) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
if (region->regiontype == RGN_TYPE_WINDOW) {
if (ED_space_image_show_cache_and_mval_over(sima, region, event->mval)) {
return OPERATOR_PASS_THROUGH;
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 342afa847b4..64e1fa2f768 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -180,7 +180,7 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i
if (node && is_image_texture_node(node)) {
node->id = &ima->id;
- ED_node_tag_update_nodetree(bmain, ma->nodetree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ma->nodetree);
}
}
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 0a82c237256..a2d5ffb1392 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -48,6 +48,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -415,7 +416,7 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain,
}
nodeSetActive(ntree, output_material);
- ntreeUpdateTree(bmain, ntree);
+ BKE_ntree_update_main_tree(bmain, ntree, nullptr);
return ma;
}
diff --git a/source/blender/freestyle/intern/image/GaussianFilter.h b/source/blender/freestyle/intern/image/GaussianFilter.h
index af537cf2d86..f6bfdbd31b0 100644
--- a/source/blender/freestyle/intern/image/GaussianFilter.h
+++ b/source/blender/freestyle/intern/image/GaussianFilter.h
@@ -123,7 +123,7 @@ class GaussianFilter {
template<class Map> float GaussianFilter::getSmoothedPixel(Map *map, int x, int y)
{
- float sum = 0.0f;
+ // float sum = 0.0f;
float L = 0.0f;
int w = (int)map->width(); // soc
int h = (int)map->height(); // soc
@@ -142,7 +142,7 @@ template<class Map> float GaussianFilter::getSmoothedPixel(Map *map, int x, int
float tmpL = map->pixel(x + j, y + i);
float m = _mask[abs(i) * _storedMaskSize + abs(j)];
L += m * tmpL;
- sum += m;
+ // sum += m;
}
}
// L /= sum;
diff --git a/source/blender/freestyle/intern/stroke/Operators.cpp b/source/blender/freestyle/intern/stroke/Operators.cpp
index c73bb739e47..cdb85817a85 100644
--- a/source/blender/freestyle/intern/stroke/Operators.cpp
+++ b/source/blender/freestyle/intern/stroke/Operators.cpp
@@ -885,7 +885,7 @@ static int __recursiveSplit(Chain *_curve,
#endif
real _min = FLT_MAX;
++it;
- real mean = 0.0f;
+ // real mean = 0.0f;
// soc unused - real variance = 0.0f;
unsigned count = 0;
CurveInternal::CurvePointIterator next = it;
@@ -904,14 +904,14 @@ static int __recursiveSplit(Chain *_curve,
if (func(it0d) < 0) {
return -1;
}
- mean += func.result;
+ // mean += func.result;
if (func.result < _min) {
_min = func.result;
split = it;
bsplit = true;
}
}
- mean /= (float)count;
+ // mean /= (float)count;
// if ((!bsplit) || (mean - _min > mean)) { // we didn't find any minimum
if (!bsplit) { // we didn't find any minimum
diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh
index a591aaed34a..11f8a7e9b94 100644
--- a/source/blender/functions/FN_field.hh
+++ b/source/blender/functions/FN_field.hh
@@ -60,11 +60,21 @@ class FieldInput;
struct FieldInputs;
/**
+ * Have a fixed set of base node types, because all code that works with field nodes has to
+ * understand those.
+ */
+enum class FieldNodeType {
+ Input,
+ Operation,
+ Constant,
+};
+
+/**
* A node in a field-tree. It has at least one output that can be referenced by fields.
*/
class FieldNode {
private:
- bool is_input_;
+ FieldNodeType node_type_;
protected:
/**
@@ -76,14 +86,13 @@ class FieldNode {
std::shared_ptr<const FieldInputs> field_inputs_;
public:
- FieldNode(bool is_input);
+ FieldNode(FieldNodeType node_type);
virtual ~FieldNode() = default;
virtual const CPPType &output_cpp_type(int output_index) const = 0;
- bool is_input() const;
- bool is_operation() const;
+ FieldNodeType node_type() const;
bool depends_on_input() const;
const std::shared_ptr<const FieldInputs> &field_inputs() const;
@@ -267,6 +276,20 @@ class FieldInput : public FieldNode {
const CPPType &output_cpp_type(int output_index) const override;
};
+class FieldConstant : public FieldNode {
+ private:
+ const CPPType &type_;
+ void *value_;
+
+ public:
+ FieldConstant(const CPPType &type, const void *value);
+ ~FieldConstant();
+
+ const CPPType &output_cpp_type(int output_index) const override;
+ const CPPType &type() const;
+ GPointer value() const;
+};
+
/**
* Keeps track of the inputs of a field.
*/
@@ -468,9 +491,7 @@ template<typename T> T evaluate_constant_field(const Field<T> &field)
template<typename T> Field<T> make_constant_field(T value)
{
- auto constant_fn = std::make_unique<fn::CustomMF_Constant<T>>(std::forward<T>(value));
- auto operation = std::make_shared<FieldOperation>(std::move(constant_fn));
- return Field<T>{GField{std::move(operation), 0}};
+ return make_constant_field(CPPType::get<T>(), &value);
}
GField make_constant_field(const CPPType &type, const void *value);
@@ -552,18 +573,13 @@ template<typename T> struct ValueOrField {
/** \name #FieldNode Inline Methods
* \{ */
-inline FieldNode::FieldNode(bool is_input) : is_input_(is_input)
-{
-}
-
-inline bool FieldNode::is_input() const
+inline FieldNode::FieldNode(const FieldNodeType node_type) : node_type_(node_type)
{
- return is_input_;
}
-inline bool FieldNode::is_operation() const
+inline FieldNodeType FieldNode::node_type() const
{
- return !is_input_;
+ return node_type_;
}
inline bool FieldNode::depends_on_input() const
diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh
index fc8612d6f87..6aebca51219 100644
--- a/source/blender/functions/FN_generic_virtual_array.hh
+++ b/source/blender/functions/FN_generic_virtual_array.hh
@@ -753,8 +753,7 @@ namespace detail {
template<typename StorageT> inline GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get()
{
static_assert(std::is_base_of_v<GVArrayImpl, StorageT> ||
- std::is_same_v<StorageT, const GVArrayImpl *> ||
- std::is_same_v<StorageT, std::shared_ptr<const GVArrayImpl>>);
+ is_same_any_v<StorageT, const GVArrayImpl *, std::shared_ptr<const GVArrayImpl>>);
if constexpr (std::is_base_of_v<GVArrayImpl, StorageT>) {
return {[](const void *buffer) {
diff --git a/source/blender/functions/FN_multi_function_procedure.hh b/source/blender/functions/FN_multi_function_procedure.hh
index a26eb1045a7..d73bc089278 100644
--- a/source/blender/functions/FN_multi_function_procedure.hh
+++ b/source/blender/functions/FN_multi_function_procedure.hh
@@ -268,6 +268,7 @@ class MFProcedure : NonCopyable, NonMovable {
Vector<MFReturnInstruction *> return_instructions_;
Vector<MFVariable *> variables_;
Vector<MFParameter> params_;
+ Vector<destruct_ptr<MultiFunction>> owned_functions_;
MFInstruction *entry_ = nullptr;
friend class MFProcedureDotExport;
@@ -284,9 +285,10 @@ class MFProcedure : NonCopyable, NonMovable {
MFReturnInstruction &new_return_instruction();
void add_parameter(MFParamType::InterfaceType interface_type, MFVariable &variable);
-
Span<ConstMFParameter> params() const;
+ template<typename T, typename... Args> const MultiFunction &construct_function(Args &&...args);
+
MFInstruction *entry();
const MFInstruction *entry() const;
void set_entry(MFInstruction &entry);
@@ -550,6 +552,15 @@ inline Span<const MFVariable *> MFProcedure::variables() const
return variables_;
}
+template<typename T, typename... Args>
+inline const MultiFunction &MFProcedure::construct_function(Args &&...args)
+{
+ destruct_ptr<T> fn = allocator_.construct<T>(std::forward<Args>(args)...);
+ const MultiFunction &fn_ref = *fn;
+ owned_functions_.append(std::move(fn));
+ return fn_ref;
+}
+
/** \} */
} // namespace blender::fn
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index 604e5c6d13f..d6b83c42294 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -64,17 +64,26 @@ static FieldTreeInfo preprocess_field_tree(Span<GFieldRef> entry_fields)
while (!fields_to_check.is_empty()) {
GFieldRef field = fields_to_check.pop();
- if (field.node().is_input()) {
- const FieldInput &field_input = static_cast<const FieldInput &>(field.node());
- field_tree_info.deduplicated_field_inputs.add(field_input);
- continue;
- }
- BLI_assert(field.node().is_operation());
- const FieldOperation &operation = static_cast<const FieldOperation &>(field.node());
- for (const GFieldRef operation_input : operation.inputs()) {
- field_tree_info.field_users.add(operation_input, field);
- if (handled_fields.add(operation_input)) {
- fields_to_check.push(operation_input);
+ const FieldNode &field_node = field.node();
+ switch (field_node.node_type()) {
+ case FieldNodeType::Input: {
+ const FieldInput &field_input = static_cast<const FieldInput &>(field_node);
+ field_tree_info.deduplicated_field_inputs.add(field_input);
+ break;
+ }
+ case FieldNodeType::Operation: {
+ const FieldOperation &operation = static_cast<const FieldOperation &>(field_node);
+ for (const GFieldRef operation_input : operation.inputs()) {
+ field_tree_info.field_users.add(operation_input, field);
+ if (handled_fields.add(operation_input)) {
+ fields_to_check.push(operation_input);
+ }
+ }
+ break;
+ }
+ case FieldNodeType::Constant: {
+ /* Nothing to do. */
+ break;
}
}
}
@@ -179,56 +188,71 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure,
fields_to_check.pop();
continue;
}
- /* Field inputs should already be handled above. */
- BLI_assert(field.node().is_operation());
-
- const FieldOperation &operation = static_cast<const FieldOperation &>(field.node());
- const Span<GField> operation_inputs = operation.inputs();
-
- if (field_with_index.current_input_index < operation_inputs.size()) {
- /* Not all inputs are handled yet. Push the next input field to the stack and increment the
- * input index. */
- fields_to_check.push({operation_inputs[field_with_index.current_input_index]});
- field_with_index.current_input_index++;
- }
- else {
- /* All inputs variables are ready, now gather all variables that are used by the function
- * and call it. */
- const MultiFunction &multi_function = operation.multi_function();
- Vector<MFVariable *> variables(multi_function.param_amount());
-
- int param_input_index = 0;
- int param_output_index = 0;
- for (const int param_index : multi_function.param_indices()) {
- const MFParamType param_type = multi_function.param_type(param_index);
- const MFParamType::InterfaceType interface_type = param_type.interface_type();
- if (interface_type == MFParamType::Input) {
- const GField &input_field = operation_inputs[param_input_index];
- variables[param_index] = variable_by_field.lookup(input_field);
- param_input_index++;
- }
- else if (interface_type == MFParamType::Output) {
- const GFieldRef output_field{operation, param_output_index};
- const bool output_is_ignored =
- field_tree_info.field_users.lookup(output_field).is_empty() &&
- !output_fields.contains(output_field);
- if (output_is_ignored) {
- /* Ignored outputs don't need a variable. */
- variables[param_index] = nullptr;
- }
- else {
- /* Create a new variable for used outputs. */
- MFVariable &new_variable = procedure.new_variable(param_type.data_type());
- variables[param_index] = &new_variable;
- variable_by_field.add_new(output_field, &new_variable);
- }
- param_output_index++;
+ const FieldNode &field_node = field.node();
+ switch (field_node.node_type()) {
+ case FieldNodeType::Input: {
+ /* Field inputs should already be handled above. */
+ break;
+ }
+ case FieldNodeType::Operation: {
+ const FieldOperation &operation_node = static_cast<const FieldOperation &>(field.node());
+ const Span<GField> operation_inputs = operation_node.inputs();
+
+ if (field_with_index.current_input_index < operation_inputs.size()) {
+ /* Not all inputs are handled yet. Push the next input field to the stack and increment
+ * the input index. */
+ fields_to_check.push({operation_inputs[field_with_index.current_input_index]});
+ field_with_index.current_input_index++;
}
else {
- BLI_assert_unreachable();
+ /* All inputs variables are ready, now gather all variables that are used by the
+ * function and call it. */
+ const MultiFunction &multi_function = operation_node.multi_function();
+ Vector<MFVariable *> variables(multi_function.param_amount());
+
+ int param_input_index = 0;
+ int param_output_index = 0;
+ for (const int param_index : multi_function.param_indices()) {
+ const MFParamType param_type = multi_function.param_type(param_index);
+ const MFParamType::InterfaceType interface_type = param_type.interface_type();
+ if (interface_type == MFParamType::Input) {
+ const GField &input_field = operation_inputs[param_input_index];
+ variables[param_index] = variable_by_field.lookup(input_field);
+ param_input_index++;
+ }
+ else if (interface_type == MFParamType::Output) {
+ const GFieldRef output_field{operation_node, param_output_index};
+ const bool output_is_ignored =
+ field_tree_info.field_users.lookup(output_field).is_empty() &&
+ !output_fields.contains(output_field);
+ if (output_is_ignored) {
+ /* Ignored outputs don't need a variable. */
+ variables[param_index] = nullptr;
+ }
+ else {
+ /* Create a new variable for used outputs. */
+ MFVariable &new_variable = procedure.new_variable(param_type.data_type());
+ variables[param_index] = &new_variable;
+ variable_by_field.add_new(output_field, &new_variable);
+ }
+ param_output_index++;
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+ }
+ builder.add_call_with_all_variables(multi_function, variables);
}
+ break;
+ }
+ case FieldNodeType::Constant: {
+ const FieldConstant &constant_node = static_cast<const FieldConstant &>(field_node);
+ const MultiFunction &fn = procedure.construct_function<CustomMF_GenericConstant>(
+ constant_node.type(), constant_node.value().get(), false);
+ MFVariable &new_variable = *builder.add_call<1>(fn)[0];
+ variable_by_field.add_new(field, &new_variable);
+ break;
}
- builder.add_call_with_all_variables(multi_function, variables);
}
}
}
@@ -301,17 +325,29 @@ Vector<GVArray> evaluate_fields(ResourceScope &scope,
Vector<GVArray> field_context_inputs = get_field_context_inputs(
scope, mask, context, field_tree_info.deduplicated_field_inputs);
- /* Finish fields that output an input varray directly. For those we don't have to do any further
- * processing. */
+ /* Finish fields that don't need any processing directly. */
for (const int out_index : fields_to_evaluate.index_range()) {
const GFieldRef &field = fields_to_evaluate[out_index];
- if (!field.node().is_input()) {
- continue;
+ const FieldNode &field_node = field.node();
+ switch (field_node.node_type()) {
+ case FieldNodeType::Input: {
+ const FieldInput &field_input = static_cast<const FieldInput &>(field.node());
+ const int field_input_index = field_tree_info.deduplicated_field_inputs.index_of(
+ field_input);
+ const GVArray &varray = field_context_inputs[field_input_index];
+ r_varrays[out_index] = varray;
+ break;
+ }
+ case FieldNodeType::Constant: {
+ const FieldConstant &field_constant = static_cast<const FieldConstant &>(field.node());
+ r_varrays[out_index] = GVArray::ForSingleRef(
+ field_constant.type(), mask.min_array_size(), field_constant.value().get());
+ break;
+ }
+ case FieldNodeType::Operation: {
+ break;
+ }
}
- const FieldInput &field_input = static_cast<const FieldInput &>(field.node());
- const int field_input_index = field_tree_info.deduplicated_field_inputs.index_of(field_input);
- const GVArray &varray = field_context_inputs[field_input_index];
- r_varrays[out_index] = varray;
}
Set<GFieldRef> varying_fields = find_varying_fields(field_tree_info, field_context_inputs);
@@ -491,9 +527,8 @@ GField make_field_constant_if_possible(GField field)
GField make_constant_field(const CPPType &type, const void *value)
{
- auto constant_fn = std::make_unique<CustomMF_GenericConstant>(type, value, true);
- auto operation = std::make_shared<FieldOperation>(std::move(constant_fn));
- return GField{std::move(operation), 0};
+ auto constant_node = std::make_shared<FieldConstant>(type, value);
+ return GField{std::move(constant_node)};
}
GVArray FieldContext::get_varray_for_input(const FieldInput &field_input,
@@ -602,7 +637,7 @@ static std::shared_ptr<const FieldInputs> combine_field_inputs(Span<GField> fiel
}
FieldOperation::FieldOperation(const MultiFunction &function, Vector<GField> inputs)
- : FieldNode(false), function_(&function), inputs_(std::move(inputs))
+ : FieldNode(FieldNodeType::Operation), function_(&function), inputs_(std::move(inputs))
{
field_inputs_ = combine_field_inputs(inputs_);
}
@@ -612,7 +647,7 @@ FieldOperation::FieldOperation(const MultiFunction &function, Vector<GField> inp
*/
FieldInput::FieldInput(const CPPType &type, std::string debug_name)
- : FieldNode(true), type_(&type), debug_name_(std::move(debug_name))
+ : FieldNode(FieldNodeType::Input), type_(&type), debug_name_(std::move(debug_name))
{
std::shared_ptr<FieldInputs> field_inputs = std::make_shared<FieldInputs>();
field_inputs->nodes.add_new(this);
@@ -621,6 +656,40 @@ FieldInput::FieldInput(const CPPType &type, std::string debug_name)
}
/* --------------------------------------------------------------------
+ * FieldConstant.
+ */
+
+FieldConstant::FieldConstant(const CPPType &type, const void *value)
+ : FieldNode(FieldNodeType::Constant), type_(type)
+{
+ value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
+ type.copy_construct(value, value_);
+}
+
+FieldConstant::~FieldConstant()
+{
+ type_.destruct(value_);
+ MEM_freeN(value_);
+}
+
+const CPPType &FieldConstant::output_cpp_type(int output_index) const
+{
+ BLI_assert(output_index == 0);
+ UNUSED_VARS_NDEBUG(output_index);
+ return type_;
+}
+
+const CPPType &FieldConstant::type() const
+{
+ return type_;
+}
+
+GPointer FieldConstant::value() const
+{
+ return {type_, value_};
+}
+
+/* --------------------------------------------------------------------
* FieldEvaluator.
*/
diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc
index 0cbec35ec7a..965c09984fa 100644
--- a/source/blender/geometry/intern/mesh_to_curve_convert.cc
+++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc
@@ -16,6 +16,7 @@
#include "BLI_array.hh"
#include "BLI_set.hh"
+#include "BLI_string_ref.hh"
#include "BLI_task.hh"
#include "DNA_mesh_types.h"
@@ -41,11 +42,22 @@ static void copy_attribute_to_points(const VArray<T> &source_data,
}
}
-static void copy_attributes_to_points(CurveEval &curve,
- const MeshComponent &mesh_component,
- Span<Vector<int>> point_to_vert_maps)
+static std::unique_ptr<CurveEval> create_curve_from_vert_indices(
+ const MeshComponent &mesh_component, Span<Vector<int>> vert_indices, IndexRange cyclic_splines)
{
- MutableSpan<SplinePtr> splines = curve.splines();
+ std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+ curve->resize(vert_indices.size());
+
+ MutableSpan<SplinePtr> splines = curve->splines();
+
+ for (const int i : vert_indices.index_range()) {
+ splines[i] = std::make_unique<PolySpline>();
+ splines[i]->resize(vert_indices[i].size());
+ }
+ for (const int i : cyclic_splines) {
+ splines[i]->set_cyclic(true);
+ }
+
Set<bke::AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids();
/* Copy builtin control point attributes. */
@@ -54,27 +66,44 @@ static void copy_attributes_to_points(CurveEval &curve,
"tilt", ATTR_DOMAIN_POINT, 0.0f);
threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
for (const int i : range) {
- copy_attribute_to_points<float>(
- tilt_attribute, point_to_vert_maps[i], splines[i]->tilts());
+ copy_attribute_to_points<float>(tilt_attribute, vert_indices[i], splines[i]->tilts());
}
});
source_attribute_ids.remove_contained("tilt");
}
+ else {
+ for (SplinePtr &spline : splines) {
+ spline->tilts().fill(0.0f);
+ }
+ }
+
if (source_attribute_ids.contains("radius")) {
const VArray<float> radius_attribute = mesh_component.attribute_get_for_read<float>(
"radius", ATTR_DOMAIN_POINT, 1.0f);
threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) {
for (const int i : range) {
- copy_attribute_to_points<float>(
- radius_attribute, point_to_vert_maps[i], splines[i]->radii());
+ copy_attribute_to_points<float>(radius_attribute, vert_indices[i], splines[i]->radii());
}
});
source_attribute_ids.remove_contained("radius");
}
+ else {
+ for (SplinePtr &spline : splines) {
+ spline->radii().fill(1.0f);
+ }
+ }
+
+ VArray<float3> mesh_positions = mesh_component.attribute_get_for_read(
+ "position", ATTR_DOMAIN_POINT, float3(0));
+ threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ copy_attribute_to_points(mesh_positions, vert_indices[i], splines[i]->positions());
+ }
+ });
for (const bke::AttributeIDRef &attribute_id : source_attribute_ids) {
- /* Don't copy attributes that are built-in on meshes but not on curves. */
if (mesh_component.attribute_is_builtin(attribute_id)) {
+ /* Don't copy attributes that are built-in on meshes but not on curves. */
continue;
}
@@ -104,24 +133,27 @@ static void copy_attributes_to_points(CurveEval &curve,
attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) {
using T = decltype(dummy);
copy_attribute_to_points<T>(
- mesh_attribute.typed<T>(), point_to_vert_maps[i], spline_attribute->typed<T>());
+ mesh_attribute.typed<T>(), vert_indices[i], spline_attribute->typed<T>());
});
}
});
}
- curve.assert_valid_point_attributes();
+ curve->assert_valid_point_attributes();
+ return curve;
}
struct CurveFromEdgesOutput {
- std::unique_ptr<CurveEval> curve;
- Vector<Vector<int>> point_to_vert_maps;
+ /** The indices in the mesh for each control point of each result splines. */
+ Vector<Vector<int>> vert_indices;
+ /** A subset of splines that should be set cyclic. */
+ IndexRange cyclic_splines;
};
-static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int, int>> edges)
+static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts,
+ Span<std::pair<int, int>> edges)
{
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- Vector<Vector<int>> point_to_vert_maps;
+ Vector<Vector<int>> vert_indices;
/* Compute the number of edges connecting to each vertex. */
Array<int> neighbor_count(verts.size(), 0);
@@ -173,19 +205,15 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int
continue;
}
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- Vector<int> point_to_vert_map;
-
- spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
- point_to_vert_map.append(current_vert);
+ Vector<int> spline_indices;
+ spline_indices.append(current_vert);
/* Follow connected edges until we read a vertex with more than two connected edges. */
while (true) {
int last_vert = current_vert;
current_vert = next_vert;
- spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
- point_to_vert_map.append(current_vert);
+ spline_indices.append(current_vert);
unused_edges[current_vert]--;
unused_edges[last_vert]--;
@@ -199,12 +227,13 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int
next_vert = (last_vert == next_a) ? next_b : next_a;
}
- spline->attributes.reallocate(spline->size());
- curve->add_spline(std::move(spline));
- point_to_vert_maps.append(std::move(point_to_vert_map));
+ vert_indices.append(std::move(spline_indices));
}
}
+ /* All splines added after this are cyclic. */
+ const int cyclic_start = vert_indices.size();
+
/* All remaining edges are part of cyclic splines (we skipped vertices with two edges before). */
for (const int start_vert : verts.index_range()) {
if (unused_edges[start_vert] != 2) {
@@ -214,20 +243,16 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int
int current_vert = start_vert;
int next_vert = neighbors[neighbor_offsets[current_vert]];
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- Vector<int> point_to_vert_map;
- spline->set_cyclic(true);
+ Vector<int> spline_indices;
- spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
- point_to_vert_map.append(current_vert);
+ spline_indices.append(current_vert);
/* Follow connected edges until we loop back to the start vertex. */
while (next_vert != start_vert) {
const int last_vert = current_vert;
current_vert = next_vert;
- spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
- point_to_vert_map.append(current_vert);
+ spline_indices.append(current_vert);
unused_edges[current_vert]--;
unused_edges[last_vert]--;
@@ -237,13 +262,12 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int
next_vert = (last_vert == next_a) ? next_b : next_a;
}
- spline->attributes.reallocate(spline->size());
- curve->add_spline(std::move(spline));
- point_to_vert_maps.append(std::move(point_to_vert_map));
+ vert_indices.append(std::move(spline_indices));
}
- curve->attributes.reallocate(curve->splines().size());
- return {std::move(curve), std::move(point_to_vert_maps)};
+ const int final_size = vert_indices.size();
+
+ return {std::move(vert_indices), IndexRange(cyclic_start, final_size - cyclic_start)};
}
/**
@@ -266,9 +290,11 @@ std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_compo
const Mesh &mesh = *mesh_component.get_for_read();
Vector<std::pair<int, int>> selected_edges = get_selected_edges(*mesh_component.get_for_read(),
selection);
- CurveFromEdgesOutput output = edges_to_curve({mesh.mvert, mesh.totvert}, selected_edges);
- copy_attributes_to_points(*output.curve, mesh_component, output.point_to_vert_maps);
- return std::move(output.curve);
+ CurveFromEdgesOutput output = edges_to_curve_point_indices({mesh.mvert, mesh.totvert},
+ selected_edges);
+
+ return create_curve_from_vert_indices(
+ mesh_component, output.vert_indices, output.cyclic_splines);
}
} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
index ae513bf88e9..4022794d53f 100644
--- a/source/blender/geometry/intern/realize_instances.cc
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -1167,7 +1167,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index];
const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index];
const std::optional<GSpan> src_span_opt = src_point_attributes.get_for_read(attribute_id);
- void *dst_buffer = MEM_malloc_arrayN(spline_size, cpp_type.size(), __func__);
+ void *dst_buffer = MEM_malloc_arrayN(spline_size, cpp_type.size(), "Curve Attribute");
if (src_span_opt.has_value()) {
const GSpan src_span = *src_span_opt;
cpp_type.copy_construct_n(src_span.data(), dst_buffer, spline_size);
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
index f6a85919de4..c583a45a27d 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c
@@ -40,6 +40,8 @@
#include "MOD_gpencil_modifiertypes.h"
#include "MOD_gpencil_util.h"
+#include "DEG_depsgraph_query.h"
+
void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
{
#define INIT_GP_TYPE(typeName) \
@@ -73,7 +75,7 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
bool is_stroke_affected_by_modifier(Object *ob,
char *mlayername,
- const Material *material,
+ Material *material,
const int mpassindex,
const int gpl_passindex,
const int minpoints,
@@ -84,8 +86,8 @@ bool is_stroke_affected_by_modifier(Object *ob,
const bool inv3,
const bool inv4)
{
- Material *ma = BKE_gpencil_material(ob, gps->mat_nr + 1);
- MaterialGPencilStyle *gp_style = ma->gp_style;
+ Material *ma_gps = BKE_gpencil_material(ob, gps->mat_nr + 1);
+ MaterialGPencilStyle *gp_style = ma_gps->gp_style;
/* omit if filter by layer */
if (mlayername[0] != '\0') {
@@ -102,13 +104,16 @@ bool is_stroke_affected_by_modifier(Object *ob,
}
/* Omit if filter by material. */
if (material != NULL) {
+ /* Requires to use the original material to compare the same pointer address. */
+ Material *ma_md_orig = (Material *)DEG_get_original_id(&material->id);
+ Material *ma_gps_orig = (Material *)DEG_get_original_id(&ma_gps->id);
if (inv4 == false) {
- if (material != ma) {
+ if (ma_md_orig != ma_gps_orig) {
return false;
}
}
else {
- if (material == ma) {
+ if (ma_md_orig == ma_gps_orig) {
return false;
}
}
diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
index 59ed11a02f3..722574929c0 100644
--- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
+++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h
@@ -34,7 +34,7 @@ struct bGPDstroke;
*/
bool is_stroke_affected_by_modifier(struct Object *ob,
char *mlayername,
- const struct Material *material,
+ struct Material *material,
const int mpassindex,
const int gpl_passindex,
const int minpoints,
diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
index 2ef72da03fd..dadeebeff0a 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
+++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h
@@ -450,10 +450,10 @@ typedef struct LineartBoundingArea {
ListBase up;
ListBase bp;
- int16_t triangle_count;
- int16_t max_triangle_count;
- int16_t line_count;
- int16_t max_line_count;
+ uint16_t triangle_count;
+ uint16_t max_triangle_count;
+ uint16_t line_count;
+ uint16_t max_line_count;
/* Use array for speeding up multiple accesses. */
struct LineartTriangle **linked_triangles;
diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
index d9a32711833..2f82a22754d 100644
--- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
+++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c
@@ -327,7 +327,12 @@ BLI_INLINE bool lineart_occlusion_is_adjacent_intersection(LineartEdge *e, Linea
static void lineart_bounding_area_triangle_add(LineartRenderBuffer *rb,
LineartBoundingArea *ba,
LineartTriangle *tri)
-{
+{ /* In case of too many triangles concentrating in one point, do not add anymore, these triangles
+ * will be either narrower than a single pixel, or will still be added into the list of other
+ * less dense areas. */
+ if (ba->triangle_count >= 65535) {
+ return;
+ }
if (ba->triangle_count >= ba->max_triangle_count) {
LineartTriangle **new_array = lineart_mem_acquire(
&rb->render_data_pool, sizeof(LineartTriangle *) * ba->max_triangle_count * 2);
@@ -343,6 +348,12 @@ static void lineart_bounding_area_line_add(LineartRenderBuffer *rb,
LineartBoundingArea *ba,
LineartEdge *e)
{
+ /* In case of too many lines concentrating in one point, do not add anymore, these lines will
+ * be either shorter than a single pixel, or will still be added into the list of other less
+ * dense areas. */
+ if (ba->line_count >= 65535) {
+ return;
+ }
if (ba->line_count >= ba->max_line_count) {
LineartEdge **new_array = lineart_mem_acquire(&rb->render_data_pool,
sizeof(LineartEdge *) * ba->max_line_count * 2);
@@ -1959,13 +1970,12 @@ static uchar lineart_intersection_mask_check(Collection *c, Object *ob)
}
}
- if (c->children.first == NULL) {
- if (BKE_collection_has_object(c, (Object *)(ob->id.orig_id))) {
- if (c->lineart_flags & COLLECTION_LRT_USE_INTERSECTION_MASK) {
- return c->lineart_intersection_mask;
- }
+ if (BKE_collection_has_object(c, (Object *)(ob->id.orig_id))) {
+ if (c->lineart_flags & COLLECTION_LRT_USE_INTERSECTION_MASK) {
+ return c->lineart_intersection_mask;
}
}
+
return 0;
}
@@ -2574,8 +2584,12 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl),
INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
}
else {
- INTERSECT_JUST_GREATER(is, order, is[LCross], LCross);
- INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ if (LCross >= 0) {
+ INTERSECT_JUST_GREATER(is, order, is[LCross], LCross);
+ if (LCross >= 0) {
+ INTERSECT_JUST_GREATER(is, order, is[LCross], RCross);
+ }
+ }
}
}
}
@@ -2930,15 +2944,7 @@ static LineartEdge *lineart_triangle_intersect(LineartRenderBuffer *rb,
result->intersection_mask = (tri->intersection_mask | testing->intersection_mask);
lineart_prepend_edge_direct(&rb->intersection.first, result);
- int r1, r2, c1, c2, row, col;
- if (lineart_get_edge_bounding_areas(rb, result, &r1, &r2, &c1, &c2)) {
- for (row = r1; row != r2 + 1; row++) {
- for (col = c1; col != c2 + 1; col++) {
- lineart_bounding_area_link_edge(
- rb, &rb->initial_bounding_areas[row * LRT_BA_ROWS + col], result);
- }
- }
- }
+
return result;
}
@@ -3409,7 +3415,6 @@ static void lineart_bounding_area_split(LineartRenderBuffer *rb,
LineartBoundingArea *ba = lineart_mem_acquire(&rb->render_data_pool,
sizeof(LineartBoundingArea) * 4);
LineartTriangle *tri;
- LineartEdge *e;
ba[0].l = root->cx;
ba[0].r = root->r;
@@ -3475,11 +3480,6 @@ static void lineart_bounding_area_split(LineartRenderBuffer *rb,
}
}
- for (int i = 0; i < root->line_count; i++) {
- e = root->linked_lines[i];
- lineart_bounding_area_link_edge(rb, root, e);
- }
-
rb->bounding_area_count += 3;
}
diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h
index 5189fa1ae41..5e67441be27 100644
--- a/source/blender/gpu/GPU_context.h
+++ b/source/blender/gpu/GPU_context.h
@@ -40,6 +40,8 @@ typedef enum eGPUBackendType {
void GPU_backend_init(eGPUBackendType backend);
void GPU_backend_exit(void);
+eGPUBackendType GPU_backend_get_type(void);
+
/** Opaque type hiding blender::gpu::Context. */
typedef struct GPUContext GPUContext;
diff --git a/source/blender/gpu/GPU_index_buffer.h b/source/blender/gpu/GPU_index_buffer.h
index e4f1709173e..0f83e590597 100644
--- a/source/blender/gpu/GPU_index_buffer.h
+++ b/source/blender/gpu/GPU_index_buffer.h
@@ -53,6 +53,8 @@ void GPU_indexbuf_init_ex(GPUIndexBufBuilder *, GPUPrimType, uint index_len, uin
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len);
GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len);
+void GPU_indexbuf_init_build_on_device(GPUIndexBuf *elem, uint index_len);
+
/*
* Thread safe.
*
@@ -82,6 +84,16 @@ void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, GPUIndexBuf *);
void GPU_indexbuf_bind_as_ssbo(GPUIndexBuf *elem, int binding);
+/* Upload data to the GPU (if not built on the device) and bind the buffer to its default target.
+ */
+void GPU_indexbuf_use(GPUIndexBuf *elem);
+
+/* Partially update the GPUIndexBuf which was already sent to the device, or built directly on the
+ * device. The data needs to be compatible with potential compression applied to the original
+ * indices when the index buffer was built, i.e., if the data was compressed to use shorts instead
+ * of ints, shorts should passed here. */
+void GPU_indexbuf_update_sub(GPUIndexBuf *elem, uint start, uint len, const void *data);
+
/* Create a sub-range of an existing index-buffer. */
GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length);
void GPU_indexbuf_create_subrange_in_place(GPUIndexBuf *elem,
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index ea3028e539b..f7a01fadadc 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -24,6 +24,7 @@
#pragma once
#include "DNA_customdata_types.h" /* for CustomDataType */
+#include "DNA_image_types.h"
#include "DNA_listBase.h"
#include "BLI_sys_types.h" /* for bool */
@@ -256,7 +257,8 @@ typedef struct GPUMaterialAttribute {
typedef struct GPUMaterialTexture {
struct GPUMaterialTexture *next, *prev;
struct Image *ima;
- struct ImageUser *iuser;
+ struct ImageUser iuser;
+ bool iuser_available;
struct GPUTexture **colorband;
char sampler_name[32]; /* Name of sampler in GLSL. */
char tiled_mapping_name[32]; /* Name of tile mapping sampler in GLSL. */
diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h
index fa70a8934db..7b69012dcbc 100644
--- a/source/blender/gpu/GPU_state.h
+++ b/source/blender/gpu/GPU_state.h
@@ -40,9 +40,11 @@ typedef enum eGPUBarrier {
GPU_BARRIER_SHADER_IMAGE_ACCESS = (1 << 0),
GPU_BARRIER_TEXTURE_FETCH = (1 << 1),
GPU_BARRIER_SHADER_STORAGE = (1 << 2),
+ GPU_BARRIER_VERTEX_ATTRIB_ARRAY = (1 << 3),
+ GPU_BARRIER_ELEMENT_ARRAY = (1 << 4),
} eGPUBarrier;
-ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_SHADER_STORAGE)
+ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_ELEMENT_ARRAY)
/**
* Defines the fixed pipeline blending equation.
diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h
index 62a495abfb3..43a8e7fc4cb 100644
--- a/source/blender/gpu/GPU_vertex_buffer.h
+++ b/source/blender/gpu/GPU_vertex_buffer.h
@@ -91,6 +91,8 @@ void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts);
void GPU_vertbuf_init_with_format_ex(GPUVertBuf *, const GPUVertFormat *, GPUUsageType);
+void GPU_vertbuf_init_build_on_device(GPUVertBuf *verts, GPUVertFormat *format, uint v_len);
+
#define GPU_vertbuf_init_with_format(verts, format) \
GPU_vertbuf_init_with_format_ex(verts, format, GPU_USAGE_STATIC)
@@ -172,6 +174,7 @@ const GPUVertFormat *GPU_vertbuf_get_format(const GPUVertBuf *verts);
uint GPU_vertbuf_get_vertex_alloc(const GPUVertBuf *verts);
uint GPU_vertbuf_get_vertex_len(const GPUVertBuf *verts);
GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts);
+void GPU_vertbuf_tag_dirty(GPUVertBuf *verts);
/**
* Should be rename to #GPU_vertbuf_data_upload.
@@ -179,12 +182,14 @@ GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts);
void GPU_vertbuf_use(GPUVertBuf *);
void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding);
+void GPU_vertbuf_wrap_handle(GPUVertBuf *verts, uint64_t handle);
+
/**
* XXX: do not use!
* This is just a wrapper for the use of the Hair refine workaround.
* To be used with #GPU_vertbuf_use().
*/
-void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data);
+void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, const void *data);
/* Metrics */
uint GPU_vertbuf_get_memory_usage(void);
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index 5af15d1bc3d..98714269402 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -186,6 +186,15 @@ void GPU_backend_exit()
g_backend = nullptr;
}
+eGPUBackendType GPU_backend_get_type()
+{
+ if (g_backend && dynamic_cast<GLBackend *>(g_backend) != nullptr) {
+ return GPU_BACKEND_OPENGL;
+ }
+
+ return GPU_BACKEND_NONE;
+}
+
GPUBackend *GPUBackend::get()
{
return g_backend;
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc
index 3404eb67e28..5b1eac2e82f 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.cc
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -563,7 +563,7 @@ static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs)
GPUOffScreen *GPU_offscreen_create(
int width, int height, bool depth, eGPUTextureFormat format, char err_out[256])
{
- GPUOffScreen *ofs = (GPUOffScreen *)MEM_callocN(sizeof(GPUOffScreen), __func__);
+ GPUOffScreen *ofs = MEM_cnew<GPUOffScreen>(__func__);
/* Sometimes areas can have 0 height or width and this will
* create a 1D texture which we don't want. */
diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc
index 3472cc24a74..895b2a8461b 100644
--- a/source/blender/gpu/intern/gpu_index_buffer.cc
+++ b/source/blender/gpu/intern/gpu_index_buffer.cc
@@ -74,11 +74,16 @@ void GPU_indexbuf_init(GPUIndexBufBuilder *builder,
GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len)
{
GPUIndexBuf *elem_ = GPU_indexbuf_calloc();
- IndexBuf *elem = unwrap(elem_);
- elem->init_build_on_device(index_len);
+ GPU_indexbuf_init_build_on_device(elem_, index_len);
return elem_;
}
+void GPU_indexbuf_init_build_on_device(GPUIndexBuf *elem, uint index_len)
+{
+ IndexBuf *elem_ = unwrap(elem);
+ elem_->init_build_on_device(index_len);
+}
+
void GPU_indexbuf_join(GPUIndexBufBuilder *builder_to, const GPUIndexBufBuilder *builder_from)
{
BLI_assert(builder_to->data == builder_from->data);
@@ -410,9 +415,19 @@ int GPU_indexbuf_primitive_len(GPUPrimType prim_type)
return indices_per_primitive(prim_type);
}
+void GPU_indexbuf_use(GPUIndexBuf *elem)
+{
+ unwrap(elem)->upload_data();
+}
+
void GPU_indexbuf_bind_as_ssbo(GPUIndexBuf *elem, int binding)
{
unwrap(elem)->bind_as_ssbo(binding);
}
+void GPU_indexbuf_update_sub(GPUIndexBuf *elem, uint start, uint len, const void *data)
+{
+ unwrap(elem)->update_sub(start, len, data);
+}
+
/** \} */
diff --git a/source/blender/gpu/intern/gpu_index_buffer_private.hh b/source/blender/gpu/intern/gpu_index_buffer_private.hh
index ed7dd830c8c..adc0145f867 100644
--- a/source/blender/gpu/intern/gpu_index_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_index_buffer_private.hh
@@ -92,11 +92,15 @@ class IndexBuf {
return is_init_;
};
+ virtual void upload_data(void) = 0;
+
virtual void bind_as_ssbo(uint binding) = 0;
virtual const uint32_t *read() const = 0;
uint32_t *unmap(const uint32_t *mapped_memory) const;
+ virtual void update_sub(uint start, uint len, const void *data) = 0;
+
private:
inline void squeeze_indices_short(uint min_idx, uint max_idx);
inline uint index_range(uint *r_min, uint *r_max);
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index 50ff450ac79..e0d60aa5fda 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -439,7 +439,10 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph,
if (tex == NULL) {
tex = MEM_callocN(sizeof(*tex), __func__);
tex->ima = ima;
- tex->iuser = iuser;
+ if (iuser != NULL) {
+ tex->iuser = *iuser;
+ tex->iuser_available = true;
+ }
tex->colorband = colorband;
tex->sampler_state = sampler_state;
BLI_snprintf(tex->sampler_name, sizeof(tex->sampler_name), "samp%d", num_textures);
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index 1b6cb196534..3f5a639d2a0 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -339,7 +339,7 @@ void GPU_shader_bind(GPUShader *gpu_shader)
}
}
-void GPU_shader_unbind(void)
+void GPU_shader_unbind()
{
#ifndef NDEBUG
Context *ctx = Context::get();
diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc
index 1648446d21b..937f49ccaec 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.cc
+++ b/source/blender/gpu/intern/gpu_shader_interface.cc
@@ -74,6 +74,8 @@ void ShaderInterface::sort_inputs()
sort_input_list(MutableSpan<ShaderInput>(inputs_, attr_len_));
sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_, ubo_len_));
sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_));
+ sort_input_list(
+ MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_ + uniform_len_, ssbo_len_));
}
void ShaderInterface::debug_print()
diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc
index c7e2043b790..1b8b28bf04c 100644
--- a/source/blender/gpu/intern/gpu_texture.cc
+++ b/source/blender/gpu/intern/gpu_texture.cc
@@ -190,7 +190,7 @@ using namespace blender::gpu;
/* ------ Memory Management ------ */
-uint GPU_texture_memory_usage_get(void)
+uint GPU_texture_memory_usage_get()
{
/* TODO(fclem): Do that inside the new Texture class. */
return 0;
@@ -424,7 +424,7 @@ void GPU_texture_unbind(GPUTexture *tex_)
Context::get()->state_manager->texture_unbind(tex);
}
-void GPU_texture_unbind_all(void)
+void GPU_texture_unbind_all()
{
Context::get()->state_manager->texture_unbind_all();
}
@@ -439,7 +439,7 @@ void GPU_texture_image_unbind(GPUTexture *tex)
Context::get()->state_manager->image_unbind(unwrap(tex));
}
-void GPU_texture_image_unbind_all(void)
+void GPU_texture_image_unbind_all()
{
Context::get()->state_manager->image_unbind_all();
}
@@ -613,7 +613,7 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *r_size)
* Override texture sampler state for one sampler unit only.
* \{ */
-void GPU_samplers_update(void)
+void GPU_samplers_update()
{
GPUBackend::get()->samplers_update();
}
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc
index 5ed9648387f..dba31f501f2 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.cc
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc
@@ -144,6 +144,12 @@ void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts_,
unwrap(verts_)->init(format, usage);
}
+void GPU_vertbuf_init_build_on_device(GPUVertBuf *verts, GPUVertFormat *format, uint v_len)
+{
+ GPU_vertbuf_init_with_format_ex(verts, format, GPU_USAGE_DEVICE_ONLY);
+ GPU_vertbuf_data_alloc(verts, v_len);
+}
+
GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts_)
{
return wrap(unwrap(verts_)->duplicate());
@@ -313,6 +319,11 @@ GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts)
return unwrap(verts)->flag;
}
+void GPU_vertbuf_tag_dirty(GPUVertBuf *verts)
+{
+ unwrap(verts)->flag |= GPU_VERTBUF_DATA_DIRTY;
+}
+
uint GPU_vertbuf_get_memory_usage()
{
return VertBuf::memory_usage;
@@ -323,12 +334,17 @@ void GPU_vertbuf_use(GPUVertBuf *verts)
unwrap(verts)->upload();
}
+void GPU_vertbuf_wrap_handle(GPUVertBuf *verts, uint64_t handle)
+{
+ unwrap(verts)->wrap_handle(handle);
+}
+
void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding)
{
unwrap(verts)->bind_as_ssbo(binding);
}
-void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data)
+void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, const void *data)
{
unwrap(verts)->update_sub(start, len, data);
}
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
index 9531c2c1a5f..2f46295f45a 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
@@ -68,6 +68,8 @@ class VertBuf {
void upload(void);
virtual void bind_as_ssbo(uint binding) = 0;
+ virtual void wrap_handle(uint64_t handle) = 0;
+
VertBuf *duplicate(void);
/* Size of the data allocated. */
@@ -96,7 +98,7 @@ class VertBuf {
}
}
- virtual void update_sub(uint start, uint len, void *data) = 0;
+ virtual void update_sub(uint start, uint len, const void *data) = 0;
virtual const void *read() const = 0;
virtual void *unmap(const void *mapped_data) const = 0;
diff --git a/source/blender/gpu/opengl/gl_index_buffer.cc b/source/blender/gpu/opengl/gl_index_buffer.cc
index e305f765ad9..82bab460ae3 100644
--- a/source/blender/gpu/opengl/gl_index_buffer.cc
+++ b/source/blender/gpu/opengl/gl_index_buffer.cc
@@ -81,4 +81,14 @@ bool GLIndexBuf::is_active() const
return ibo_id_ == active_ibo_id;
}
+void GLIndexBuf::upload_data()
+{
+ bind();
+}
+
+void GLIndexBuf::update_sub(uint start, uint len, const void *data)
+{
+ glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, start, len, data);
+}
+
} // namespace blender::gpu
diff --git a/source/blender/gpu/opengl/gl_index_buffer.hh b/source/blender/gpu/opengl/gl_index_buffer.hh
index 0dbdaa6d398..85d52447bc6 100644
--- a/source/blender/gpu/opengl/gl_index_buffer.hh
+++ b/source/blender/gpu/opengl/gl_index_buffer.hh
@@ -61,6 +61,10 @@ class GLIndexBuf : public IndexBuf {
return (index_type_ == GPU_INDEX_U16) ? 0xFFFFu : 0xFFFFFFFFu;
}
+ void upload_data(void) override;
+
+ void update_sub(uint start, uint len, const void *data) override;
+
private:
bool is_active() const;
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index cd2c3caad46..8367b0de02b 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -47,7 +47,7 @@ GLShader::GLShader(const char *name) : Shader(name)
{
#if 0 /* Would be nice to have, but for now the Deferred compilation \
* does not have a GPUContext. */
- BLI_assert(GLContext::get() != NULL);
+ BLI_assert(GLContext::get() != nullptr);
#endif
shader_program_ = glCreateProgram();
@@ -58,7 +58,7 @@ GLShader::~GLShader()
{
#if 0 /* Would be nice to have, but for now the Deferred compilation \
* does not have a GPUContext. */
- BLI_assert(GLContext::get() != NULL);
+ BLI_assert(GLContext::get() != nullptr);
#endif
/* Invalid handles are silently ignored. */
glDeleteShader(vert_shader_);
diff --git a/source/blender/gpu/opengl/gl_state.hh b/source/blender/gpu/opengl/gl_state.hh
index 979644b41c9..f5c38a33628 100644
--- a/source/blender/gpu/opengl/gl_state.hh
+++ b/source/blender/gpu/opengl/gl_state.hh
@@ -130,6 +130,12 @@ static inline GLbitfield to_gl(eGPUBarrier barrier_bits)
if (barrier_bits & GPU_BARRIER_SHADER_STORAGE) {
barrier |= GL_SHADER_STORAGE_BARRIER_BIT;
}
+ if (barrier_bits & GPU_BARRIER_VERTEX_ATTRIB_ARRAY) {
+ barrier |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
+ }
+ if (barrier_bits & GPU_BARRIER_ELEMENT_ARRAY) {
+ barrier |= GL_ELEMENT_ARRAY_BARRIER_BIT;
+ }
return barrier;
}
diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.cc b/source/blender/gpu/opengl/gl_vertex_buffer.cc
index ce16a491528..469ac2cf8d6 100644
--- a/source/blender/gpu/opengl/gl_vertex_buffer.cc
+++ b/source/blender/gpu/opengl/gl_vertex_buffer.cc
@@ -49,6 +49,10 @@ void GLVertBuf::resize_data()
void GLVertBuf::release_data()
{
+ if (is_wrapper_) {
+ return;
+ }
+
if (vbo_id_ != 0) {
GLContext::buf_free(vbo_id_);
vbo_id_ = 0;
@@ -137,6 +141,16 @@ void *GLVertBuf::unmap(const void *mapped_data) const
return result;
}
+void GLVertBuf::wrap_handle(uint64_t handle)
+{
+ BLI_assert(vbo_id_ == 0);
+ BLI_assert(glIsBuffer(static_cast<uint>(handle)));
+ is_wrapper_ = true;
+ vbo_id_ = static_cast<uint>(handle);
+ /* We assume the data is already on the device, so no need to allocate or send it. */
+ flag = GPU_VERTBUF_DATA_UPLOADED;
+}
+
bool GLVertBuf::is_active() const
{
if (!vbo_id_) {
@@ -147,7 +161,7 @@ bool GLVertBuf::is_active() const
return vbo_id_ == active_vbo_id;
}
-void GLVertBuf::update_sub(uint start, uint len, void *data)
+void GLVertBuf::update_sub(uint start, uint len, const void *data)
{
glBufferSubData(GL_ARRAY_BUFFER, start, len, data);
}
diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.hh b/source/blender/gpu/opengl/gl_vertex_buffer.hh
index 6c38a2225b3..27e4cc4f8e2 100644
--- a/source/blender/gpu/opengl/gl_vertex_buffer.hh
+++ b/source/blender/gpu/opengl/gl_vertex_buffer.hh
@@ -39,17 +39,22 @@ class GLVertBuf : public VertBuf {
private:
/** OpenGL buffer handle. Init on first upload. Immutable after that. */
GLuint vbo_id_ = 0;
+ /** Defines whether the buffer handle is wrapped by this GLVertBuf, i.e. we do not own it and
+ * should not free it. */
+ bool is_wrapper_ = false;
/** Size on the GPU. */
size_t vbo_size_ = 0;
public:
void bind(void);
- void update_sub(uint start, uint len, void *data) override;
+ void update_sub(uint start, uint len, const void *data) override;
const void *read() const override;
void *unmap(const void *mapped_data) const override;
+ void wrap_handle(uint64_t handle) override;
+
protected:
void acquire_data(void) override;
void resize_data(void) override;
diff --git a/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl
index 5b6a890ccc8..91f986d23ad 100644
--- a/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl
@@ -5,11 +5,7 @@ uniform mat4 ModelMatrix;
#endif
in vec3 pos;
-#if defined(USE_COLOR_U32)
-in uint color;
-#else
in vec4 color;
-#endif
flat out vec4 finalColor;
@@ -17,15 +13,7 @@ void main()
{
vec4 pos_4d = vec4(pos, 1.0);
gl_Position = ModelViewProjectionMatrix * pos_4d;
-
-#if defined(USE_COLOR_U32)
- finalColor = vec4(((color)&uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 8) & uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 16) & uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 24)) * (1.0f / 255.0f));
-#else
finalColor = color;
-#endif
#ifdef USE_WORLD_CLIP_PLANES
world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz);
diff --git a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
index 2033401db67..08623fa9935 100644
--- a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl
@@ -1,21 +1,9 @@
-#if defined(USE_COLOR_U32)
-uniform uint color;
-#else
uniform vec4 color;
-#endif
out vec4 fragColor;
void main()
{
-#if defined(USE_COLOR_U32)
- fragColor = vec4(((color)&uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 8) & uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 16) & uint(0xFF)) * (1.0f / 255.0f),
- ((color >> 24)) * (1.0f / 255.0f));
-#else
- fragColor = color;
-#endif
- fragColor = blender_srgb_to_framebuffer_space(fragColor);
+ fragColor = blender_srgb_to_framebuffer_space(color);
}
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index 949efb522f3..4a4e22ed884 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -284,7 +284,7 @@ static int initialize_chain(Object *ob, bPoseChannel *pchan_tip, bConstraint *co
/* setup the chain data */
/* create a target */
- target = (PoseTarget *)MEM_callocN(sizeof(PoseTarget), "posetarget");
+ target = MEM_cnew<PoseTarget>("posetarget");
target->con = con;
/* by construction there can be only one tree per channel
* and each channel can be part of at most one tree. */
@@ -292,7 +292,7 @@ static int initialize_chain(Object *ob, bPoseChannel *pchan_tip, bConstraint *co
if (tree == nullptr) {
/* make new tree */
- tree = (PoseTree *)MEM_callocN(sizeof(PoseTree), "posetree");
+ tree = MEM_cnew<PoseTree>("posetree");
tree->iterations = data->iterations;
tree->totchannel = segcount;
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index e1b9853ac21..ec8cf36dd49 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -683,7 +683,7 @@ static bool imb_exr_multilayer_parse_channels_from_file(ExrHandle *data);
void *IMB_exr_get_handle(void)
{
- ExrHandle *data = (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
+ ExrHandle *data = MEM_cnew<ExrHandle>("exr handle");
data->multiView = new StringVector();
BLI_addtail(&exrhandles, data);
@@ -789,7 +789,7 @@ void IMB_exr_add_channel(void *handle,
ExrHandle *data = (ExrHandle *)handle;
ExrChannel *echan;
- echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr channel");
+ echan = MEM_cnew<ExrChannel>("exr channel");
echan->m = new MultiViewChannelName();
if (layname && layname[0] != '\0') {
@@ -1496,7 +1496,7 @@ static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname)
ExrLayer *lay = (ExrLayer *)BLI_findstring(lb, layname, offsetof(ExrLayer, name));
if (lay == nullptr) {
- lay = (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer");
+ lay = MEM_cnew<ExrLayer>("exr layer");
BLI_addtail(lb, lay);
BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME);
}
@@ -1509,7 +1509,7 @@ static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
ExrPass *pass = (ExrPass *)BLI_findstring(lb, passname, offsetof(ExrPass, name));
if (pass == nullptr) {
- pass = (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass");
+ pass = MEM_cnew<ExrPass>("exr pass");
if (STREQ(passname, "Combined")) {
BLI_addhead(lb, pass);
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
index 3e071a9e4d7..e1c451a8412 100644
--- a/source/blender/imbuf/intern/transform.cc
+++ b/source/blender/imbuf/intern/transform.cc
@@ -305,19 +305,22 @@ class Sampler {
void sample(const ImBuf *source, const float u, const float v, SampleType &r_sample)
{
- const float wrapped_u = uv_wrapper.modify_u(source, u);
- const float wrapped_v = uv_wrapper.modify_v(source, v);
-
if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float> &&
NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
bilinear_interpolation_color_fl(source, nullptr, &r_sample[0], wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_NEAREST &&
std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
nearest_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_BILINEAR &&
std::is_same_v<StorageType, unsigned char> && NumChannels == 4) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
bilinear_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v);
}
else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float>) {
@@ -326,6 +329,8 @@ class Sampler {
source->rect_float, &r_sample[0], source->x, source->y, NumChannels, u, v, true, true);
}
else {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
BLI_bilinear_interpolation_fl(source->rect_float,
&r_sample[0],
source->x,
@@ -336,6 +341,8 @@ class Sampler {
}
}
else if constexpr (Filter == IMB_FILTER_NEAREST && std::is_same_v<StorageType, float>) {
+ const float wrapped_u = uv_wrapper.modify_u(source, u);
+ const float wrapped_v = uv_wrapper.modify_v(source, v);
sample_nearest_float(source, wrapped_u, wrapped_v, r_sample);
}
else {
diff --git a/source/blender/io/CMakeLists.txt b/source/blender/io/CMakeLists.txt
index f11ad7627b9..b97b3ef97de 100644
--- a/source/blender/io/CMakeLists.txt
+++ b/source/blender/io/CMakeLists.txt
@@ -19,6 +19,7 @@
# ***** END GPL LICENSE BLOCK *****
add_subdirectory(common)
+add_subdirectory(wavefront_obj)
if(WITH_ALEMBIC)
add_subdirectory(alembic)
diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp
index 870db4a15d3..49a4b22dbc3 100644
--- a/source/blender/io/collada/AnimationImporter.cpp
+++ b/source/blender/io/collada/AnimationImporter.cpp
@@ -237,7 +237,7 @@ void AnimationImporter::add_fcurves_to_object(Main *bmain,
/* no matching groups, so add one */
if (grp == nullptr) {
/* Add a new group, and make it active */
- grp = (bActionGroup *)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
+ grp = MEM_cnew<bActionGroup>("bActionGroup");
grp->flag = AGRP_SELECTED;
BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
@@ -2177,7 +2177,7 @@ void AnimationImporter::add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurv
/* no matching groups, so add one */
if (grp == nullptr) {
/* Add a new group, and make it active */
- grp = (bActionGroup *)MEM_callocN(sizeof(bActionGroup), "bActionGroup");
+ grp = MEM_cnew<bActionGroup>("bActionGroup");
grp->flag = AGRP_SELECTED;
BLI_strncpy(grp->name, bone_name, sizeof(grp->name));
diff --git a/source/blender/io/collada/Materials.cpp b/source/blender/io/collada/Materials.cpp
index 1f358accc4e..6e17172f642 100644
--- a/source/blender/io/collada/Materials.cpp
+++ b/source/blender/io/collada/Materials.cpp
@@ -16,6 +16,8 @@
#include "Materials.h"
+#include "BKE_node_tree_update.h"
+
MaterialNode::MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map)
: mContext(C), material(ma), effect(nullptr), key_image_map(&key_image_map)
{
@@ -106,7 +108,7 @@ bNodeTree *MaterialNode::prepare_material_nodetree()
void MaterialNode::update_material_nodetree()
{
- ntreeUpdateTree(CTX_data_main(mContext), ntree);
+ BKE_ntree_update_main_tree(CTX_data_main(mContext), ntree, nullptr);
}
bNode *MaterialNode::add_node(int node_type, int locx, int locy, std::string label)
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 7539fba1343..c856e60c4b8 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc
@@ -238,7 +238,7 @@ void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl,
/* Get the thickness in pixels using a simple 1 point stroke. */
bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, false, false);
gps_temp->totpoints = 1;
- gps_temp->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points");
+ gps_temp->points = MEM_cnew<bGPDspoint>("gp_stroke_points");
const bGPDspoint *pt_src = &gps->points[0];
bGPDspoint *pt_dst = &gps_temp->points[0];
copy_v3_v3(&pt_dst->x, &pt_src->x);
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 09eac7a2813..3ca6ed6cd45 100644
--- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
+++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc
@@ -308,7 +308,7 @@ void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl,
/* Get the thickness in pixels using a simple 1 point stroke. */
bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, false, false);
gps_temp->totpoints = 1;
- gps_temp->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points");
+ gps_temp->points = MEM_cnew<bGPDspoint>("gp_stroke_points");
bGPDspoint *pt_src = &gps->points[0];
bGPDspoint *pt_dst = &gps_temp->points[0];
copy_v3_v3(&pt_dst->x, &pt_src->x);
diff --git a/source/blender/io/usd/intern/usd_reader_material.cc b/source/blender/io/usd/intern/usd_reader_material.cc
index db0c5785a68..645dea42971 100644
--- a/source/blender/io/usd/intern/usd_reader_material.cc
+++ b/source/blender/io/usd/intern/usd_reader_material.cc
@@ -23,6 +23,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BLI_math_vector.h"
#include "BLI_string.h"
@@ -339,7 +340,7 @@ void USDMaterialReader::import_usd_preview(Material *mtl,
nodeSetActive(ntree, output);
- ntreeUpdateTree(bmain_, ntree);
+ BKE_ntree_update_main_tree(bmain_, ntree, nullptr);
/* Optionally, set the material blend mode. */
diff --git a/source/blender/io/wavefront_obj/CMakeLists.txt b/source/blender/io/wavefront_obj/CMakeLists.txt
new file mode 100644
index 00000000000..190475c5550
--- /dev/null
+++ b/source/blender/io/wavefront_obj/CMakeLists.txt
@@ -0,0 +1,84 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ./exporter
+ ../../blenkernel
+ ../../blenlib
+ ../../bmesh
+ ../../bmesh/intern
+ ../../depsgraph
+ ../../editors/include
+ ../../makesdna
+ ../../makesrna
+ ../../nodes
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ IO_wavefront_obj.cc
+ exporter/obj_exporter.cc
+ exporter/obj_export_file_writer.cc
+ exporter/obj_export_mesh.cc
+ exporter/obj_export_mtl.cc
+ exporter/obj_export_nurbs.cc
+
+ IO_wavefront_obj.h
+ exporter/obj_exporter.hh
+ exporter/obj_export_file_writer.hh
+ exporter/obj_export_io.hh
+ exporter/obj_export_mesh.hh
+ exporter/obj_export_mtl.hh
+ exporter/obj_export_nurbs.hh
+)
+
+set(LIB
+ bf_blenkernel
+)
+
+blender_add_lib(bf_wavefront_obj "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_GTESTS)
+ set(TEST_SRC
+ tests/obj_exporter_tests.cc
+ tests/obj_exporter_tests.hh
+ )
+
+ set(TEST_INC
+ ${INC}
+
+ ../../blenloader
+ ../../../../tests/gtests
+ )
+
+ set(TEST_LIB
+ ${LIB}
+
+ bf_blenloader_tests
+ bf_wavefront_obj
+ )
+
+ include(GTestTesting)
+ blender_add_test_lib(bf_wavefront_obj_tests "${TEST_SRC}" "${TEST_INC}" "${INC_SYS}" "${TEST_LIB}")
+ add_dependencies(bf_wavefront_obj_tests bf_wavefront_obj)
+endif()
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.cc b/source/blender/io/wavefront_obj/IO_wavefront_obj.cc
new file mode 100644
index 00000000000..1c93eafe91a
--- /dev/null
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.cc
@@ -0,0 +1,34 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#include "BLI_timeit.hh"
+
+#include "IO_wavefront_obj.h"
+
+#include "obj_exporter.hh"
+
+/**
+ * C-interface for the exporter.
+ */
+void OBJ_export(bContext *C, const OBJExportParams *export_params)
+{
+ SCOPED_TIMER("OBJ export");
+ blender::io::obj::exporter_main(C, *export_params);
+}
diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
new file mode 100644
index 00000000000..25687fd957c
--- /dev/null
+++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h
@@ -0,0 +1,97 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#pragma once
+
+#include "BKE_context.h"
+#include "BLI_path_util.h"
+#include "DEG_depsgraph.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ OBJ_AXIS_X_UP = 0,
+ OBJ_AXIS_Y_UP = 1,
+ OBJ_AXIS_Z_UP = 2,
+ OBJ_AXIS_NEGATIVE_X_UP = 3,
+ OBJ_AXIS_NEGATIVE_Y_UP = 4,
+ OBJ_AXIS_NEGATIVE_Z_UP = 5,
+} eTransformAxisUp;
+
+typedef enum {
+ OBJ_AXIS_X_FORWARD = 0,
+ OBJ_AXIS_Y_FORWARD = 1,
+ OBJ_AXIS_Z_FORWARD = 2,
+ OBJ_AXIS_NEGATIVE_X_FORWARD = 3,
+ OBJ_AXIS_NEGATIVE_Y_FORWARD = 4,
+ OBJ_AXIS_NEGATIVE_Z_FORWARD = 5,
+} eTransformAxisForward;
+
+const int TOTAL_AXES = 3;
+
+struct OBJExportParams {
+ /** Full path to the destination .OBJ file. */
+ char filepath[FILE_MAX];
+
+ /** Full path to current blender file (used for comments in output). */
+ const char *blen_filepath;
+
+ /** Whether multiple frames should be exported. */
+ bool export_animation;
+ /** The first frame to be exported. */
+ int start_frame;
+ /** The last frame to be exported. */
+ int end_frame;
+
+ /* Geometry Transform options. */
+ eTransformAxisForward forward_axis;
+ eTransformAxisUp up_axis;
+ float scaling_factor;
+
+ /* File Write Options. */
+ bool export_selected_objects;
+ eEvaluationMode export_eval_mode;
+ bool export_uv;
+ bool export_normals;
+ bool export_materials;
+ bool export_triangulated_mesh;
+ bool export_curves_as_nurbs;
+
+ /* Grouping options. */
+ bool export_object_groups;
+ bool export_material_groups;
+ bool export_vertex_groups;
+ /**
+ * Calculate smooth groups from sharp edges.
+ */
+ bool export_smooth_groups;
+ /**
+ * Create bitflags instead of the default "0"/"1" group IDs.
+ */
+ bool smooth_groups_bitflags;
+};
+
+void OBJ_export(bContext *C, const struct OBJExportParams *export_params);
+
+#ifdef __cplusplus
+}
+#endif
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
new file mode 100644
index 00000000000..d92d1c5ad48
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc
@@ -0,0 +1,626 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#include <algorithm>
+#include <cstdio>
+
+#include "BKE_blender_version.h"
+
+#include "BLI_path_util.h"
+
+#include "obj_export_mesh.hh"
+#include "obj_export_mtl.hh"
+#include "obj_export_nurbs.hh"
+
+#include "obj_export_file_writer.hh"
+
+namespace blender::io::obj {
+/**
+ * Per reference http://www.martinreddy.net/gfx/3d/OBJ.spec:
+ * To turn off smoothing groups, use a value of 0 or off.
+ * Polygonal elements use group numbers to put elements in different smoothing groups.
+ * For free-form surfaces, smoothing groups are either turned on or off;
+ * there is no difference between values greater than 0.
+ */
+const int SMOOTH_GROUP_DISABLED = 0;
+const int SMOOTH_GROUP_DEFAULT = 1;
+
+const char *DEFORM_GROUP_DISABLED = "off";
+/* There is no deform group default name. Use what the user set in the UI. */
+
+/**
+ * Per reference http://www.martinreddy.net/gfx/3d/OBJ.spec:
+ * Once a material is assigned, it cannot be turned off; it can only be changed.
+ * If a material name is not specified, a white material is used.
+ * So an empty material name is written. */
+const char *MATERIAL_GROUP_DISABLED = "";
+
+/**
+ * Write one line of polygon indices as "f v1/vt1/vn1 v2/vt2/vn2 ...".
+ */
+void OBJWriter::write_vert_uv_normal_indices(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> normal_indices) const
+{
+ BLI_assert(vert_indices.size() == uv_indices.size() &&
+ vert_indices.size() == normal_indices.size());
+ file_handler_->write<eOBJSyntaxElement::poly_element_begin>();
+ for (int j = 0; j < vert_indices.size(); j++) {
+ file_handler_->write<eOBJSyntaxElement::vertex_uv_normal_indices>(
+ vert_indices[j] + index_offsets_.vertex_offset + 1,
+ uv_indices[j] + index_offsets_.uv_vertex_offset + 1,
+ normal_indices[j] + index_offsets_.normal_offset + 1);
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_element_end>();
+}
+
+/**
+ * Write one line of polygon indices as "f v1//vn1 v2//vn2 ...".
+ */
+void OBJWriter::write_vert_normal_indices(Span<int> vert_indices,
+ Span<int> /*uv_indices*/,
+ Span<int> normal_indices) const
+{
+ BLI_assert(vert_indices.size() == normal_indices.size());
+ file_handler_->write<eOBJSyntaxElement::poly_element_begin>();
+ for (int j = 0; j < vert_indices.size(); j++) {
+ file_handler_->write<eOBJSyntaxElement::vertex_normal_indices>(
+ vert_indices[j] + index_offsets_.vertex_offset + 1,
+ normal_indices[j] + index_offsets_.normal_offset + 1);
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_element_end>();
+}
+
+/**
+ * Write one line of polygon indices as "f v1/vt1 v2/vt2 ...".
+ */
+void OBJWriter::write_vert_uv_indices(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> /*normal_indices*/) const
+{
+ BLI_assert(vert_indices.size() == uv_indices.size());
+ file_handler_->write<eOBJSyntaxElement::poly_element_begin>();
+ for (int j = 0; j < vert_indices.size(); j++) {
+ file_handler_->write<eOBJSyntaxElement::vertex_uv_indices>(
+ vert_indices[j] + index_offsets_.vertex_offset + 1,
+ uv_indices[j] + index_offsets_.uv_vertex_offset + 1);
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_element_end>();
+}
+
+/**
+ * Write one line of polygon indices as "f v1 v2 ...".
+ */
+void OBJWriter::write_vert_indices(Span<int> vert_indices,
+ Span<int> /*uv_indices*/,
+ Span<int> /*normal_indices*/) const
+{
+ file_handler_->write<eOBJSyntaxElement::poly_element_begin>();
+ for (const int vert_index : vert_indices) {
+ file_handler_->write<eOBJSyntaxElement::vertex_indices>(vert_index +
+ index_offsets_.vertex_offset + 1);
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_element_end>();
+}
+
+void OBJWriter::write_header() const
+{
+ using namespace std::string_literals;
+ file_handler_->write<eOBJSyntaxElement::string>("# Blender "s + BKE_blender_version_string() +
+ "\n");
+ file_handler_->write<eOBJSyntaxElement::string>("# www.blender.org\n");
+}
+
+/**
+ * Write file name of Material Library in .OBJ file.
+ */
+void OBJWriter::write_mtllib_name(const StringRefNull mtl_filepath) const
+{
+ /* Split .MTL file path into parent directory and filename. */
+ char mtl_file_name[FILE_MAXFILE];
+ char mtl_dir_name[FILE_MAXDIR];
+ BLI_split_dirfile(mtl_filepath.data(), mtl_dir_name, mtl_file_name, FILE_MAXDIR, FILE_MAXFILE);
+ file_handler_->write<eOBJSyntaxElement::mtllib>(mtl_file_name);
+}
+
+/**
+ * Write an object's group with mesh and/or material name appended conditionally.
+ */
+void OBJWriter::write_object_group(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) {
+ file_handler_->write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name +
+ "_" + object_material_name);
+ return;
+ }
+ file_handler_->write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name);
+}
+
+/**
+ * Write object's name or group.
+ */
+void OBJWriter::write_object_name(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(obj_mesh_data);
+ return;
+ }
+ file_handler_->write<eOBJSyntaxElement::object_name>(object_name);
+}
+
+/**
+ * Write vertex coordinates for all vertices as "v x y z".
+ */
+void OBJWriter::write_vertex_coords(const OBJMesh &obj_mesh_data) const
+{
+ const int tot_vertices = obj_mesh_data.tot_vertices();
+ for (int i = 0; i < tot_vertices; i++) {
+ float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor);
+ file_handler_->write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]);
+ }
+}
+
+/**
+ * Write UV vertex coordinates for all vertices as "vt u v".
+ * \note UV indices are stored here, but written later.
+ */
+void OBJWriter::write_uv_coords(OBJMesh &r_obj_mesh_data) const
+{
+ Vector<std::array<float, 2>> uv_coords;
+ /* UV indices are calculated and stored in an OBJMesh member here. */
+ r_obj_mesh_data.store_uv_coords_and_indices(uv_coords);
+
+ for (const std::array<float, 2> &uv_vertex : uv_coords) {
+ file_handler_->write<eOBJSyntaxElement::uv_vertex_coords>(uv_vertex[0], uv_vertex[1]);
+ }
+}
+
+/**
+ * Write loop normals for smooth-shaded polygons, and polygon normals otherwise, as "vn x y z".
+ */
+void OBJWriter::write_poly_normals(const OBJMesh &obj_mesh_data) const
+{
+ obj_mesh_data.ensure_mesh_normals();
+ Vector<float3> lnormals;
+ const int tot_polygons = obj_mesh_data.tot_polygons();
+ for (int i = 0; i < tot_polygons; i++) {
+ if (obj_mesh_data.is_ith_poly_smooth(i)) {
+ obj_mesh_data.calc_loop_normals(i, lnormals);
+ for (const float3 &lnormal : lnormals) {
+ file_handler_->write<eOBJSyntaxElement::normal>(lnormal[0], lnormal[1], lnormal[2]);
+ }
+ }
+ else {
+ float3 poly_normal = obj_mesh_data.calc_poly_normal(i);
+ file_handler_->write<eOBJSyntaxElement::normal>(
+ poly_normal[0], poly_normal[1], poly_normal[2]);
+ }
+ }
+}
+
+/**
+ * Write smooth group if polygon at the given index is shaded smooth else "s 0"
+ */
+int OBJWriter::write_smooth_group(const OBJMesh &obj_mesh_data,
+ const int poly_index,
+ const int last_poly_smooth_group) const
+{
+ int current_group = SMOOTH_GROUP_DISABLED;
+ if (!export_params_.export_smooth_groups && obj_mesh_data.is_ith_poly_smooth(poly_index)) {
+ /* Smooth group calculation is disabled, but polygon is smooth-shaded. */
+ current_group = SMOOTH_GROUP_DEFAULT;
+ }
+ else if (obj_mesh_data.is_ith_poly_smooth(poly_index)) {
+ /* Smooth group calc is enabled and polygon is smooth–shaded, so find the group. */
+ current_group = obj_mesh_data.ith_smooth_group(poly_index);
+ }
+
+ if (current_group == last_poly_smooth_group) {
+ /* Group has already been written, even if it is "s 0". */
+ return current_group;
+ }
+ file_handler_->write<eOBJSyntaxElement::smooth_group>(current_group);
+ return current_group;
+}
+
+/**
+ * Write material name and material group of a polygon in the .OBJ file.
+ * \return #mat_nr of the polygon at the given index.
+ * \note It doesn't write to the material library.
+ */
+int16_t OBJWriter::write_poly_material(const OBJMesh &obj_mesh_data,
+ const int poly_index,
+ const int16_t last_poly_mat_nr,
+ std::function<const char *(int)> matname_fn) const
+{
+ if (!export_params_.export_materials || obj_mesh_data.tot_materials() <= 0) {
+ return last_poly_mat_nr;
+ }
+ const int16_t current_mat_nr = obj_mesh_data.ith_poly_matnr(poly_index);
+ /* Whenever a polygon with a new material is encountered, write its material
+ * and/or group, otherwise pass. */
+ if (last_poly_mat_nr == current_mat_nr) {
+ return current_mat_nr;
+ }
+ if (current_mat_nr == NOT_FOUND) {
+ file_handler_->write<eOBJSyntaxElement::poly_usemtl>(MATERIAL_GROUP_DISABLED);
+ return current_mat_nr;
+ }
+ if (export_params_.export_object_groups) {
+ write_object_group(obj_mesh_data);
+ }
+ const char *mat_name = matname_fn(current_mat_nr);
+ if (!mat_name) {
+ mat_name = MATERIAL_GROUP_DISABLED;
+ }
+ file_handler_->write<eOBJSyntaxElement::poly_usemtl>(mat_name);
+
+ return current_mat_nr;
+}
+
+/**
+ * Write the name of the deform group of a polygon.
+ */
+int16_t OBJWriter::write_vertex_group(const OBJMesh &obj_mesh_data,
+ const int poly_index,
+ const int16_t last_poly_vertex_group) const
+{
+ if (!export_params_.export_vertex_groups) {
+ return last_poly_vertex_group;
+ }
+ const int16_t current_group = obj_mesh_data.get_poly_deform_group_index(poly_index);
+
+ if (current_group == last_poly_vertex_group) {
+ /* No vertex group found in this polygon, just like in the last iteration. */
+ return current_group;
+ }
+ if (current_group == NOT_FOUND) {
+ file_handler_->write<eOBJSyntaxElement::object_group>(DEFORM_GROUP_DISABLED);
+ return current_group;
+ }
+ file_handler_->write<eOBJSyntaxElement::object_group>(
+ obj_mesh_data.get_poly_deform_group_name(current_group));
+ return current_group;
+}
+
+/**
+ * \return Writer function with appropriate polygon-element syntax.
+ */
+OBJWriter::func_vert_uv_normal_indices OBJWriter::get_poly_element_writer(
+ const int total_uv_vertices) const
+{
+ if (export_params_.export_normals) {
+ if (export_params_.export_uv && (total_uv_vertices > 0)) {
+ /* Write both normals and UV indices. */
+ return &OBJWriter::write_vert_uv_normal_indices;
+ }
+ /* Write normals indices. */
+ return &OBJWriter::write_vert_normal_indices;
+ }
+ /* Write UV indices. */
+ if (export_params_.export_uv && (total_uv_vertices > 0)) {
+ return &OBJWriter::write_vert_uv_indices;
+ }
+ /* Write neither normals nor UV indices. */
+ return &OBJWriter::write_vert_indices;
+}
+
+/**
+ * Write polygon elements with at least vertex indices, and conditionally with UV vertex
+ * indices and polygon normal indices. Also write groups: smooth, vertex, material.
+ * The matname_fn turns a 0-indexed material slot number in an Object into the
+ * name used in the .obj file.
+ * \note UV indices were stored while writing UV vertices.
+ */
+void OBJWriter::write_poly_elements(const OBJMesh &obj_mesh_data,
+ std::function<const char *(int)> matname_fn)
+{
+ int last_poly_smooth_group = NEGATIVE_INIT;
+ int16_t last_poly_vertex_group = NEGATIVE_INIT;
+ int16_t last_poly_mat_nr = NEGATIVE_INIT;
+
+ const func_vert_uv_normal_indices poly_element_writer = get_poly_element_writer(
+ obj_mesh_data.tot_uv_vertices());
+
+ /* Number of normals may not be equal to number of polygons due to smooth shading. */
+ int per_object_tot_normals = 0;
+ const int tot_polygons = obj_mesh_data.tot_polygons();
+ for (int i = 0; i < tot_polygons; i++) {
+ 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);
+ /* For an Object, a normal index depends on how many of its normals have been written before
+ * it. This is unknown because of smooth shading. So pass "per object total normals"
+ * and update it after each call. */
+ int new_normals = 0;
+ Vector<int> poly_normal_indices;
+ std::tie(new_normals, poly_normal_indices) = obj_mesh_data.calc_poly_normal_indices(
+ i, per_object_tot_normals);
+ per_object_tot_normals += new_normals;
+
+ last_poly_smooth_group = write_smooth_group(obj_mesh_data, i, last_poly_smooth_group);
+ last_poly_vertex_group = write_vertex_group(obj_mesh_data, i, last_poly_vertex_group);
+ last_poly_mat_nr = write_poly_material(obj_mesh_data, i, last_poly_mat_nr, matname_fn);
+ (this->*poly_element_writer)(poly_vertex_indices, poly_uv_indices, poly_normal_indices);
+ }
+ /* Unusual: Other indices are updated in #OBJWriter::update_index_offsets. */
+ index_offsets_.normal_offset += per_object_tot_normals;
+}
+
+/**
+ * Write loose edges of a mesh as "l v1 v2".
+ */
+void OBJWriter::write_edges_indices(const OBJMesh &obj_mesh_data) const
+{
+ obj_mesh_data.ensure_mesh_edges();
+ const int tot_edges = obj_mesh_data.tot_edges();
+ for (int edge_index = 0; edge_index < tot_edges; edge_index++) {
+ const std::optional<std::array<int, 2>> vertex_indices =
+ obj_mesh_data.calc_loose_edge_vert_indices(edge_index);
+ if (!vertex_indices) {
+ continue;
+ }
+ file_handler_->write<eOBJSyntaxElement::edge>(
+ (*vertex_indices)[0] + index_offsets_.vertex_offset + 1,
+ (*vertex_indices)[1] + index_offsets_.vertex_offset + 1);
+ }
+}
+
+/**
+ * Write a NURBS curve to the .OBJ file in parameter form.
+ */
+void OBJWriter::write_nurbs_curve(const OBJCurve &obj_nurbs_data) const
+{
+ const int total_splines = obj_nurbs_data.total_splines();
+ for (int spline_idx = 0; spline_idx < total_splines; spline_idx++) {
+ const int total_vertices = obj_nurbs_data.total_spline_vertices(spline_idx);
+ for (int vertex_idx = 0; vertex_idx < total_vertices; vertex_idx++) {
+ const float3 vertex_coords = obj_nurbs_data.vertex_coordinates(
+ spline_idx, vertex_idx, export_params_.scaling_factor);
+ file_handler_->write<eOBJSyntaxElement::vertex_coords>(
+ vertex_coords[0], vertex_coords[1], vertex_coords[2]);
+ }
+
+ const char *nurbs_name = obj_nurbs_data.get_curve_name();
+ const int nurbs_degree = obj_nurbs_data.get_nurbs_degree(spline_idx);
+ file_handler_->write<eOBJSyntaxElement::object_group>(nurbs_name);
+ file_handler_->write<eOBJSyntaxElement::cstype>();
+ file_handler_->write<eOBJSyntaxElement::nurbs_degree>(nurbs_degree);
+ /**
+ * The numbers written here are indices into the vertex coordinates written
+ * earlier, relative to the line that is going to be written.
+ * [0.0 - 1.0] is the curve parameter range.
+ * 0.0 1.0 -1 -2 -3 -4 for a non-cyclic curve with 4 vertices.
+ * 0.0 1.0 -1 -2 -3 -4 -1 -2 -3 for a cyclic curve with 4 vertices.
+ */
+ const int total_control_points = obj_nurbs_data.total_spline_control_points(spline_idx);
+ file_handler_->write<eOBJSyntaxElement::curve_element_begin>();
+ for (int i = 0; i < total_control_points; i++) {
+ /* "+1" to keep indices one-based, even if they're negative: i.e., -1 refers to the
+ * last vertex coordinate, -2 second last. */
+ file_handler_->write<eOBJSyntaxElement::vertex_indices>(-((i % total_vertices) + 1));
+ }
+ file_handler_->write<eOBJSyntaxElement::curve_element_end>();
+
+ /**
+ * In "parm u 0 0.1 .." line:, (total control points + 2) equidistant numbers in the
+ * parameter range are inserted.
+ */
+ file_handler_->write<eOBJSyntaxElement::nurbs_parameter_begin>();
+ for (int i = 1; i <= total_control_points + 2; i++) {
+ file_handler_->write<eOBJSyntaxElement::nurbs_parameters>(1.0f * i /
+ (total_control_points + 2 + 1));
+ }
+ file_handler_->write<eOBJSyntaxElement::nurbs_parameter_end>();
+
+ file_handler_->write<eOBJSyntaxElement::nurbs_group_end>();
+ }
+}
+
+/**
+ * When there are multiple objects in a frame, the indices of previous objects' coordinates or
+ * normals add up.
+ */
+void OBJWriter::update_index_offsets(const OBJMesh &obj_mesh_data)
+{
+ index_offsets_.vertex_offset += obj_mesh_data.tot_vertices();
+ index_offsets_.uv_vertex_offset += obj_mesh_data.tot_uv_vertices();
+ /* Normal index is updated right after writing the normals. */
+}
+
+/* -------------------------------------------------------------------- */
+/** \name .MTL writers.
+ * \{ */
+
+/**
+ * Convert #float3 to string of space-separated numbers, with no leading or trailing space.
+ * Only to be used in NON-performance-critical code.
+ */
+static std::string float3_to_string(const float3 &numbers)
+{
+ std::ostringstream r_string;
+ r_string << numbers[0] << " " << numbers[1] << " " << numbers[2];
+ return r_string.str();
+};
+
+/*
+ * Create the .MTL file.
+ */
+MTLWriter::MTLWriter(const char *obj_filepath) noexcept(false)
+{
+ mtl_filepath_ = obj_filepath;
+ const bool ok = BLI_path_extension_replace(mtl_filepath_.data(), FILE_MAX, ".mtl");
+ if (!ok) {
+ throw std::system_error(ENAMETOOLONG, std::system_category(), "");
+ }
+ file_handler_ = std::make_unique<FileHandler<eFileType::MTL>>(mtl_filepath_);
+}
+
+void MTLWriter::write_header(const char *blen_filepath) const
+{
+ using namespace std::string_literals;
+ const char *blen_basename = (blen_filepath && blen_filepath[0] != '\0') ?
+ BLI_path_basename(blen_filepath) :
+ "None";
+ file_handler_->write<eMTLSyntaxElement::string>("# Blender "s + BKE_blender_version_string() +
+ " MTL File: '" + blen_basename + "'\n");
+ file_handler_->write<eMTLSyntaxElement::string>("# www.blender.org\n");
+}
+
+StringRefNull MTLWriter::mtl_file_path() const
+{
+ return mtl_filepath_;
+}
+
+/**
+ * Write properties sourced from p-BSDF node or #Object.Material.
+ */
+void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl_material)
+{
+ file_handler_->write<eMTLSyntaxElement::Ns>(mtl_material.Ns);
+ file_handler_->write<eMTLSyntaxElement::Ka>(
+ mtl_material.Ka.x, mtl_material.Ka.y, mtl_material.Ka.z);
+ file_handler_->write<eMTLSyntaxElement::Kd>(
+ mtl_material.Kd.x, mtl_material.Kd.y, mtl_material.Kd.z);
+ file_handler_->write<eMTLSyntaxElement::Ks>(
+ mtl_material.Ks.x, mtl_material.Ks.y, mtl_material.Ks.z);
+ file_handler_->write<eMTLSyntaxElement::Ke>(
+ mtl_material.Ke.x, mtl_material.Ke.y, mtl_material.Ke.z);
+ file_handler_->write<eMTLSyntaxElement::Ni>(mtl_material.Ni);
+ file_handler_->write<eMTLSyntaxElement::d>(mtl_material.d);
+ file_handler_->write<eMTLSyntaxElement::illum>(mtl_material.illum);
+}
+
+/**
+ * Write a texture map in the form "map_XX -s 1. 1. 1. -o 0. 0. 0. [-bm 1.] path/to/image".
+ */
+void MTLWriter::write_texture_map(
+ const MTLMaterial &mtl_material,
+ const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map)
+{
+ std::string translation;
+ std::string scale;
+ std::string map_bump_strength;
+ /* Optional strings should have their own leading spaces. */
+ if (texture_map.value.translation != float3{0.0f, 0.0f, 0.0f}) {
+ translation.append(" -s ").append(float3_to_string(texture_map.value.translation));
+ }
+ if (texture_map.value.scale != float3{1.0f, 1.0f, 1.0f}) {
+ scale.append(" -o ").append(float3_to_string(texture_map.value.scale));
+ }
+ if (texture_map.key == eMTLSyntaxElement::map_Bump && mtl_material.map_Bump_strength > 0.0001f) {
+ map_bump_strength.append(" -bm ").append(std::to_string(mtl_material.map_Bump_strength));
+ }
+
+#define SYNTAX_DISPATCH(eMTLSyntaxElement) \
+ if (texture_map.key == eMTLSyntaxElement) { \
+ file_handler_->write<eMTLSyntaxElement>(translation + scale + map_bump_strength, \
+ texture_map.value.image_path); \
+ return; \
+ }
+
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Kd);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ks);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ns);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_d);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_refl);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ke);
+ SYNTAX_DISPATCH(eMTLSyntaxElement::map_Bump);
+
+ BLI_assert(!"This map type was not written to the file.");
+}
+
+/**
+ * Write all of the material specifications to the MTL file.
+ * For consistency of output from run to run (useful for testing),
+ * the materials are sorted by name before writing.
+ */
+void MTLWriter::write_materials()
+{
+ if (mtlmaterials_.size() == 0) {
+ return;
+ }
+ std::sort(mtlmaterials_.begin(),
+ mtlmaterials_.end(),
+ [](const MTLMaterial &a, const MTLMaterial &b) { return a.name < b.name; });
+ for (const MTLMaterial &mtlmat : mtlmaterials_) {
+ file_handler_->write<eMTLSyntaxElement::string>("\n");
+ file_handler_->write<eMTLSyntaxElement::newmtl>(mtlmat.name);
+ write_bsdf_properties(mtlmat);
+ for (const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map :
+ mtlmat.texture_maps.items()) {
+ if (!texture_map.value.image_path.empty()) {
+ write_texture_map(mtlmat, texture_map);
+ }
+ }
+ }
+}
+
+/**
+ * Add the materials of the given object to MTLWriter, deduping
+ * against ones that are already there.
+ * Return a Vector of indices into mtlmaterials_ that hold the MTLMaterial
+ * that corresponds to each material slot, in order, of the given Object.
+ * Indexes are returned rather than pointers to the MTLMaterials themselves
+ * because the mtlmaterials_ Vector may move around when resized.
+ */
+Vector<int> MTLWriter::add_materials(const OBJMesh &mesh_to_export)
+{
+ Vector<int> r_mtl_indices;
+ r_mtl_indices.resize(mesh_to_export.tot_materials());
+ for (int16_t i = 0; i < mesh_to_export.tot_materials(); i++) {
+ const Material *material = mesh_to_export.get_object_material(i);
+ if (!material) {
+ r_mtl_indices[i] = -1;
+ continue;
+ }
+ int mtlmat_index = material_map_.lookup_default(material, -1);
+ if (mtlmat_index != -1) {
+ r_mtl_indices[i] = mtlmat_index;
+ }
+ else {
+ mtlmaterials_.append(mtlmaterial_for_material(material));
+ r_mtl_indices[i] = mtlmaterials_.size() - 1;
+ material_map_.add_new(material, r_mtl_indices[i]);
+ }
+ }
+ return r_mtl_indices;
+}
+
+const char *MTLWriter::mtlmaterial_name(int index)
+{
+ if (index < 0 || index >= mtlmaterials_.size()) {
+ return nullptr;
+ }
+ return mtlmaterials_[index].name.c_str();
+}
+/** \} */
+
+} // namespace blender::io::obj
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
new file mode 100644
index 00000000000..36d35ae370b
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh
@@ -0,0 +1,132 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#pragma once
+
+#include "DNA_meshdata_types.h"
+
+#include "BLI_map.hh"
+#include "BLI_vector.hh"
+
+#include "IO_wavefront_obj.h"
+#include "obj_export_io.hh"
+#include "obj_export_mtl.hh"
+
+namespace blender::io::obj {
+
+class OBJCurve;
+class OBJMesh;
+/**
+ * Total vertices/ UV vertices/ normals of previous Objects
+ * should be added to the current Object's indices.
+ */
+struct IndexOffsets {
+ int vertex_offset;
+ int uv_vertex_offset;
+ int normal_offset;
+};
+
+/**
+ * Responsible for writing a .OBJ file.
+ */
+class OBJWriter : NonMovable, NonCopyable {
+ private:
+ const OBJExportParams &export_params_;
+ std::unique_ptr<FileHandler<eFileType::OBJ>> file_handler_ = nullptr;
+ IndexOffsets index_offsets_{0, 0, 0};
+
+ public:
+ OBJWriter(const char *filepath, const OBJExportParams &export_params) noexcept(false)
+ : export_params_(export_params)
+ {
+ file_handler_ = std::make_unique<FileHandler<eFileType::OBJ>>(filepath);
+ }
+
+ void write_header() const;
+
+ void write_object_name(const OBJMesh &obj_mesh_data) const;
+ void write_object_group(const OBJMesh &obj_mesh_data) const;
+ void write_mtllib_name(const StringRefNull mtl_filepath) const;
+ void write_vertex_coords(const OBJMesh &obj_mesh_data) const;
+ void write_uv_coords(OBJMesh &obj_mesh_data) const;
+ void write_poly_normals(const OBJMesh &obj_mesh_data) const;
+ int write_smooth_group(const OBJMesh &obj_mesh_data,
+ int poly_index,
+ const int last_poly_smooth_group) const;
+ int16_t write_poly_material(const OBJMesh &obj_mesh_data,
+ const int poly_index,
+ const int16_t last_poly_mat_nr,
+ std::function<const char *(int)> matname_fn) const;
+ int16_t write_vertex_group(const OBJMesh &obj_mesh_data,
+ const int poly_index,
+ const int16_t last_poly_vertex_group) const;
+ void write_poly_elements(const OBJMesh &obj_mesh_data,
+ std::function<const char *(int)> matname_fn);
+ void write_edges_indices(const OBJMesh &obj_mesh_data) const;
+ void write_nurbs_curve(const OBJCurve &obj_nurbs_data) const;
+
+ void update_index_offsets(const OBJMesh &obj_mesh_data);
+
+ private:
+ using func_vert_uv_normal_indices = void (OBJWriter::*)(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> normal_indices) const;
+ func_vert_uv_normal_indices get_poly_element_writer(const int total_uv_vertices) const;
+
+ void write_vert_uv_normal_indices(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> normal_indices) const;
+ void write_vert_normal_indices(Span<int> vert_indices,
+ Span<int> /*uv_indices*/,
+ Span<int> normal_indices) const;
+ void write_vert_uv_indices(Span<int> vert_indices,
+ Span<int> uv_indices,
+ Span<int> /*normal_indices*/) const;
+ void write_vert_indices(Span<int> vert_indices,
+ Span<int> /*uv_indices*/,
+ Span<int> /*normal_indices*/) const;
+};
+
+/**
+ * Responsible for writing a .MTL file.
+ */
+class MTLWriter : NonMovable, NonCopyable {
+ private:
+ std::unique_ptr<FileHandler<eFileType::MTL>> file_handler_ = nullptr;
+ std::string mtl_filepath_;
+ Vector<MTLMaterial> mtlmaterials_;
+ /* Map from a Material* to an index into mtlmaterials_. */
+ Map<const Material *, int> material_map_;
+
+ public:
+ MTLWriter(const char *obj_filepath) noexcept(false);
+
+ void write_header(const char *blen_filepath) const;
+ void write_materials();
+ StringRefNull mtl_file_path() const;
+ Vector<int> add_materials(const OBJMesh &mesh_to_export);
+ const char *mtlmaterial_name(int index);
+
+ private:
+ void write_bsdf_properties(const MTLMaterial &mtl_material);
+ void write_texture_map(const MTLMaterial &mtl_material,
+ const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map);
+};
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
new file mode 100644
index 00000000000..83571d8aa46
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh
@@ -0,0 +1,340 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#pragma once
+
+#include <cstdio>
+#include <string>
+#include <system_error>
+#include <type_traits>
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_string_ref.hh"
+#include "BLI_utility_mixins.hh"
+
+namespace blender::io::obj {
+
+enum class eFileType {
+ OBJ,
+ MTL,
+};
+
+enum class eOBJSyntaxElement {
+ vertex_coords,
+ uv_vertex_coords,
+ normal,
+ poly_element_begin,
+ vertex_uv_normal_indices,
+ vertex_normal_indices,
+ vertex_uv_indices,
+ vertex_indices,
+ poly_element_end,
+ poly_usemtl,
+ edge,
+ cstype,
+ nurbs_degree,
+ curve_element_begin,
+ curve_element_end,
+ nurbs_parameter_begin,
+ nurbs_parameters,
+ nurbs_parameter_end,
+ nurbs_group_end,
+ new_line,
+ mtllib,
+ smooth_group,
+ object_group,
+ object_name,
+ /* Use rarely. New line is NOT included for string. */
+ string,
+};
+
+enum class eMTLSyntaxElement {
+ newmtl,
+ Ni,
+ d,
+ Ns,
+ illum,
+ Ka,
+ Kd,
+ Ks,
+ Ke,
+ map_Kd,
+ map_Ks,
+ map_Ns,
+ map_d,
+ map_refl,
+ map_Ke,
+ map_Bump,
+ /* Use rarely. New line is NOT included for string. */
+ string,
+};
+
+template<eFileType filetype> struct FileTypeTraits;
+
+template<> struct FileTypeTraits<eFileType::OBJ> {
+ using SyntaxType = eOBJSyntaxElement;
+};
+
+template<> struct FileTypeTraits<eFileType::MTL> {
+ using SyntaxType = eMTLSyntaxElement;
+};
+
+template<eFileType type> struct Formatting {
+ const char *fmt = nullptr;
+ const int total_args = 0;
+ /* Fail to compile by default. */
+ const bool is_type_valid = false;
+};
+
+/**
+ * Type dependent but always false. Use to add a conditional compile-time error.
+ */
+template<typename T> struct always_false : std::false_type {
+};
+
+template<typename... T>
+constexpr bool is_type_float = (... && std::is_floating_point_v<std::decay_t<T>>);
+
+template<typename... T>
+constexpr bool is_type_integral = (... && std::is_integral_v<std::decay_t<T>>);
+
+template<typename... T>
+constexpr bool is_type_string_related = (... && std::is_constructible_v<std::string, T>);
+
+template<eFileType filetype, typename... T>
+constexpr std::enable_if_t<filetype == eFileType::OBJ, Formatting<filetype>>
+syntax_elem_to_formatting(const eOBJSyntaxElement key)
+{
+ switch (key) {
+ case eOBJSyntaxElement::vertex_coords: {
+ return {"v %f %f %f\n", 3, is_type_float<T...>};
+ }
+ case eOBJSyntaxElement::uv_vertex_coords: {
+ return {"vt %f %f\n", 2, is_type_float<T...>};
+ }
+ case eOBJSyntaxElement::normal: {
+ return {"vn %f %f %f\n", 3, is_type_float<T...>};
+ }
+ case eOBJSyntaxElement::poly_element_begin: {
+ return {"f", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::vertex_uv_normal_indices: {
+ return {" %d/%d/%d", 3, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::vertex_normal_indices: {
+ return {" %d//%d", 2, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::vertex_uv_indices: {
+ return {" %d/%d", 2, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::vertex_indices: {
+ return {" %d", 1, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::poly_usemtl: {
+ return {"usemtl %s\n", 1, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::edge: {
+ return {"l %d %d\n", 2, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::cstype: {
+ return {"cstype bspline\n", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_degree: {
+ return {"deg %d\n", 1, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::curve_element_begin: {
+ return {"curv 0.0 1.0", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_parameter_begin: {
+ return {"parm 0.0", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_parameters: {
+ return {" %f", 1, is_type_float<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_parameter_end: {
+ return {" 1.0\n", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::nurbs_group_end: {
+ return {"end\n", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::poly_element_end: {
+ ATTR_FALLTHROUGH;
+ }
+ case eOBJSyntaxElement::curve_element_end: {
+ ATTR_FALLTHROUGH;
+ }
+ case eOBJSyntaxElement::new_line: {
+ return {"\n", 0, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::mtllib: {
+ return {"mtllib %s\n", 1, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::smooth_group: {
+ return {"s %d\n", 1, is_type_integral<T...>};
+ }
+ case eOBJSyntaxElement::object_group: {
+ return {"g %s\n", 1, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::object_name: {
+ return {"o %s\n", 1, is_type_string_related<T...>};
+ }
+ case eOBJSyntaxElement::string: {
+ return {"%s", 1, is_type_string_related<T...>};
+ }
+ }
+}
+
+template<eFileType filetype, typename... T>
+constexpr std::enable_if_t<filetype == eFileType::MTL, Formatting<filetype>>
+syntax_elem_to_formatting(const eMTLSyntaxElement key)
+{
+ switch (key) {
+ case eMTLSyntaxElement::newmtl: {
+ return {"newmtl %s\n", 1, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::Ni: {
+ return {"Ni %.6f\n", 1, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::d: {
+ return {"d %.6f\n", 1, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::Ns: {
+ return {"Ns %.6f\n", 1, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::illum: {
+ return {"illum %d\n", 1, is_type_integral<T...>};
+ }
+ case eMTLSyntaxElement::Ka: {
+ return {"Ka %.6f %.6f %.6f\n", 3, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::Kd: {
+ return {"Kd %.6f %.6f %.6f\n", 3, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::Ks: {
+ return {"Ks %.6f %.6f %.6f\n", 3, is_type_float<T...>};
+ }
+ case eMTLSyntaxElement::Ke: {
+ return {"Ke %.6f %.6f %.6f\n", 3, is_type_float<T...>};
+ }
+ /* Keep only one space between options since filepaths may have leading spaces too. */
+ case eMTLSyntaxElement::map_Kd: {
+ return {"map_Kd %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_Ks: {
+ return {"map_Ks %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_Ns: {
+ return {"map_Ns %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_d: {
+ return {"map_d %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_refl: {
+ return {"map_refl %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_Ke: {
+ return {"map_Ke %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::map_Bump: {
+ return {"map_Bump %s %s\n", 2, is_type_string_related<T...>};
+ }
+ case eMTLSyntaxElement::string: {
+ return {"%s", 1, is_type_string_related<T...>};
+ }
+ }
+}
+
+template<eFileType filetype> class FileHandler : NonCopyable, NonMovable {
+ private:
+ FILE *outfile_ = nullptr;
+ std::string outfile_path_;
+
+ public:
+ FileHandler(std::string outfile_path) noexcept(false) : outfile_path_(std::move(outfile_path))
+ {
+ outfile_ = std::fopen(outfile_path_.c_str(), "w");
+ if (!outfile_) {
+ throw std::system_error(errno, std::system_category(), "Cannot open file");
+ }
+ }
+
+ ~FileHandler()
+ {
+ if (outfile_ && std::fclose(outfile_)) {
+ std::cerr << "Error: could not close the file '" << outfile_path_
+ << "' properly, it may be corrupted." << std::endl;
+ }
+ }
+
+ template<typename FileTypeTraits<filetype>::SyntaxType key, typename... T>
+ constexpr void write(T &&...args) const
+ {
+ constexpr Formatting<filetype> fmt_nargs_valid = syntax_elem_to_formatting<filetype, T...>(
+ key);
+ write__impl<fmt_nargs_valid.total_args>(fmt_nargs_valid.fmt, std::forward<T>(args)...);
+ /* Types of all arguments and the number of arguments should match
+ * what the formatting specifies. */
+ return std::enable_if_t < fmt_nargs_valid.is_type_valid &&
+ (sizeof...(T) == fmt_nargs_valid.total_args),
+ void > ();
+ }
+
+ private:
+ /* Remove this after upgrading to C++20. */
+ template<typename T> using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
+
+ /**
+ * Make #std::string etc., usable for fprintf-family.
+ * \return: `const char *` or the original argument if the argument is
+ * not related to #std::string.
+ */
+ template<typename T> constexpr auto string_to_primitive(T &&arg) const
+ {
+ if constexpr (std::is_same_v<remove_cvref_t<T>, std::string> ||
+ std::is_same_v<remove_cvref_t<T>, blender::StringRefNull>) {
+ return arg.c_str();
+ }
+ else if constexpr (std::is_same_v<remove_cvref_t<T>, blender::StringRef>) {
+ BLI_STATIC_ASSERT(
+ (always_false<T>::value),
+ "Null-terminated string not present. Please use blender::StringRefNull instead.");
+ /* Another trick to cause a compile-time error: returning nothing to #std::printf. */
+ return;
+ }
+ else {
+ return std::forward<T>(arg);
+ }
+ }
+
+ template<int total_args, typename... T>
+ constexpr std::enable_if_t<(total_args != 0), void> write__impl(const char *fmt,
+ T &&...args) const
+ {
+ std::fprintf(outfile_, fmt, string_to_primitive(std::forward<T>(args))...);
+ }
+ template<int total_args, typename... T>
+ constexpr std::enable_if_t<(total_args == 0), void> write__impl(const char *fmt,
+ T &&...args) const
+ {
+ std::fputs(fmt, outfile_);
+ }
+};
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
new file mode 100644
index 00000000000..0947d1132b0
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
@@ -0,0 +1,489 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_lib_id.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "obj_export_mesh.hh"
+
+namespace blender::io::obj {
+/**
+ * Store evaluated Object and Mesh pointers. Conditionally triangulate a mesh, or
+ * create a new Mesh from a Curve.
+ */
+OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Object *mesh_object)
+{
+ export_object_eval_ = DEG_get_evaluated_object(depsgraph, mesh_object);
+ export_mesh_eval_ = BKE_object_get_evaluated_mesh(export_object_eval_);
+ mesh_eval_needs_free_ = false;
+
+ if (!export_mesh_eval_) {
+ /* Curves and NURBS surfaces need a new mesh when they're
+ * exported in the form of vertices and edges.
+ */
+ export_mesh_eval_ = BKE_mesh_new_from_object(depsgraph, export_object_eval_, true, true);
+ /* Since a new mesh been allocated, it needs to be freed in the destructor. */
+ mesh_eval_needs_free_ = true;
+ }
+ if (export_params.export_triangulated_mesh &&
+ ELEM(export_object_eval_->type, OB_MESH, OB_SURF)) {
+ std::tie(export_mesh_eval_, mesh_eval_needs_free_) = triangulate_mesh_eval();
+ }
+ set_world_axes_transform(export_params.forward_axis, export_params.up_axis);
+}
+
+/**
+ * Free new meshes allocated for triangulated meshes, or Curve converted to Mesh.
+ */
+OBJMesh::~OBJMesh()
+{
+ free_mesh_if_needed();
+ if (poly_smooth_groups_) {
+ MEM_freeN(poly_smooth_groups_);
+ }
+}
+
+/**
+ * Free the mesh if _the exporter_ created it.
+ */
+void OBJMesh::free_mesh_if_needed()
+{
+ if (mesh_eval_needs_free_ && export_mesh_eval_) {
+ BKE_id_free(nullptr, export_mesh_eval_);
+ }
+}
+
+/**
+ * Allocate a new Mesh with triangulated polygons.
+ *
+ * The returned mesh can be the same as the old one.
+ * \return Owning pointer to the new Mesh, and whether a new Mesh was created.
+ */
+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};
+ /* Lower threshold where triangulation of a polygon starts, i.e. a quadrilateral will be
+ * triangulated here. */
+ const int triangulate_min_verts = 4;
+
+ unique_bmesh_ptr bmesh(
+ BKE_mesh_to_bmesh_ex(export_mesh_eval_, &bm_create_params, &bm_convert_params));
+ BM_mesh_triangulate(bmesh.get(),
+ MOD_TRIANGULATE_NGON_BEAUTY,
+ MOD_TRIANGULATE_QUAD_SHORTEDGE,
+ triangulate_min_verts,
+ false,
+ nullptr,
+ nullptr,
+ nullptr);
+
+ Mesh *triangulated = BKE_mesh_from_bmesh_for_eval_nomain(
+ bmesh.get(), nullptr, export_mesh_eval_);
+ free_mesh_if_needed();
+ return {triangulated, true};
+}
+
+/**
+ * Set the final transform after applying axes settings and an Object's world transform.
+ */
+void OBJMesh::set_world_axes_transform(const eTransformAxisForward forward,
+ const eTransformAxisUp up)
+{
+ float axes_transform[3][3];
+ unit_m3(axes_transform);
+ /* +Y-forward and +Z-up are the default Blender axis settings. */
+ mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform);
+ /* mat3_from_axis_conversion returns a transposed matrix! */
+ transpose_m3(axes_transform);
+ mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_->obmat);
+ /* 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];
+}
+
+int OBJMesh::tot_vertices() const
+{
+ return export_mesh_eval_->totvert;
+}
+
+int OBJMesh::tot_polygons() const
+{
+ return export_mesh_eval_->totpoly;
+}
+
+int OBJMesh::tot_uv_vertices() const
+{
+ return tot_uv_vertices_;
+}
+
+int OBJMesh::tot_edges() const
+{
+ return export_mesh_eval_->totedge;
+}
+
+/**
+ * \return Total materials in the object.
+ */
+int16_t OBJMesh::tot_materials() const
+{
+ return export_mesh_eval_->totcol;
+}
+
+/**
+ * \return Smooth group of the polygon at the given index.
+ */
+int OBJMesh::ith_smooth_group(const int poly_index) const
+{
+ /* Calculate smooth groups first: #OBJMesh::calc_smooth_groups. */
+ BLI_assert(tot_smooth_groups_ != -NEGATIVE_INIT);
+ BLI_assert(poly_smooth_groups_);
+ return poly_smooth_groups_[poly_index];
+}
+
+void OBJMesh::ensure_mesh_normals() const
+{
+ BKE_mesh_ensure_normals(export_mesh_eval_);
+ BKE_mesh_calc_normals_split(export_mesh_eval_);
+}
+
+void OBJMesh::ensure_mesh_edges() const
+{
+ BKE_mesh_calc_edges(export_mesh_eval_, true, false);
+ BKE_mesh_calc_edges_loose(export_mesh_eval_);
+}
+
+/**
+ * Calculate smooth groups of a smooth-shaded object.
+ * \return A polygon aligned array of smooth group numbers.
+ */
+void OBJMesh::calc_smooth_groups(const bool use_bitflags)
+{
+ poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(export_mesh_eval_->medge,
+ export_mesh_eval_->totedge,
+ export_mesh_eval_->mpoly,
+ export_mesh_eval_->totpoly,
+ export_mesh_eval_->mloop,
+ export_mesh_eval_->totloop,
+ &tot_smooth_groups_,
+ use_bitflags);
+}
+
+/**
+ * Return mat_nr-th material of the object. The given index should be zero-based.
+ */
+const Material *OBJMesh::get_object_material(const int16_t mat_nr) const
+{
+ /* "+ 1" as material getter needs one-based indices. */
+ const Material *r_mat = BKE_object_material_get(export_object_eval_, mat_nr + 1);
+#ifdef DEBUG
+ if (!r_mat) {
+ std::cerr << "Material not found for mat_nr = " << mat_nr << std::endl;
+ }
+#endif
+ return r_mat;
+}
+
+bool OBJMesh::is_ith_poly_smooth(const int poly_index) const
+{
+ return export_mesh_eval_->mpoly[poly_index].flag & ME_SMOOTH;
+}
+
+/**
+ * Returns a zero-based index of a polygon's material indexing into
+ * the Object's material slots.
+ */
+int16_t OBJMesh::ith_poly_matnr(const int poly_index) const
+{
+ BLI_assert(poly_index < export_mesh_eval_->totpoly);
+ const int16_t r_mat_nr = export_mesh_eval_->mpoly[poly_index].mat_nr;
+ return r_mat_nr >= 0 ? r_mat_nr : NOT_FOUND;
+}
+
+/**
+ * Get object name as it appears in the outliner.
+ */
+const char *OBJMesh::get_object_name() const
+{
+ return export_object_eval_->id.name + 2;
+}
+
+/**
+ * Get Object's Mesh's name.
+ */
+const char *OBJMesh::get_object_mesh_name() const
+{
+ return export_mesh_eval_->id.name + 2;
+}
+
+/**
+ * Get object's material (at the given index) name. The given index should be zero-based.
+ */
+const char *OBJMesh::get_object_material_name(const int16_t mat_nr) const
+{
+ const Material *mat = get_object_material(mat_nr);
+ if (!mat) {
+ return nullptr;
+ }
+ return mat->id.name + 2;
+}
+
+/**
+ * Calculate coordinates of the vertex at the given index.
+ */
+float3 OBJMesh::calc_vertex_coords(const int vert_index, const float scaling_factor) const
+{
+ 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);
+ return r_coords;
+}
+
+/**
+ * Calculate vertex indices of all vertices of the polygon at the given index.
+ */
+Vector<int> OBJMesh::calc_poly_vertex_indices(const int poly_index) const
+{
+ const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
+ const MLoop *mloop = &export_mesh_eval_->mloop[mpoly.loopstart];
+ const int totloop = mpoly.totloop;
+ Vector<int> r_poly_vertex_indices(totloop);
+ for (int loop_index = 0; loop_index < totloop; loop_index++) {
+ r_poly_vertex_indices[loop_index] = mloop[loop_index].v;
+ }
+ return r_poly_vertex_indices;
+}
+
+/**
+ * Calculate UV vertex coordinates of an Object.
+ *
+ * \note Also store the UV vertex indices in the member variable.
+ */
+void OBJMesh::store_uv_coords_and_indices(Vector<std::array<float, 2>> &r_uv_coords)
+{
+ const MPoly *mpoly = export_mesh_eval_->mpoly;
+ const MLoop *mloop = export_mesh_eval_->mloop;
+ const int totpoly = export_mesh_eval_->totpoly;
+ const int totvert = export_mesh_eval_->totvert;
+ const MLoopUV *mloopuv = static_cast<MLoopUV *>(
+ CustomData_get_layer(&export_mesh_eval_->ldata, CD_MLOOPUV));
+ if (!mloopuv) {
+ tot_uv_vertices_ = 0;
+ return;
+ }
+ const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
+
+ UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(
+ mpoly, mloop, mloopuv, totpoly, totvert, limit, false, false);
+
+ uv_indices_.resize(totpoly);
+ /* At least total vertices of a mesh will be present in its texture map. So
+ * reserve minimum space early. */
+ r_uv_coords.reserve(totvert);
+
+ tot_uv_vertices_ = 0;
+ for (int vertex_index = 0; vertex_index < totvert; vertex_index++) {
+ const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map, vertex_index);
+ for (; uv_vert; uv_vert = uv_vert->next) {
+ if (uv_vert->separate) {
+ tot_uv_vertices_ += 1;
+ }
+ const int vertices_in_poly = mpoly[uv_vert->poly_index].totloop;
+
+ /* Store UV vertex coordinates. */
+ r_uv_coords.resize(tot_uv_vertices_);
+ const int loopstart = mpoly[uv_vert->poly_index].loopstart;
+ Span<float> vert_uv_coords(mloopuv[loopstart + uv_vert->loop_of_poly_index].uv, 2);
+ r_uv_coords[tot_uv_vertices_ - 1][0] = vert_uv_coords[0];
+ r_uv_coords[tot_uv_vertices_ - 1][1] = vert_uv_coords[1];
+
+ /* Store UV vertex indices. */
+ uv_indices_[uv_vert->poly_index].resize(vertices_in_poly);
+ /* Keep indices zero-based and let the writer handle the "+ 1" as per OBJ spec. */
+ uv_indices_[uv_vert->poly_index][uv_vert->loop_of_poly_index] = tot_uv_vertices_ - 1;
+ }
+ }
+ BKE_mesh_uv_vert_map_free(uv_vert_map);
+}
+
+Span<int> OBJMesh::calc_poly_uv_indices(const int poly_index) const
+{
+ if (uv_indices_.size() <= 0) {
+ return {};
+ }
+ BLI_assert(poly_index < export_mesh_eval_->totpoly);
+ BLI_assert(poly_index < uv_indices_.size());
+ return uv_indices_[poly_index];
+}
+/**
+ * Calculate polygon normal of a polygon at given index.
+ *
+ * Should be used for flat-shaded polygons.
+ */
+float3 OBJMesh::calc_poly_normal(const int poly_index) const
+{
+ float3 r_poly_normal;
+ const MPoly &poly = export_mesh_eval_->mpoly[poly_index];
+ 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);
+ return r_poly_normal;
+}
+
+/**
+ * Calculate loop normals of a polygon at the given index.
+ *
+ * Should be used for smooth-shaded polygons.
+ */
+void OBJMesh::calc_loop_normals(const int poly_index, Vector<float3> &r_loop_normals) const
+{
+ r_loop_normals.clear();
+ const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
+ const float(
+ *lnors)[3] = (const float(*)[3])(CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL));
+ for (int loop_of_poly = 0; loop_of_poly < mpoly.totloop; loop_of_poly++) {
+ float3 loop_normal;
+ copy_v3_v3(loop_normal, lnors[mpoly.loopstart + loop_of_poly]);
+ mul_mat3_m4_v3(world_and_axes_transform_, loop_normal);
+ r_loop_normals.append(loop_normal);
+ }
+}
+
+/**
+ * Calculate a polygon's polygon/loop normal indices.
+ * \param object_tot_prev_normals Number of normals of this Object written so far.
+ * \return Number of distinct normal indices.
+ */
+std::pair<int, Vector<int>> OBJMesh::calc_poly_normal_indices(
+ const int poly_index, const int object_tot_prev_normals) const
+{
+ const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
+ const int totloop = mpoly.totloop;
+ Vector<int> r_poly_normal_indices(totloop);
+
+ if (is_ith_poly_smooth(poly_index)) {
+ for (int poly_loop_index = 0; poly_loop_index < totloop; poly_loop_index++) {
+ /* Using polygon loop index is fine because polygon/loop normals and their normal indices are
+ * written by looping over #Mesh.mpoly /#Mesh.mloop in the same order. */
+ r_poly_normal_indices[poly_loop_index] = object_tot_prev_normals + poly_loop_index;
+ }
+ /* For a smooth-shaded polygon, #Mesh.totloop -many loop normals are written. */
+ return {totloop, r_poly_normal_indices};
+ }
+ for (int poly_loop_index = 0; poly_loop_index < totloop; poly_loop_index++) {
+ r_poly_normal_indices[poly_loop_index] = object_tot_prev_normals;
+ }
+ /* For a flat-shaded polygon, one polygon normal is written. */
+ return {1, r_poly_normal_indices};
+}
+
+/**
+ * Find the index of the vertex group with the maximum number of vertices in a polygon.
+ * The index indices into the #Object.defbase.
+ *
+ * If two or more groups have the same number of vertices (maximum), group name depends on the
+ * implementation of #std::max_element.
+ */
+int16_t OBJMesh::get_poly_deform_group_index(const int poly_index) const
+{
+ BLI_assert(poly_index < export_mesh_eval_->totpoly);
+ const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index];
+ const MLoop *mloop = &export_mesh_eval_->mloop[mpoly.loopstart];
+ const Object *obj = export_object_eval_;
+ const int tot_deform_groups = BKE_object_defgroup_count(obj);
+ /* Indices of the vector index into deform groups of an object; values are the]
+ * number of vertex members in one deform group. */
+ Vector<int16_t> deform_group_members(tot_deform_groups, 0);
+ /* Whether at least one vertex in the polygon belongs to any group. */
+ bool found_group = false;
+
+ const MDeformVert *dvert_orig = static_cast<MDeformVert *>(
+ CustomData_get_layer(&export_mesh_eval_->vdata, CD_MDEFORMVERT));
+ if (!dvert_orig) {
+ return NOT_FOUND;
+ }
+
+ const MDeformWeight *curr_weight = nullptr;
+ const MDeformVert *dvert = nullptr;
+ for (int loop_index = 0; loop_index < mpoly.totloop; loop_index++) {
+ dvert = &dvert_orig[(mloop + loop_index)->v];
+ curr_weight = dvert->dw;
+ if (curr_weight) {
+ bDeformGroup *vertex_group = static_cast<bDeformGroup *>(
+ BLI_findlink(BKE_object_defgroup_list(obj), curr_weight->def_nr));
+ if (vertex_group) {
+ deform_group_members[curr_weight->def_nr] += 1;
+ found_group = true;
+ }
+ }
+ }
+
+ if (!found_group) {
+ return NOT_FOUND;
+ }
+ /* Index of the group with maximum vertices. */
+ int16_t max_idx = std::max_element(deform_group_members.begin(), deform_group_members.end()) -
+ deform_group_members.begin();
+ return max_idx;
+}
+
+/**
+ * Find the name of the vertex deform group at the given index.
+ * The index indices into the #Object.defbase.
+ */
+const char *OBJMesh::get_poly_deform_group_name(const int16_t def_group_index) const
+{
+ const bDeformGroup &vertex_group = *(static_cast<bDeformGroup *>(
+ BLI_findlink(BKE_object_defgroup_list(export_object_eval_), def_group_index)));
+ return vertex_group.name;
+}
+
+/**
+ * Calculate vertex indices of an edge's corners if it is a loose edge.
+ */
+std::optional<std::array<int, 2>> OBJMesh::calc_loose_edge_vert_indices(const int edge_index) const
+{
+ const MEdge &edge = export_mesh_eval_->medge[edge_index];
+ if (edge.flag & ME_LOOSEEDGE) {
+ return std::array<int, 2>{static_cast<int>(edge.v1), static_cast<int>(edge.v2)};
+ }
+ return std::nullopt;
+}
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
new file mode 100644
index 00000000000..d72dd76d447
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh
@@ -0,0 +1,131 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#pragma once
+
+#include <optional>
+
+#include "BLI_float3.hh"
+#include "BLI_utility_mixins.hh"
+#include "BLI_vector.hh"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "IO_wavefront_obj.h"
+
+namespace blender::io::obj {
+/* Denote absence for usually non-negative numbers. */
+const int NOT_FOUND = -1;
+/* Any negative number other than `NOT_FOUND` to initialise usually non-negative numbers. */
+const int NEGATIVE_INIT = -10;
+
+/**
+ * #std::unique_ptr deleter for BMesh.
+ */
+struct CustomBMeshDeleter {
+ void operator()(BMesh *bmesh)
+ {
+ if (bmesh) {
+ BM_mesh_free(bmesh);
+ }
+ }
+};
+
+using unique_bmesh_ptr = std::unique_ptr<BMesh, CustomBMeshDeleter>;
+
+class OBJMesh : NonCopyable {
+ private:
+ Object *export_object_eval_;
+ Mesh *export_mesh_eval_;
+ /**
+ * For curves which are converted to mesh, and triangulated meshes, a new mesh is allocated.
+ */
+ bool mesh_eval_needs_free_ = false;
+ /**
+ * Final transform of an object obtained from export settings (up_axis, forward_axis) and the
+ * object's world transform matrix.
+ */
+ float world_and_axes_transform_[4][4];
+
+ /**
+ * Total UV vertices in a mesh's texture map.
+ */
+ int tot_uv_vertices_ = 0;
+ /**
+ * Per-polygon-per-vertex UV vertex indices.
+ */
+ Vector<Vector<int>> uv_indices_;
+ /**
+ * Total smooth groups in an object.
+ */
+ int tot_smooth_groups_ = NEGATIVE_INIT;
+ /**
+ * Polygon aligned array of their smooth groups.
+ */
+ int *poly_smooth_groups_ = nullptr;
+
+ public:
+ OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Object *mesh_object);
+ ~OBJMesh();
+
+ int tot_vertices() const;
+ int tot_polygons() const;
+ int tot_uv_vertices() const;
+ int tot_edges() const;
+
+ int16_t tot_materials() const;
+ const Material *get_object_material(const int16_t mat_nr) const;
+ int16_t ith_poly_matnr(const int poly_index) const;
+
+ void ensure_mesh_normals() const;
+ void ensure_mesh_edges() const;
+
+ void calc_smooth_groups(const bool use_bitflags);
+ int ith_smooth_group(const int poly_index) const;
+ bool is_ith_poly_smooth(const int poly_index) const;
+
+ const char *get_object_name() const;
+ const char *get_object_mesh_name() const;
+ const char *get_object_material_name(const int16_t mat_nr) const;
+
+ float3 calc_vertex_coords(const int vert_index, const float scaling_factor) const;
+ Vector<int> calc_poly_vertex_indices(const int poly_index) const;
+ void store_uv_coords_and_indices(Vector<std::array<float, 2>> &r_uv_coords);
+ Span<int> calc_poly_uv_indices(const int poly_index) const;
+ float3 calc_poly_normal(const int poly_index) const;
+ std::pair<int, Vector<int>> calc_poly_normal_indices(const int poly_index,
+ const int object_tot_prev_normals) const;
+ void calc_loop_normals(const int poly_index, Vector<float3> &r_loop_normals) const;
+ int16_t get_poly_deform_group_index(const int poly_index) const;
+ const char *get_poly_deform_group_name(const int16_t def_group_index) const;
+
+ std::optional<std::array<int, 2>> calc_loose_edge_vert_indices(const int edge_index) const;
+
+ private:
+ void free_mesh_if_needed();
+ std::pair<Mesh *, bool> triangulate_mesh_eval();
+ void set_world_axes_transform(const eTransformAxisForward forward, const eTransformAxisUp up);
+};
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
new file mode 100644
index 00000000000..b60f8976177
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc
@@ -0,0 +1,362 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#include "BKE_image.h"
+#include "BKE_node.h"
+
+#include "BLI_float3.hh"
+#include "BLI_map.hh"
+#include "BLI_path_util.h"
+
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+
+#include "NOD_node_tree_ref.hh"
+
+#include "obj_export_mesh.hh"
+#include "obj_export_mtl.hh"
+
+namespace blender::io::obj {
+
+/**
+ * Copy a float property of the given type from the bNode to given buffer.
+ */
+static void copy_property_from_node(const eNodeSocketDatatype property_type,
+ const bNode *node,
+ const char *identifier,
+ MutableSpan<float> r_property)
+{
+ if (!node) {
+ return;
+ }
+ bNodeSocket *socket{nodeFindSocket(node, SOCK_IN, identifier)};
+ BLI_assert(socket && socket->type == property_type);
+ if (!socket) {
+ return;
+ }
+ switch (property_type) {
+ case SOCK_FLOAT: {
+ BLI_assert(r_property.size() == 1);
+ bNodeSocketValueFloat *socket_def_value = static_cast<bNodeSocketValueFloat *>(
+ socket->default_value);
+ r_property[0] = socket_def_value->value;
+ break;
+ }
+ case SOCK_RGBA: {
+ BLI_assert(r_property.size() == 3);
+ bNodeSocketValueRGBA *socket_def_value = static_cast<bNodeSocketValueRGBA *>(
+ socket->default_value);
+ copy_v3_v3(r_property.data(), socket_def_value->value);
+ break;
+ }
+ case SOCK_VECTOR: {
+ BLI_assert(r_property.size() == 3);
+ bNodeSocketValueVector *socket_def_value = static_cast<bNodeSocketValueVector *>(
+ socket->default_value);
+ copy_v3_v3(r_property.data(), socket_def_value->value);
+ break;
+ }
+ default: {
+ /* Other socket types are not handled here. */
+ BLI_assert(0);
+ break;
+ }
+ }
+}
+
+/**
+ * Collect all the source sockets linked to the destination socket in a destination node.
+ */
+static void linked_sockets_to_dest_id(const bNode *dest_node,
+ const nodes::NodeTreeRef &node_tree,
+ StringRefNull dest_socket_id,
+ Vector<const nodes::OutputSocketRef *> &r_linked_sockets)
+{
+ r_linked_sockets.clear();
+ if (!dest_node) {
+ return;
+ }
+ Span<const nodes::NodeRef *> object_dest_nodes = node_tree.nodes_by_type(dest_node->idname);
+ Span<const nodes::InputSocketRef *> dest_inputs = object_dest_nodes.first()->inputs();
+ const nodes::InputSocketRef *dest_socket = nullptr;
+ for (const nodes::InputSocketRef *curr_socket : dest_inputs) {
+ if (STREQ(curr_socket->bsocket()->identifier, dest_socket_id.c_str())) {
+ dest_socket = curr_socket;
+ break;
+ }
+ }
+ if (dest_socket) {
+ Span<const nodes::OutputSocketRef *> linked_sockets = dest_socket->directly_linked_sockets();
+ r_linked_sockets.resize(linked_sockets.size());
+ r_linked_sockets = linked_sockets;
+ }
+}
+
+/**
+ * From a list of sockets, get the parent node which is of the given node type.
+ */
+static const bNode *get_node_of_type(Span<const nodes::OutputSocketRef *> sockets_list,
+ const int node_type)
+{
+ for (const nodes::SocketRef *socket : sockets_list) {
+ const bNode *parent_node = socket->bnode();
+ if (parent_node->typeinfo->type == node_type) {
+ return parent_node;
+ }
+ }
+ return nullptr;
+}
+
+/**
+ * From a texture image shader node, get the image's filepath.
+ * Returned filepath is stripped of initial "//". If packed image is found,
+ * only the file "name" is returned.
+ */
+static const char *get_image_filepath(const bNode *tex_node)
+{
+ if (!tex_node) {
+ return nullptr;
+ }
+ Image *tex_image = reinterpret_cast<Image *>(tex_node->id);
+ if (!tex_image || !BKE_image_has_filepath(tex_image)) {
+ return nullptr;
+ }
+ const char *path = tex_image->filepath;
+ if (BKE_image_has_packedfile(tex_image)) {
+ /* Put image in the same directory as the .MTL file. */
+ path = BLI_path_slash_rfind(path) + 1;
+ fprintf(stderr,
+ "Packed image found:'%s'. Unpack and place the image in the same "
+ "directory as the .MTL file.\n",
+ path);
+ }
+ if (path[0] == '/' && path[1] == '/') {
+ path += 2;
+ }
+ return path;
+}
+
+/**
+ * Find the Principled-BSDF Node in nodetree.
+ * We only want one that feeds directly into a Material Output node
+ * (that is the behavior of the legacy Python exporter).
+ */
+static const nodes::NodeRef *find_bsdf_node(const nodes::NodeTreeRef *nodetree)
+{
+ if (!nodetree) {
+ return nullptr;
+ }
+ for (const nodes::NodeRef *node : nodetree->nodes_by_type("ShaderNodeOutputMaterial")) {
+ const nodes::InputSocketRef *node_input_socket0 = node->inputs()[0];
+ for (const nodes::OutputSocketRef *out_sock : node_input_socket0->directly_linked_sockets()) {
+ const nodes::NodeRef &in_node = out_sock->node();
+ if (in_node.typeinfo()->type == SH_NODE_BSDF_PRINCIPLED) {
+ return &in_node;
+ }
+ }
+ }
+ return nullptr;
+}
+
+/**
+ * Store properties found either in bNode or material into r_mtl_mat.
+ */
+static void store_bsdf_properties(const nodes::NodeRef *bsdf_node,
+ const Material *material,
+ MTLMaterial &r_mtl_mat)
+{
+ const bNode *bnode = nullptr;
+ if (bsdf_node) {
+ bnode = bsdf_node->bnode();
+ }
+
+ /* If p-BSDF is not present, fallback to #Object.Material. */
+ float roughness = material->roughness;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Roughness", {&roughness, 1});
+ }
+ /* Emperical approximation. Importer should use the inverse of this method. */
+ float spec_exponent = (1.0f - roughness) * 30;
+ spec_exponent *= spec_exponent;
+
+ float specular = material->spec;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Specular", {&specular, 1});
+ }
+
+ float metallic = material->metallic;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Metallic", {&metallic, 1});
+ }
+
+ float refraction_index = 1.0f;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "IOR", {&refraction_index, 1});
+ }
+
+ float dissolved = material->a;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Alpha", {&dissolved, 1});
+ }
+ const bool transparent = dissolved != 1.0f;
+
+ float3 diffuse_col = {material->r, material->g, material->b};
+ if (bnode) {
+ copy_property_from_node(SOCK_RGBA, bnode, "Base Color", {diffuse_col, 3});
+ }
+
+ float3 emission_col{0.0f};
+ float emission_strength = 0.0f;
+ if (bnode) {
+ copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1});
+ copy_property_from_node(SOCK_RGBA, bnode, "Emission", {emission_col, 3});
+ }
+ mul_v3_fl(emission_col, emission_strength);
+
+ /* See https://wikipedia.org/wiki/Wavefront_.obj_file for all possible values of illum. */
+ /* Highlight on. */
+ int illum = 2;
+ if (specular == 0.0f) {
+ /* Color on and Ambient on. */
+ illum = 1;
+ }
+ else if (metallic > 0.0f) {
+ /* Metallic ~= Reflection. */
+ if (transparent) {
+ /* Transparency: Refraction on, Reflection: ~~Fresnel off and Ray trace~~ on. */
+ illum = 6;
+ }
+ else {
+ /* Reflection on and Ray trace on. */
+ illum = 3;
+ }
+ }
+ else if (transparent) {
+ /* Transparency: Glass on, Reflection: Ray trace off */
+ illum = 9;
+ }
+ r_mtl_mat.Ns = spec_exponent;
+ if (metallic != 0.0f) {
+ r_mtl_mat.Ka = {metallic, metallic, metallic};
+ }
+ else {
+ r_mtl_mat.Ka = {1.0f, 1.0f, 1.0f};
+ }
+ r_mtl_mat.Kd = diffuse_col;
+ r_mtl_mat.Ks = {specular, specular, specular};
+ r_mtl_mat.Ke = emission_col;
+ r_mtl_mat.Ni = refraction_index;
+ r_mtl_mat.d = dissolved;
+ r_mtl_mat.illum = illum;
+}
+
+/**
+ * Store image texture options and filepaths in r_mtl_mat.
+ */
+static void store_image_textures(const nodes::NodeRef *bsdf_node,
+ const nodes::NodeTreeRef *node_tree,
+ const Material *material,
+ MTLMaterial &r_mtl_mat)
+{
+ if (!material || !node_tree || !bsdf_node) {
+ /* No nodetree, no images, or no Principled BSDF node. */
+ return;
+ }
+ const bNode *bnode = bsdf_node->bnode();
+
+ /* Normal Map Texture has two extra tasks of:
+ * - finding a Normal Map node before finding a texture node.
+ * - finding "Strength" property of the node for `-bm` option.
+ */
+
+ for (Map<const eMTLSyntaxElement, tex_map_XX>::MutableItem texture_map :
+ r_mtl_mat.texture_maps.items()) {
+ Vector<const nodes::OutputSocketRef *> linked_sockets;
+ const bNode *normal_map_node{nullptr};
+
+ if (texture_map.key == eMTLSyntaxElement::map_Bump) {
+ /* Find sockets linked to destination "Normal" socket in p-bsdf node. */
+ linked_sockets_to_dest_id(bnode, *node_tree, "Normal", linked_sockets);
+ /* Among the linked sockets, find Normal Map shader node. */
+ normal_map_node = get_node_of_type(linked_sockets, SH_NODE_NORMAL_MAP);
+
+ /* Find sockets linked to "Color" socket in normal map node. */
+ linked_sockets_to_dest_id(normal_map_node, *node_tree, "Color", linked_sockets);
+ }
+ else if (texture_map.key == eMTLSyntaxElement::map_Ke) {
+ float emission_strength = 0.0f;
+ copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1});
+ if (emission_strength == 0.0f) {
+ continue;
+ }
+ }
+ else {
+ /* Find sockets linked to the destination socket of interest, in p-bsdf node. */
+ linked_sockets_to_dest_id(
+ bnode, *node_tree, texture_map.value.dest_socket_id, linked_sockets);
+ }
+
+ /* Among the linked sockets, find Image Texture shader node. */
+ const bNode *tex_node{get_node_of_type(linked_sockets, SH_NODE_TEX_IMAGE)};
+ if (!tex_node) {
+ continue;
+ }
+ const char *tex_image_filepath = get_image_filepath(tex_node);
+ if (!tex_image_filepath) {
+ continue;
+ }
+
+ /* Find "Mapping" node if connected to texture node. */
+ linked_sockets_to_dest_id(tex_node, *node_tree, "Vector", linked_sockets);
+ const bNode *mapping = get_node_of_type(linked_sockets, SH_NODE_MAPPING);
+
+ if (normal_map_node) {
+ copy_property_from_node(
+ SOCK_FLOAT, normal_map_node, "Strength", {&r_mtl_mat.map_Bump_strength, 1});
+ }
+ /* Texture transform options. Only translation (origin offset, "-o") and scale
+ * ("-o") are supported. */
+ copy_property_from_node(SOCK_VECTOR, mapping, "Location", {texture_map.value.translation, 3});
+ copy_property_from_node(SOCK_VECTOR, mapping, "Scale", {texture_map.value.scale, 3});
+
+ texture_map.value.image_path = tex_image_filepath;
+ }
+}
+
+MTLMaterial mtlmaterial_for_material(const Material *material)
+{
+ BLI_assert(material != nullptr);
+ MTLMaterial mtlmat;
+ mtlmat.name = std::string(material->id.name + 2);
+ std::replace(mtlmat.name.begin(), mtlmat.name.end(), ' ', '_');
+ const nodes::NodeTreeRef *nodetree = nullptr;
+ if (material->nodetree) {
+ nodetree = new nodes::NodeTreeRef(material->nodetree);
+ }
+ const nodes::NodeRef *bsdf_node = find_bsdf_node(nodetree);
+ store_bsdf_properties(bsdf_node, material, mtlmat);
+ store_image_textures(bsdf_node, nodetree, material, mtlmat);
+ if (nodetree) {
+ delete nodetree;
+ }
+ return mtlmat;
+}
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh
new file mode 100644
index 00000000000..2f62d189bd1
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh
@@ -0,0 +1,104 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#pragma once
+
+#include "BLI_float3.hh"
+#include "BLI_map.hh"
+#include "BLI_string_ref.hh"
+#include "BLI_vector.hh"
+
+#include "DNA_node_types.h"
+#include "obj_export_io.hh"
+
+namespace blender {
+template<> struct DefaultHash<io::obj::eMTLSyntaxElement> {
+ uint64_t operator()(const io::obj::eMTLSyntaxElement value) const
+ {
+ return static_cast<uint64_t>(value);
+ }
+};
+
+} // namespace blender
+
+namespace blender::io::obj {
+class OBJMesh;
+
+/**
+ * Generic container for texture node properties.
+ */
+struct tex_map_XX {
+ tex_map_XX(StringRef to_socket_id) : dest_socket_id(to_socket_id){};
+
+ /** Target socket which this texture node connects to. */
+ const std::string dest_socket_id;
+ float3 translation{0.0f};
+ float3 scale{1.0f};
+ /* Only Flat and Smooth projections are supported. */
+ int projection_type = SHD_PROJ_FLAT;
+ std::string image_path;
+ std::string mtl_dir_path;
+};
+
+/**
+ * Container suited for storing Material data for/from a .MTL file.
+ */
+struct MTLMaterial {
+ MTLMaterial()
+ {
+ texture_maps.add(eMTLSyntaxElement::map_Kd, tex_map_XX("Base Color"));
+ texture_maps.add(eMTLSyntaxElement::map_Ks, tex_map_XX("Specular"));
+ texture_maps.add(eMTLSyntaxElement::map_Ns, tex_map_XX("Roughness"));
+ texture_maps.add(eMTLSyntaxElement::map_d, tex_map_XX("Alpha"));
+ texture_maps.add(eMTLSyntaxElement::map_refl, tex_map_XX("Metallic"));
+ texture_maps.add(eMTLSyntaxElement::map_Ke, tex_map_XX("Emission"));
+ texture_maps.add(eMTLSyntaxElement::map_Bump, tex_map_XX("Normal"));
+ }
+
+ /**
+ * Caller must ensure that the given lookup key exists in the Map.
+ * \return Texture map corresponding to the given ID.
+ */
+ tex_map_XX &tex_map_of_type(const eMTLSyntaxElement key)
+ {
+ {
+ BLI_assert(texture_maps.contains_as(key));
+ return texture_maps.lookup_as(key);
+ }
+ }
+
+ std::string name;
+ /* Always check for negative values while importing or exporting. Use defaults if
+ * any value is negative. */
+ float Ns{-1.0f};
+ float3 Ka{-1.0f};
+ float3 Kd{-1.0f};
+ float3 Ks{-1.0f};
+ float3 Ke{-1.0f};
+ float Ni{-1.0f};
+ float d{-1.0f};
+ int illum{-1};
+ Map<const eMTLSyntaxElement, tex_map_XX> texture_maps;
+ /** Only used for Normal Map node: "map_Bump". */
+ float map_Bump_strength{-1.0f};
+};
+
+MTLMaterial mtlmaterial_for_material(const Material *material);
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
new file mode 100644
index 00000000000..4138ad2f697
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc
@@ -0,0 +1,122 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#include "BLI_float3.hh"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "IO_wavefront_obj.h"
+#include "obj_export_nurbs.hh"
+
+namespace blender::io::obj {
+OBJCurve::OBJCurve(const Depsgraph *depsgraph,
+ const OBJExportParams &export_params,
+ Object *curve_object)
+ : export_object_eval_(curve_object)
+{
+ export_object_eval_ = DEG_get_evaluated_object(depsgraph, curve_object);
+ export_curve_ = static_cast<Curve *>(export_object_eval_->data);
+ set_world_axes_transform(export_params.forward_axis, export_params.up_axis);
+}
+
+/**
+ * Set the final transform after applying axes settings and an Object's world transform.
+ */
+void OBJCurve::set_world_axes_transform(const eTransformAxisForward forward,
+ const eTransformAxisUp up)
+{
+ float axes_transform[3][3];
+ unit_m3(axes_transform);
+ /* +Y-forward and +Z-up are the Blender's default axis settings. */
+ mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform);
+ /* mat3_from_axis_conversion returns a transposed matrix! */
+ transpose_m3(axes_transform);
+ mul_m4_m3m4(world_axes_transform_, axes_transform, export_object_eval_->obmat);
+ /* #mul_m4_m3m4 does not transform last row of #Object.obmat, i.e. location data. */
+ mul_v3_m3v3(world_axes_transform_[3], axes_transform, export_object_eval_->obmat[3]);
+ world_axes_transform_[3][3] = export_object_eval_->obmat[3][3];
+}
+
+const char *OBJCurve::get_curve_name() const
+{
+ return export_object_eval_->id.name + 2;
+}
+
+int OBJCurve::total_splines() const
+{
+ return BLI_listbase_count(&export_curve_->nurb);
+}
+
+/**
+ * \param spline_index: Zero-based index of spline of interest.
+ * \return: Total vertices in a spline.
+ */
+int OBJCurve::total_spline_vertices(const int spline_index) const
+{
+ const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index));
+ return nurb->pntsu * nurb->pntsv;
+}
+
+/**
+ * Get coordinates of the vertex at the given index on the given spline.
+ */
+float3 OBJCurve::vertex_coordinates(const int spline_index,
+ const int vertex_index,
+ const float scaling_factor) const
+{
+ const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index));
+ float3 r_coord;
+ const BPoint &bpoint = nurb->bp[vertex_index];
+ copy_v3_v3(r_coord, bpoint.vec);
+ mul_m4_v3(world_axes_transform_, r_coord);
+ mul_v3_fl(r_coord, scaling_factor);
+ return r_coord;
+}
+
+/**
+ * Get total control points of the NURBS spline at the given index. This is different than total
+ * vertices of a spline.
+ */
+int OBJCurve::total_spline_control_points(const int spline_index) const
+{
+ const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index));
+ const int r_nurbs_degree = nurb->orderu - 1;
+ /* Total control points = Number of points in the curve (+ degree of the
+ * curve if it is cyclic). */
+ int r_tot_control_points = nurb->pntsv * nurb->pntsu;
+ if (nurb->flagu & CU_NURB_CYCLIC) {
+ r_tot_control_points += r_nurbs_degree;
+ }
+ return r_tot_control_points;
+}
+
+/**
+ * Get the degree of the NURBS spline at the given index.
+ */
+int OBJCurve::get_nurbs_degree(const int spline_index) const
+{
+ const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index));
+ return nurb->orderu - 1;
+}
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
new file mode 100644
index 00000000000..463e41befb5
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh
@@ -0,0 +1,57 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#pragma once
+
+#include "BLI_utility_mixins.hh"
+
+#include "DNA_curve_types.h"
+
+namespace blender::io::obj {
+
+/**
+ * Provides access to the a Curve Object's properties.
+ * Only #CU_NURBS type is supported.
+ *
+ * \note Used for Curves to be exported in parameter form, and not converted to meshes.
+ */
+class OBJCurve : NonCopyable {
+ private:
+ const Object *export_object_eval_;
+ const Curve *export_curve_;
+ float world_axes_transform_[4][4];
+
+ public:
+ OBJCurve(const Depsgraph *depsgraph, const OBJExportParams &export_params, Object *curve_object);
+
+ const char *get_curve_name() const;
+ int total_splines() const;
+ int total_spline_vertices(const int spline_index) const;
+ float3 vertex_coordinates(const int spline_index,
+ const int vertex_index,
+ const float scaling_factor) const;
+ int total_spline_control_points(const int spline_index) const;
+ int get_nurbs_degree(const int spline_index) const;
+
+ private:
+ void set_world_axes_transform(const eTransformAxisForward forward, const eTransformAxisUp up);
+};
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
new file mode 100644
index 00000000000..d15d053adc9
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc
@@ -0,0 +1,302 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#include <cstdio>
+#include <exception>
+#include <memory>
+
+#include "BKE_scene.h"
+
+#include "BLI_path_util.h"
+#include "BLI_vector.hh"
+
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_scene_types.h"
+
+#include "ED_object.h"
+
+#include "obj_export_mesh.hh"
+#include "obj_export_nurbs.hh"
+#include "obj_exporter.hh"
+
+#include "obj_export_file_writer.hh"
+
+namespace blender::io::obj {
+
+OBJDepsgraph::OBJDepsgraph(const bContext *C, const eEvaluationMode eval_mode)
+{
+ Scene *scene = CTX_data_scene(C);
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ if (eval_mode == DAG_EVAL_RENDER) {
+ depsgraph_ = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
+ needs_free_ = true;
+ DEG_graph_build_for_all_objects(depsgraph_);
+ BKE_scene_graph_evaluated_ensure(depsgraph_, bmain);
+ }
+ else {
+ depsgraph_ = CTX_data_ensure_evaluated_depsgraph(C);
+ needs_free_ = false;
+ }
+}
+
+OBJDepsgraph::~OBJDepsgraph()
+{
+ if (needs_free_) {
+ DEG_graph_free(depsgraph_);
+ }
+}
+
+Depsgraph *OBJDepsgraph::get()
+{
+ return depsgraph_;
+}
+
+void OBJDepsgraph::update_for_newframe()
+{
+ BKE_scene_graph_update_for_newframe(depsgraph_);
+}
+
+static void print_exception_error(const std::system_error &ex)
+{
+ std::cerr << ex.code().category().name() << ": " << ex.what() << ": " << ex.code().message()
+ << std::endl;
+}
+
+/**
+ * Filter supported objects from the Scene.
+ *
+ * \note Curves are also stored with Meshes if export settings specify so.
+ */
+std::pair<Vector<std::unique_ptr<OBJMesh>>, Vector<std::unique_ptr<OBJCurve>>>
+filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_params)
+{
+ Vector<std::unique_ptr<OBJMesh>> r_exportable_meshes;
+ Vector<std::unique_ptr<OBJCurve>> r_exportable_nurbs;
+ const ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
+ LISTBASE_FOREACH (const Base *, base, &view_layer->object_bases) {
+ Object *object_in_layer = base->object;
+ if (export_params.export_selected_objects && !(object_in_layer->base_flag & BASE_SELECTED)) {
+ continue;
+ }
+ switch (object_in_layer->type) {
+ case OB_SURF:
+ /* Export in mesh form: vertices and polygons. */
+ ATTR_FALLTHROUGH;
+ case OB_MESH:
+ r_exportable_meshes.append(
+ std::make_unique<OBJMesh>(depsgraph, export_params, object_in_layer));
+ break;
+ case OB_CURVE: {
+ Curve *curve = static_cast<Curve *>(object_in_layer->data);
+ Nurb *nurb{static_cast<Nurb *>(curve->nurb.first)};
+ if (!nurb) {
+ /* An empty curve. Not yet supported to export these as meshes. */
+ if (export_params.export_curves_as_nurbs) {
+ r_exportable_nurbs.append(
+ std::make_unique<OBJCurve>(depsgraph, export_params, object_in_layer));
+ }
+ break;
+ }
+ switch (nurb->type) {
+ case CU_NURBS:
+ if (export_params.export_curves_as_nurbs) {
+ /* Export in parameter form: control points. */
+ r_exportable_nurbs.append(
+ std::make_unique<OBJCurve>(depsgraph, export_params, object_in_layer));
+ }
+ else {
+ /* Export in mesh form: edges and vertices. */
+ r_exportable_meshes.append(
+ std::make_unique<OBJMesh>(depsgraph, export_params, object_in_layer));
+ }
+ break;
+ case CU_BEZIER:
+ /* Always export in mesh form: edges and vertices. */
+ r_exportable_meshes.append(
+ std::make_unique<OBJMesh>(depsgraph, export_params, object_in_layer));
+ break;
+ default:
+ /* Other curve types are not supported. */
+ break;
+ }
+ break;
+ }
+ default:
+ /* Other object types are not supported. */
+ break;
+ }
+ }
+ return {std::move(r_exportable_meshes), std::move(r_exportable_nurbs)};
+}
+
+static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_mesh,
+ OBJWriter &obj_writer,
+ MTLWriter *mtl_writer,
+ const OBJExportParams &export_params)
+{
+ if (mtl_writer) {
+ obj_writer.write_mtllib_name(mtl_writer->mtl_file_path());
+ }
+
+ /* Smooth groups and UV vertex indices may make huge memory allocations, so they should be freed
+ * right after they're written, instead of waiting for #blender::Vector to clean them up after
+ * all the objects are exported. */
+ for (auto &obj_mesh : exportable_as_mesh) {
+ obj_writer.write_object_name(*obj_mesh);
+ obj_writer.write_vertex_coords(*obj_mesh);
+ Vector<int> obj_mtlindices;
+
+ if (obj_mesh->tot_polygons() > 0) {
+ if (export_params.export_smooth_groups) {
+ obj_mesh->calc_smooth_groups(export_params.smooth_groups_bitflags);
+ }
+ if (export_params.export_normals) {
+ obj_writer.write_poly_normals(*obj_mesh);
+ }
+ if (export_params.export_uv) {
+ obj_writer.write_uv_coords(*obj_mesh);
+ }
+ if (mtl_writer) {
+ obj_mtlindices = mtl_writer->add_materials(*obj_mesh);
+ }
+ /* This function takes a 0-indexed slot index for the obj_mesh object and
+ * returns the material name that we are using in the .obj file for it. */
+ std::function<const char *(int)> matname_fn = [&](int s) -> const char * {
+ if (!mtl_writer || s < 0 || s >= obj_mtlindices.size()) {
+ return nullptr;
+ }
+ return mtl_writer->mtlmaterial_name(obj_mtlindices[s]);
+ };
+ obj_writer.write_poly_elements(*obj_mesh, matname_fn);
+ }
+ obj_writer.write_edges_indices(*obj_mesh);
+
+ obj_writer.update_index_offsets(*obj_mesh);
+ }
+}
+
+/**
+ * Export NURBS Curves in parameter form, not as vertices and edges.
+ */
+static void write_nurbs_curve_objects(const Vector<std::unique_ptr<OBJCurve>> &exportable_as_nurbs,
+ const OBJWriter &obj_writer)
+{
+ /* #OBJCurve doesn't have any dynamically allocated memory, so it's fine
+ * to wait for #blender::Vector to clean the objects up. */
+ for (const std::unique_ptr<OBJCurve> &obj_curve : exportable_as_nurbs) {
+ obj_writer.write_nurbs_curve(*obj_curve);
+ }
+}
+
+/**
+ * Export a single frame to a .OBJ file.
+ *
+ * Conditionally write a .MTL file also.
+ */
+void export_frame(Depsgraph *depsgraph, const OBJExportParams &export_params, const char *filepath)
+{
+ std::unique_ptr<OBJWriter> frame_writer = nullptr;
+ try {
+ frame_writer = std::make_unique<OBJWriter>(filepath, export_params);
+ }
+ catch (const std::system_error &ex) {
+ print_exception_error(ex);
+ return;
+ }
+ if (!frame_writer) {
+ BLI_assert(!"File should be writable by now.");
+ return;
+ }
+ std::unique_ptr<MTLWriter> mtl_writer = nullptr;
+ if (export_params.export_materials) {
+ try {
+ mtl_writer = std::make_unique<MTLWriter>(export_params.filepath);
+ }
+ catch (const std::system_error &ex) {
+ print_exception_error(ex);
+ }
+ }
+
+ frame_writer->write_header();
+
+ auto [exportable_as_mesh, exportable_as_nurbs] = filter_supported_objects(depsgraph,
+ export_params);
+
+ write_mesh_objects(
+ std::move(exportable_as_mesh), *frame_writer, mtl_writer.get(), export_params);
+ if (mtl_writer) {
+ mtl_writer->write_header(export_params.blen_filepath);
+ mtl_writer->write_materials();
+ }
+ write_nurbs_curve_objects(std::move(exportable_as_nurbs), *frame_writer);
+}
+
+/**
+ * Append the current frame number in the .OBJ file name.
+ *
+ * \return Whether the filepath is in #FILE_MAX limits.
+ */
+bool append_frame_to_filename(const char *filepath, const int frame, char *r_filepath_with_frames)
+{
+ BLI_strncpy(r_filepath_with_frames, filepath, FILE_MAX);
+ BLI_path_extension_replace(r_filepath_with_frames, FILE_MAX, "");
+ const int digits = frame == 0 ? 1 : integer_digits_i(abs(frame));
+ BLI_path_frame(r_filepath_with_frames, frame, digits);
+ return BLI_path_extension_replace(r_filepath_with_frames, FILE_MAX, ".obj");
+}
+
+/**
+ * Central internal function to call Scene update & writer functions.
+ */
+void exporter_main(bContext *C, const OBJExportParams &export_params)
+{
+ ED_object_mode_set(C, OB_MODE_OBJECT);
+ OBJDepsgraph obj_depsgraph(C, export_params.export_eval_mode);
+ Scene *scene = DEG_get_input_scene(obj_depsgraph.get());
+ const char *filepath = export_params.filepath;
+
+ /* Single frame export, i.e. no animation. */
+ if (!export_params.export_animation) {
+ fprintf(stderr, "Writing to %s\n", filepath);
+ export_frame(obj_depsgraph.get(), export_params, filepath);
+ return;
+ }
+
+ char filepath_with_frames[FILE_MAX];
+ /* Used to reset the Scene to its original state. */
+ const int original_frame = CFRA;
+
+ for (int frame = export_params.start_frame; frame <= export_params.end_frame; frame++) {
+ const bool filepath_ok = append_frame_to_filename(filepath, frame, filepath_with_frames);
+ if (!filepath_ok) {
+ fprintf(stderr, "Error: File Path too long.\n%s\n", filepath_with_frames);
+ return;
+ }
+
+ CFRA = frame;
+ obj_depsgraph.update_for_newframe();
+ fprintf(stderr, "Writing to %s\n", filepath_with_frames);
+ export_frame(obj_depsgraph.get(), export_params, filepath_with_frames);
+ }
+ CFRA = original_frame;
+}
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.hh b/source/blender/io/wavefront_obj/exporter/obj_exporter.hh
new file mode 100644
index 00000000000..e02a240b51a
--- /dev/null
+++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.hh
@@ -0,0 +1,88 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup obj
+ */
+
+#pragma once
+
+#include "BLI_utility_mixins.hh"
+
+#include "BLI_vector.hh"
+
+#include "IO_wavefront_obj.h"
+
+namespace blender::io::obj {
+
+/**
+ * Behaves like `std::unique_ptr<Depsgraph, custom_deleter>`.
+ * Needed to free a new Depsgraph created for #DAG_EVAL_RENDER.
+ */
+class OBJDepsgraph : NonMovable, NonCopyable {
+ private:
+ Depsgraph *depsgraph_ = nullptr;
+ bool needs_free_ = false;
+
+ public:
+ OBJDepsgraph(const bContext *C, const eEvaluationMode eval_mode);
+ ~OBJDepsgraph();
+
+ Depsgraph *get();
+ void update_for_newframe();
+};
+
+/**
+ * The main function for exporting a .obj file according to the given `export_parameters`.
+ * It uses the context `C` to get the dependency graph, and from that, the `Scene`.
+ * Depending on whether or not `export_params.export_animation` is set, it writes
+ * either one file per animation frame, or just one file.
+ */
+void exporter_main(bContext *C, const OBJExportParams &export_params);
+
+class OBJMesh;
+class OBJCurve;
+
+/**
+ * Export a single frame of a .obj file, according to the given `export_parameters`.
+ * The frame state is given in `depsgraph`.
+ * The output file name is given by `filepath`.
+ * This function is normally called from `exporter_main`, but is exposed here for testing purposes.
+ */
+void export_frame(Depsgraph *depsgraph,
+ const OBJExportParams &export_params,
+ const char *filepath);
+
+/**
+ * Find the objects to be exported in the `view_layer` of the dependency graph`depsgraph`,
+ * and return them in vectors `unique_ptr`s of `OBJMesh` and `OBJCurve`.
+ * If `export_params.export_selected_objects` is set, then only selected objects are to be
+ * exported, else all objects are to be exported. But only objects of type `OB_MESH`, `OB_CURVE`,
+ * and `OB_SURF` are supported; the rest will be ignored. If `export_params.export_curves_as_nurbs`
+ * is set, then curves of type `CU_NURBS` are exported in curve form in the .obj file, otherwise
+ * they are converted to mesh and returned in the `OBJMesh` vector. All other exportable types are
+ * always converted to mesh and returned in the `OBJMesh` vector.
+ */
+std::pair<Vector<std::unique_ptr<OBJMesh>>, Vector<std::unique_ptr<OBJCurve>>>
+filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_params);
+
+/**
+ * Makes `r_filepath_with_frames` (which should point at a character array of size `FILE_MAX`)
+ * be `filepath` with its "#" characters replaced by the number representing `frame`, and with
+ * a .obj extension.
+ */
+bool append_frame_to_filename(const char *filepath, const int frame, char *r_filepath_with_frames);
+} // namespace blender::io::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
new file mode 100644
index 00000000000..f12bfd0cea5
--- /dev/null
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc
@@ -0,0 +1,417 @@
+/* Apache License, Version 2.0 */
+
+#include <fstream>
+#include <gtest/gtest.h>
+#include <ios>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <system_error>
+
+#include "testing/testing.h"
+#include "tests/blendfile_loading_base_test.h"
+
+#include "BKE_appdir.h"
+#include "BKE_blender_version.h"
+
+#include "BLI_fileops.h"
+#include "BLI_index_range.hh"
+#include "BLI_string_utf8.h"
+#include "BLI_vector.hh"
+
+#include "DEG_depsgraph.h"
+
+#include "obj_export_file_writer.hh"
+#include "obj_export_mesh.hh"
+#include "obj_export_nurbs.hh"
+#include "obj_exporter.hh"
+
+#include "obj_exporter_tests.hh"
+
+namespace blender::io::obj {
+
+/* This is also the test name. */
+class obj_exporter_test : public BlendfileLoadingBaseTest {
+ public:
+ /**
+ * \param filepath: relative to "tests" directory.
+ */
+ bool load_file_and_depsgraph(const std::string &filepath,
+ const eEvaluationMode eval_mode = DAG_EVAL_VIEWPORT)
+ {
+ if (!blendfile_load(filepath.c_str())) {
+ return false;
+ }
+ depsgraph_create(eval_mode);
+ return true;
+ }
+};
+
+const std::string all_objects_file = "io_tests/blend_scene/all_objects.blend";
+const std::string all_curve_objects_file = "io_tests/blend_scene/all_curves.blend";
+
+TEST_F(obj_exporter_test, filter_objects_curves_as_mesh)
+{
+ OBJExportParamsDefault _export;
+ if (!load_file_and_depsgraph(all_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+ auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+ EXPECT_EQ(objmeshes.size(), 17);
+ EXPECT_EQ(objcurves.size(), 0);
+}
+
+TEST_F(obj_exporter_test, filter_objects_curves_as_nurbs)
+{
+ OBJExportParamsDefault _export;
+ if (!load_file_and_depsgraph(all_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+ _export.params.export_curves_as_nurbs = true;
+ auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+ EXPECT_EQ(objmeshes.size(), 16);
+ EXPECT_EQ(objcurves.size(), 2);
+}
+
+TEST_F(obj_exporter_test, filter_objects_selected)
+{
+ OBJExportParamsDefault _export;
+ if (!load_file_and_depsgraph(all_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+ _export.params.export_selected_objects = true;
+ _export.params.export_curves_as_nurbs = true;
+ auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+ EXPECT_EQ(objmeshes.size(), 1);
+ EXPECT_EQ(objcurves.size(), 0);
+}
+
+TEST(obj_exporter_utils, append_negative_frame_to_filename)
+{
+ const char path_original[FILE_MAX] = "/my_file.obj";
+ const char path_truth[FILE_MAX] = "/my_file-123.obj";
+ const int frame = -123;
+ char path_with_frame[FILE_MAX] = {0};
+ const bool ok = append_frame_to_filename(path_original, frame, path_with_frame);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ_ARRAY(path_with_frame, path_truth, BLI_strlen_utf8(path_truth));
+}
+
+TEST(obj_exporter_utils, append_positive_frame_to_filename)
+{
+ const char path_original[FILE_MAX] = "/my_file.obj";
+ const char path_truth[FILE_MAX] = "/my_file123.obj";
+ const int frame = 123;
+ char path_with_frame[FILE_MAX] = {0};
+ const bool ok = append_frame_to_filename(path_original, frame, path_with_frame);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ_ARRAY(path_with_frame, path_truth, BLI_strlen_utf8(path_truth));
+}
+
+TEST_F(obj_exporter_test, curve_nurbs_points)
+{
+ if (!load_file_and_depsgraph(all_curve_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+
+ OBJExportParamsDefault _export;
+ _export.params.export_curves_as_nurbs = true;
+ auto [objmeshes_unused, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+
+ for (auto &objcurve : objcurves) {
+ if (all_nurbs_truth.count(objcurve->get_curve_name()) != 1) {
+ ADD_FAILURE();
+ return;
+ }
+ const NurbsObject *const nurbs_truth = all_nurbs_truth.at(objcurve->get_curve_name()).get();
+ EXPECT_EQ(objcurve->total_splines(), nurbs_truth->total_splines());
+ for (int spline_index : IndexRange(objcurve->total_splines())) {
+ EXPECT_EQ(objcurve->total_spline_vertices(spline_index),
+ nurbs_truth->total_spline_vertices(spline_index));
+ EXPECT_EQ(objcurve->get_nurbs_degree(spline_index),
+ nurbs_truth->get_nurbs_degree(spline_index));
+ EXPECT_EQ(objcurve->total_spline_control_points(spline_index),
+ nurbs_truth->total_spline_control_points(spline_index));
+ }
+ }
+}
+
+TEST_F(obj_exporter_test, curve_coordinates)
+{
+ if (!load_file_and_depsgraph(all_curve_objects_file)) {
+ ADD_FAILURE();
+ return;
+ }
+
+ OBJExportParamsDefault _export;
+ _export.params.export_curves_as_nurbs = true;
+ auto [objmeshes_unused, objcurves]{filter_supported_objects(depsgraph, _export.params)};
+
+ for (auto &objcurve : objcurves) {
+ if (all_nurbs_truth.count(objcurve->get_curve_name()) != 1) {
+ ADD_FAILURE();
+ return;
+ }
+ const NurbsObject *const nurbs_truth = all_nurbs_truth.at(objcurve->get_curve_name()).get();
+ EXPECT_EQ(objcurve->total_splines(), nurbs_truth->total_splines());
+ for (int spline_index : IndexRange(objcurve->total_splines())) {
+ for (int vertex_index : IndexRange(objcurve->total_spline_vertices(spline_index))) {
+ EXPECT_V3_NEAR(objcurve->vertex_coordinates(
+ spline_index, vertex_index, _export.params.scaling_factor),
+ nurbs_truth->vertex_coordinates(spline_index, vertex_index),
+ 0.000001f);
+ }
+ }
+ }
+}
+
+static std::unique_ptr<OBJWriter> init_writer(const OBJExportParams &params,
+ const std::string out_filepath)
+{
+ try {
+ auto writer = std::make_unique<OBJWriter>(out_filepath.c_str(), params);
+ return writer;
+ }
+ catch (const std::system_error &ex) {
+ std::cerr << ex.code().category().name() << ": " << ex.what() << ": " << ex.code().message()
+ << std::endl;
+ return nullptr;
+ }
+}
+
+/* The following is relative to BKE_tempdir_base. */
+const char *const temp_file_path = "output.OBJ";
+
+static std::string read_temp_file_in_string(const std::string &file_path)
+{
+ std::ifstream temp_stream(file_path);
+ std::ostringstream input_ss;
+ input_ss << temp_stream.rdbuf();
+ return input_ss.str();
+}
+
+TEST(obj_exporter_writer, header)
+{
+ /* Because testing doesn't fully initialize Blender, we need the following. */
+ BKE_tempdir_init(NULL);
+ std::string out_file_path = blender::tests::flags_test_release_dir() + "/" + temp_file_path;
+ {
+ OBJExportParamsDefault _export;
+ std::unique_ptr<OBJWriter> writer = init_writer(_export.params, out_file_path);
+ if (!writer) {
+ ADD_FAILURE();
+ return;
+ }
+ writer->write_header();
+ }
+ const std::string result = read_temp_file_in_string(out_file_path);
+ using namespace std::string_literals;
+ ASSERT_EQ(result, "# Blender "s + BKE_blender_version_string() + "\n" + "# www.blender.org\n");
+ BLI_delete(out_file_path.c_str(), false, false);
+}
+
+TEST(obj_exporter_writer, mtllib)
+{
+ std::string out_file_path = blender::tests::flags_test_release_dir() + "/" + temp_file_path;
+ {
+ OBJExportParamsDefault _export;
+ std::unique_ptr<OBJWriter> writer = init_writer(_export.params, out_file_path);
+ if (!writer) {
+ ADD_FAILURE();
+ return;
+ }
+ writer->write_mtllib_name("/Users/blah.mtl");
+ writer->write_mtllib_name("\\C:\\blah.mtl");
+ }
+ const std::string result = read_temp_file_in_string(out_file_path);
+ ASSERT_EQ(result, "mtllib blah.mtl\nmtllib blah.mtl\n");
+}
+
+/* Return true if string #a and string #b are equal after their first newline. */
+static bool strings_equal_after_first_lines(const std::string &a, const std::string &b)
+{
+ /* If `dbg_level > 0` then a failing test will print context around the first mismatch. */
+ const bool dbg_level = 0;
+ const size_t a_len = a.size();
+ const size_t b_len = b.size();
+ const size_t a_next = a.find_first_of('\n');
+ const size_t b_next = b.find_first_of('\n');
+ if (a_next == std::string::npos || b_next == std::string::npos) {
+ if (dbg_level > 0) {
+ std::cout << "Couldn't find newline in one of args\n";
+ }
+ return false;
+ }
+ if (dbg_level > 0) {
+ if (a.compare(a_next, a_len - a_next, b, b_next, b_len - b_next) != 0) {
+ for (int i = 0; i < a_len - a_next && i < b_len - b_next; ++i) {
+ if (a[a_next + i] != b[b_next + i]) {
+ std::cout << "Difference found at pos " << a_next + i << " of a\n";
+ std::cout << "a: " << a.substr(a_next + i, 100) << " ...\n";
+ std::cout << "b: " << b.substr(b_next + i, 100) << " ... \n";
+ return false;
+ }
+ }
+ }
+ else {
+ return true;
+ }
+ }
+ return a.compare(a_next, a_len - a_next, b, b_next, b_len - b_next) == 0;
+}
+
+/* From here on, tests are whole file tests, testing for golden output. */
+class obj_exporter_regression_test : public obj_exporter_test {
+ public:
+ /**
+ * Export the given blend file with the given parameters and
+ * test to see if it matches a golden file (ignoring any difference in Blender version number).
+ * \param blendfile: input, relative to "tests" directory.
+ * \param golden_obj: expected output, relative to "tests" directory.
+ * \param params: the parameters to be used for export.
+ */
+ void compare_obj_export_to_golden(const std::string &blendfile,
+ const std::string &golden_obj,
+ const std::string &golden_mtl,
+ OBJExportParams &params)
+ {
+ if (!load_file_and_depsgraph(blendfile)) {
+ return;
+ }
+ /* Because testing doesn't fully initialize Blender, we need the following. */
+ BKE_tempdir_init(NULL);
+ std::string tempdir = std::string(BKE_tempdir_base());
+ std::string out_file_path = tempdir + BLI_path_basename(golden_obj.c_str());
+ strncpy(params.filepath, out_file_path.c_str(), FILE_MAX);
+ params.blen_filepath = blendfile.c_str();
+ export_frame(depsgraph, params, out_file_path.c_str());
+ std::string output_str = read_temp_file_in_string(out_file_path);
+
+ std::string golden_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_obj;
+ std::string golden_str = read_temp_file_in_string(golden_file_path);
+ ASSERT_TRUE(strings_equal_after_first_lines(output_str, golden_str));
+ BLI_delete(out_file_path.c_str(), false, false);
+ if (!golden_mtl.empty()) {
+ std::string out_mtl_file_path = tempdir + BLI_path_basename(golden_mtl.c_str());
+ std::string output_mtl_str = read_temp_file_in_string(out_mtl_file_path);
+ std::string golden_mtl_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_mtl;
+ std::string golden_mtl_str = read_temp_file_in_string(golden_mtl_file_path);
+ ASSERT_TRUE(strings_equal_after_first_lines(output_mtl_str, golden_mtl_str));
+ BLI_delete(out_mtl_file_path.c_str(), false, false);
+ }
+ }
+};
+
+TEST_F(obj_exporter_regression_test, all_tris)
+{
+ OBJExportParamsDefault _export;
+ compare_obj_export_to_golden("io_tests/blend_geometry/all_tris.blend",
+ "io_tests/obj/all_tris.obj",
+ "io_tests/obj/all_tris.mtl",
+ _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, all_quads)
+{
+ OBJExportParamsDefault _export;
+ _export.params.scaling_factor = 2.0f;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/all_quads.blend", "io_tests/obj/all_quads.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, fgons)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/fgons.blend", "io_tests/obj/fgons.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, edges)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/edges.blend", "io_tests/obj/edges.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, vertices)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/vertices.blend", "io_tests/obj/vertices.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, nurbs_as_nurbs)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ _export.params.export_curves_as_nurbs = true;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/nurbs.blend", "io_tests/obj/nurbs.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, nurbs_as_mesh)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ _export.params.export_curves_as_nurbs = false;
+ compare_obj_export_to_golden(
+ "io_tests/blend_geometry/nurbs.blend", "io_tests/obj/nurbs_mesh.obj", "", _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, cube_all_data_triangulated)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ _export.params.export_triangulated_mesh = true;
+ compare_obj_export_to_golden("io_tests/blend_geometry/cube_all_data.blend",
+ "io_tests/obj/cube_all_data_triangulated.obj",
+ "",
+ _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, suzanne_all_data)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_materials = false;
+ _export.params.export_smooth_groups = true;
+ compare_obj_export_to_golden("io_tests/blend_geometry/suzanne_all_data.blend",
+ "io_tests/obj/suzanne_all_data.obj",
+ "",
+ _export.params);
+}
+
+TEST_F(obj_exporter_regression_test, all_objects)
+{
+ OBJExportParamsDefault _export;
+ _export.params.forward_axis = OBJ_AXIS_Y_FORWARD;
+ _export.params.up_axis = OBJ_AXIS_Z_UP;
+ _export.params.export_smooth_groups = true;
+ compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend",
+ "io_tests/obj/all_objects.obj",
+ "io_tests/obj/all_objects.mtl",
+ _export.params);
+}
+
+} // namespace blender::io::obj
diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
new file mode 100644
index 00000000000..def70eff0ee
--- /dev/null
+++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh
@@ -0,0 +1,149 @@
+/* Apache License, Version 2.0 */
+
+/**
+ * This file contains default values for several items like
+ * vertex coordinates, export parameters, MTL values etc.
+ */
+
+#pragma once
+
+#include <array>
+#include <gtest/gtest.h>
+#include <string>
+#include <vector>
+
+#include "IO_wavefront_obj.h"
+
+namespace blender::io::obj {
+
+using array_float_3 = std::array<float, 3>;
+
+/**
+ * This matches #OBJCurve's member functions, except that all the numbers and names are known
+ * constants. Used to store expected values of NURBS Curve sobjects.
+ */
+class NurbsObject {
+ private:
+ std::string nurbs_name_;
+ /* The indices in these vectors are spline indices. */
+ std::vector<std::vector<array_float_3>> coordinates_;
+ std::vector<int> degrees_;
+ std::vector<int> control_points_;
+
+ public:
+ NurbsObject(const std::string nurbs_name,
+ const std::vector<std::vector<array_float_3>> coordinates,
+ const std::vector<int> degrees,
+ const std::vector<int> control_points)
+ : nurbs_name_(nurbs_name),
+ coordinates_(coordinates),
+ degrees_(degrees),
+ control_points_(control_points)
+ {
+ }
+
+ int total_splines() const
+ {
+ return coordinates_.size();
+ }
+
+ int total_spline_vertices(const int spline_index) const
+ {
+ if (spline_index >= coordinates_.size()) {
+ ADD_FAILURE();
+ return 0;
+ }
+ return coordinates_[spline_index].size();
+ }
+
+ const float *vertex_coordinates(const int spline_index, const int vertex_index) const
+ {
+ return coordinates_[spline_index][vertex_index].data();
+ }
+
+ int get_nurbs_degree(const int spline_index) const
+ {
+ return degrees_[spline_index];
+ }
+
+ int total_spline_control_points(const int spline_index) const
+ {
+ return control_points_[spline_index];
+ }
+};
+
+struct OBJExportParamsDefault {
+ OBJExportParams params;
+ OBJExportParamsDefault()
+ {
+ params.filepath[0] = '\0';
+ params.blen_filepath = "";
+ params.export_animation = false;
+ params.start_frame = 0;
+ params.end_frame = 1;
+
+ params.forward_axis = OBJ_AXIS_NEGATIVE_Z_FORWARD;
+ params.up_axis = OBJ_AXIS_Y_UP;
+ params.scaling_factor = 1.f;
+
+ params.export_eval_mode = DAG_EVAL_VIEWPORT;
+ params.export_selected_objects = false;
+ params.export_uv = true;
+ params.export_normals = true;
+ params.export_materials = true;
+ params.export_triangulated_mesh = false;
+ params.export_curves_as_nurbs = false;
+
+ params.export_object_groups = false;
+ params.export_material_groups = false;
+ params.export_vertex_groups = false;
+ params.export_smooth_groups = true;
+ params.smooth_groups_bitflags = false;
+ }
+};
+
+const std::vector<std::vector<array_float_3>> coordinates_NurbsCurve{
+ {{6.94742, 0.000000, 0.000000},
+ {7.44742, 0.000000, -1.000000},
+ {9.44742, 0.000000, -1.000000},
+ {9.94742, 0.000000, 0.000000}}};
+const std::vector<std::vector<array_float_3>> coordinates_NurbsCircle{
+ {{11.463165, 0.000000, 1.000000},
+ {10.463165, 0.000000, 1.000000},
+ {10.463165, 0.000000, 0.000000},
+ {10.463165, 0.000000, -1.000000},
+ {11.463165, 0.000000, -1.000000},
+ {12.463165, 0.000000, -1.000000},
+ {12.463165, 0.000000, 0.000000},
+ {12.463165, 0.000000, 1.000000}}};
+const std::vector<std::vector<array_float_3>> coordinates_NurbsPathCurve{
+ {{13.690557, 0.000000, 0.000000},
+ {14.690557, 0.000000, 0.000000},
+ {15.690557, 0.000000, 0.000000},
+ {16.690557, 0.000000, 0.000000},
+ {17.690557, 0.000000, 0.000000}},
+ {{14.192808, 0.000000, 0.000000},
+ {14.692808, 0.000000, -1.000000},
+ {16.692808, 0.000000, -1.000000},
+ {17.192808, 0.000000, 0.000000}}};
+
+const std::map<std::string, std::unique_ptr<NurbsObject>> all_nurbs_truth = []() {
+ std::map<std::string, std::unique_ptr<NurbsObject>> all_nurbs;
+ all_nurbs.emplace(
+ "NurbsCurve",
+ /* Name, coordinates, degrees of splines, control points of splines. */
+ std::make_unique<NurbsObject>(
+ "NurbsCurve", coordinates_NurbsCurve, std::vector<int>{3}, std::vector<int>{4}));
+ all_nurbs.emplace(
+ "NurbsCircle",
+ std::make_unique<NurbsObject>(
+ "NurbsCircle", coordinates_NurbsCircle, std::vector<int>{3}, std::vector<int>{11}));
+ /* This is actually an Object containing a NurbsPath and a NurbsCurve spline. */
+ all_nurbs.emplace("NurbsPathCurve",
+ std::make_unique<NurbsObject>("NurbsPathCurve",
+ coordinates_NurbsPathCurve,
+ std::vector<int>{3, 3},
+ std::vector<int>{5, 4}));
+ return all_nurbs;
+}();
+} // namespace blender::io::obj
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 6a478f9abb5..17b3fb302e6 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -802,6 +802,9 @@ typedef enum IDRecalcFlag {
*/
ID_RECALC_TAG_FOR_UNDO = (1 << 24),
+ /* The node tree has changed in a way that affects its output nodes. */
+ ID_RECALC_NTREE_OUTPUT = (1 << 25),
+
/***************************************************************************
* Pseudonyms, to have more semantic meaning in the actual code without
* using too much low-level and implementation specific tags. */
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 36bdd4915ff..787dbc23515 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -134,7 +134,6 @@ typedef enum CustomDataType {
CD_CLOTH_ORCO = 23,
/* CD_RECAST = 24, */ /* UNUSED */
- /* BMESH ONLY START */
CD_MPOLY = 25,
CD_MLOOP = 26,
CD_SHAPE_KEYINDEX = 27,
@@ -144,7 +143,6 @@ typedef enum CustomDataType {
CD_ORIGSPACE_MLOOP = 31,
CD_PREVIEW_MLOOPCOL = 32,
CD_BM_ELEM_PYPTR = 33,
- /* BMESH ONLY END */
CD_PAINT_MASK = 34,
CD_GRID_PAINT_MASK = 35,
@@ -164,7 +162,6 @@ typedef enum CustomDataType {
CD_PROP_COLOR = 47,
CD_PROP_FLOAT3 = 48,
CD_PROP_FLOAT2 = 49,
-
CD_PROP_BOOL = 50,
CD_HAIRLENGTH = 51,
@@ -197,7 +194,6 @@ typedef enum CustomDataType {
#define CD_MASK_CLOTH_ORCO (1 << CD_CLOTH_ORCO)
// #define CD_MASK_RECAST (1 << CD_RECAST) /* DEPRECATED */
-/* BMESH ONLY START */
#define CD_MASK_MPOLY (1 << CD_MPOLY)
#define CD_MASK_MLOOP (1 << CD_MLOOP)
#define CD_MASK_SHAPE_KEYINDEX (1 << CD_SHAPE_KEYINDEX)
@@ -207,7 +203,6 @@ typedef enum CustomDataType {
#define CD_MASK_ORIGSPACE_MLOOP (1LL << CD_ORIGSPACE_MLOOP)
#define CD_MASK_PREVIEW_MLOOPCOL (1LL << CD_PREVIEW_MLOOPCOL)
#define CD_MASK_BM_ELEM_PYPTR (1LL << CD_BM_ELEM_PYPTR)
-/* BMESH ONLY END */
#define CD_MASK_PAINT_MASK (1LL << CD_PAINT_MASK)
#define CD_MASK_GRID_PAINT_MASK (1LL << CD_GRID_PAINT_MASK)
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 77cb553c7c7..94e88bdaca6 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -74,7 +74,7 @@ struct MLoopTri_Store {
int len_alloc;
};
-/* Runtime data, not saved in files. */
+/** Runtime data, not saved in files. */
typedef struct Mesh_Runtime {
/* Evaluated mesh for objects which do not have effective modifiers.
* This mesh is used as a result of modifier stack evaluation.
@@ -138,6 +138,15 @@ typedef struct Mesh_Runtime {
int64_t cd_dirty_loop;
int64_t cd_dirty_poly;
+ /**
+ * Settings for lazily evaluating the subdivision on the CPU if needed. These are
+ * set in the modifier when GPU subdivision can be performed.
+ */
+ char subsurf_apply_render;
+ char subsurf_use_optimal_display;
+ char _pad[2];
+ int subsurf_resolution;
+
} Mesh_Runtime;
typedef struct Mesh {
@@ -356,16 +365,17 @@ typedef enum eMeshWrapperType {
ME_WRAPPER_TYPE_MDATA = 0,
/** Use edit-mesh data (#Mesh.edit_mesh, #Mesh_Runtime.edit_data). */
ME_WRAPPER_TYPE_BMESH = 1,
- /* ME_WRAPPER_TYPE_SUBD = 2, */ /* TODO */
+ /** Use subdivision mesh data (#Mesh_Runtime.mesh_eval). */
+ ME_WRAPPER_TYPE_SUBD = 2,
} eMeshWrapperType;
-/* texflag */
+/** #Mesh.texflag */
enum {
ME_AUTOSPACE = 1,
ME_AUTOSPACE_EVALUATED = 2,
};
-/* me->editflag */
+/** #Mesh.editflag */
enum {
ME_EDIT_MIRROR_VERTEX_GROUPS = 1 << 0,
ME_EDIT_MIRROR_Y = 1 << 1, /* unused so far */
@@ -387,7 +397,7 @@ enum {
((_me)->editflag & ME_EDIT_PAINT_VERT_SEL) ? SCE_SELECT_VERTEX : \
0)
-/* me->flag */
+/** #Mesh.flag */
enum {
ME_FLAG_UNUSED_0 = 1 << 0, /* cleared */
ME_FLAG_UNUSED_1 = 1 << 1, /* cleared */
@@ -407,26 +417,26 @@ enum {
ME_REMESH_REPROJECT_SCULPT_FACE_SETS = 1 << 15,
};
-/* me->cd_flag */
+/** #Mesh.cd_flag */
enum {
ME_CDFLAG_VERT_BWEIGHT = 1 << 0,
ME_CDFLAG_EDGE_BWEIGHT = 1 << 1,
ME_CDFLAG_EDGE_CREASE = 1 << 2,
};
-/* me->remesh_mode */
+/** #Mesh.remesh_mode */
enum {
REMESH_VOXEL = 0,
REMESH_QUAD = 1,
};
-/* Subsurf Type */
+/** #SubsurfModifierData.subdivType */
enum {
ME_CC_SUBSURF = 0,
ME_SIMPLE_SUBSURF = 1,
};
-/* me->symmetry */
+/** #Mesh.symmetry */
typedef enum eMeshSymmetryType {
ME_SYMMETRY_X = 1 << 0,
ME_SYMMETRY_Y = 1 << 1,
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index f7a468264c3..fc041e257b0 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -121,28 +121,28 @@ typedef struct ModifierData {
int type, mode;
char _pad0[4];
short flag;
- /* An "expand" bit for each of the modifier's (sub)panels (uiPanelDataExpansion). */
+ /** An "expand" bit for each of the modifier's (sub)panels (#uiPanelDataExpansion). */
short ui_expand_flag;
/** MAX_NAME. */
char name[64];
char *error;
- /* Pointer to a ModifierData in the original domain. */
+ /** Pointer to a #ModifierData in the original domain. */
struct ModifierData *orig_modifier_data;
- /* Runtime field which contains unique identifier of the modifier. */
+ /** Runtime field which contains unique identifier of the modifier. */
SessionUUID session_uuid;
- /* Runtime field which contains runtime data which is specific to a modifier type. */
+ /** Runtime field which contains runtime data which is specific to a modifier type. */
void *runtime;
void *_pad1;
} ModifierData;
typedef enum {
- /* This modifier has been inserted in local override, and hence can be fully edited. */
+ /** This modifier has been inserted in local override, and hence can be fully edited. */
eModifierFlag_OverrideLibrary_Local = (1 << 0),
- /* This modifier does not own its caches, but instead shares them with another modifier. */
+ /** This modifier does not own its caches, but instead shares them with another modifier. */
eModifierFlag_SharedCaches = (1 << 1),
/**
* This modifier is the object's active modifier. Used for context in the node editor.
@@ -151,7 +151,9 @@ typedef enum {
eModifierFlag_Active = (1 << 2),
} ModifierFlag;
-/* not a real modifier */
+/**
+ * \note Not a real modifier.
+ */
typedef struct MappingInfoModifierData {
ModifierData modifier;
@@ -194,6 +196,13 @@ typedef enum {
SUBSURF_BOUNDARY_SMOOTH_PRESERVE_CORNERS = 1,
} eSubsurfBoundarySmooth;
+typedef struct SubsurfRuntimeData {
+ /* Cached subdivision surface descriptor, with topology and settings. */
+ struct Subdiv *subdiv;
+ char set_by_draw_code;
+ char _pad[7];
+} SubsurfRuntimeData;
+
typedef struct SubsurfModifierData {
ModifierData modifier;
@@ -219,7 +228,7 @@ typedef struct LatticeModifierData {
void *_pad1;
} LatticeModifierData;
-/* Lattice modifier flags. */
+/** #LatticeModifierData.flag */
enum {
MOD_LATTICE_INVERT_VGROUP = (1 << 0),
};
@@ -237,12 +246,12 @@ typedef struct CurveModifierData {
void *_pad1;
} CurveModifierData;
-/* Curve modifier flags */
+/** #CurveModifierData.flag */
enum {
MOD_CURVE_INVERT_VGROUP = (1 << 0),
};
-/* CurveModifierData->defaxis */
+/** #CurveModifierData.defaxis */
enum {
MOD_CURVE_POSX = 1,
MOD_CURVE_POSY = 2,
@@ -264,7 +273,7 @@ typedef struct BuildModifierData {
int seed;
} BuildModifierData;
-/* Build Modifier -> flag */
+/** #BuildModifierData.flag */
enum {
/** order of vertices is randomized */
MOD_BUILD_FLAG_RANDOMIZE = (1 << 0),
@@ -272,7 +281,7 @@ enum {
MOD_BUILD_FLAG_REVERSE = (1 << 1),
};
-/* Mask Modifier */
+/** Mask Modifier. */
typedef struct MaskModifierData {
ModifierData modifier;
@@ -289,13 +298,13 @@ typedef struct MaskModifierData {
void *_pad1;
} MaskModifierData;
-/* Mask Modifier -> mode */
+/** #MaskModifierData.mode */
enum {
MOD_MASK_MODE_VGROUP = 0,
MOD_MASK_MODE_ARM = 1,
};
-/* Mask Modifier -> flag */
+/** #MaskModifierData.flag */
enum {
MOD_MASK_INV = (1 << 0),
MOD_MASK_SMOOTH = (1 << 1),
@@ -304,63 +313,68 @@ enum {
typedef struct ArrayModifierData {
ModifierData modifier;
- /* the object with which to cap the start of the array. */
+ /** The object with which to cap the start of the array. */
struct Object *start_cap;
- /* the object with which to cap the end of the array. */
+ /** The object with which to cap the end of the array. */
struct Object *end_cap;
- /* the curve object to use for MOD_ARR_FITCURVE. */
+ /** The curve object to use for #MOD_ARR_FITCURVE. */
struct Object *curve_ob;
- /* the object to use for object offset. */
+ /** The object to use for object offset. */
struct Object *offset_ob;
- /* a constant duplicate offset;
- * 1 means the duplicates are 1 unit apart
+ /**
+ * A constant duplicate offset;
+ * 1 means the duplicates are 1 unit apart.
*/
float offset[3];
- /* a scaled factor for duplicate offsets;
- * 1 means the duplicates are 1 object-width apart
+ /**
+ * A scaled factor for duplicate offsets;
+ * 1 means the duplicates are 1 object-width apart.
*/
float scale[3];
- /* the length over which to distribute the duplicates */
+ /** The length over which to distribute the duplicates. */
float length;
- /* the limit below which to merge vertices in adjacent duplicates */
+ /** The limit below which to merge vertices in adjacent duplicates. */
float merge_dist;
- /* determines how duplicate count is calculated; one of:
- * - MOD_ARR_FIXEDCOUNT -> fixed
- * - MOD_ARR_FITLENGTH -> calculated to fit a set length
- * - MOD_ARR_FITCURVE -> calculated to fit the length of a Curve object
+ /**
+ * Determines how duplicate count is calculated; one of:
+ * - #MOD_ARR_FIXEDCOUNT -> fixed.
+ * - #MOD_ARR_FITLENGTH -> calculated to fit a set length.
+ * - #MOD_ARR_FITCURVE -> calculated to fit the length of a Curve object.
*/
int fit_type;
- /* flags specifying how total offset is calculated; binary OR of:
- * - MOD_ARR_OFF_CONST -> total offset += offset
- * - MOD_ARR_OFF_RELATIVE -> total offset += relative * object width
- * - MOD_ARR_OFF_OBJ -> total offset += offset_ob's matrix
- * total offset is the sum of the individual enabled offsets
+ /**
+ * Flags specifying how total offset is calculated; binary OR of:
+ * - #MOD_ARR_OFF_CONST -> total offset += offset.
+ * - #MOD_ARR_OFF_RELATIVE -> total offset += relative * object width.
+ * - #MOD_ARR_OFF_OBJ -> total offset += offset_ob's matrix.
+ * Total offset is the sum of the individual enabled offsets.
*/
int offset_type;
- /* general flags:
- * MOD_ARR_MERGE -> merge vertices in adjacent duplicates
+ /**
+ * General flags:
+ * #MOD_ARR_MERGE -> merge vertices in adjacent duplicates.
*/
int flags;
- /* the number of duplicates to generate for MOD_ARR_FIXEDCOUNT */
+ /** The number of duplicates to generate for #MOD_ARR_FIXEDCOUNT. */
int count;
float uv_offset[2];
} ArrayModifierData;
-/* ArrayModifierData->fit_type */
+/** #ArrayModifierData.fit_type */
enum {
MOD_ARR_FIXEDCOUNT = 0,
MOD_ARR_FITLENGTH = 1,
MOD_ARR_FITCURVE = 2,
};
-/* ArrayModifierData->offset_type */
+/** #ArrayModifierData.offset_type */
enum {
MOD_ARR_OFF_CONST = (1 << 0),
MOD_ARR_OFF_RELATIVE = (1 << 1),
MOD_ARR_OFF_OBJ = (1 << 2),
};
-/* ArrayModifierData->flags */
+/** #ArrayModifierData.flags */
enum {
MOD_ARR_MERGE = (1 << 0),
MOD_ARR_MERGEFINAL = (1 << 1),
@@ -389,7 +403,7 @@ typedef struct MirrorModifierData {
void *_pad1;
} MirrorModifierData;
-/* MirrorModifierData->flag */
+/** #MirrorModifierData.flag */
enum {
MOD_MIR_CLIPPING = (1 << 0),
MOD_MIR_MIRROR_U = (1 << 1),
@@ -416,7 +430,7 @@ typedef struct EdgeSplitModifierData {
int flags;
} EdgeSplitModifierData;
-/* EdgeSplitModifierData->flags */
+/** #EdgeSplitModifierData.flags */
enum {
MOD_EDGESPLIT_FROMANGLE = (1 << 1),
MOD_EDGESPLIT_FROMFLAG = (1 << 2),
@@ -468,7 +482,7 @@ typedef struct BevelModifierData {
void *_pad2;
} BevelModifierData;
-/* BevelModifierData->flags and BevelModifierData->lim_flags */
+/** #BevelModifierData.flags and BevelModifierData.lim_flags */
enum {
#ifdef DNA_DEPRECATED_ALLOW
MOD_BEVEL_VERT_DEPRECATED = (1 << 1),
@@ -491,7 +505,7 @@ enum {
MOD_BEVEL_HARDEN_NORMALS = (1 << 15),
};
-/* BevelModifierData->val_flags (not used as flags any more) */
+/** #BevelModifierData.val_flags (not used as flags any more) */
enum {
MOD_BEVEL_AMT_OFFSET = 0,
MOD_BEVEL_AMT_WIDTH = 1,
@@ -500,19 +514,19 @@ enum {
MOD_BEVEL_AMT_ABSOLUTE = 4,
};
-/* BevelModifierData->profile_type */
+/** #BevelModifierData.profile_type */
enum {
MOD_BEVEL_PROFILE_SUPERELLIPSE = 0,
MOD_BEVEL_PROFILE_CUSTOM = 1,
};
-/* BevelModifierData->edge_flags */
+/** #BevelModifierData.edge_flags */
enum {
MOD_BEVEL_MARK_SEAM = (1 << 0),
MOD_BEVEL_MARK_SHARP = (1 << 1),
};
-/* BevelModifierData->face_str_mode */
+/** #BevelModifierData.face_str_mode */
enum {
MOD_BEVEL_FACE_STRENGTH_NONE = 0,
MOD_BEVEL_FACE_STRENGTH_NEW = 1,
@@ -520,20 +534,20 @@ enum {
MOD_BEVEL_FACE_STRENGTH_ALL = 3,
};
-/* BevelModifier->miter_inner and ->miter_outer */
+/** #BevelModifier.miter_inner & #BevelModifier.miter_outer */
enum {
MOD_BEVEL_MITER_SHARP = 0,
MOD_BEVEL_MITER_PATCH = 1,
MOD_BEVEL_MITER_ARC = 2,
};
-/* BevelModifier->vmesh_method */
+/** #BevelModifier.vmesh_method */
enum {
MOD_BEVEL_VMESH_ADJ = 0,
MOD_BEVEL_VMESH_CUTOFF = 1,
};
-/* BevelModifier->affect_type */
+/** #BevelModifier.affect_type */
enum {
MOD_BEVEL_AFFECT_VERTICES = 0,
MOD_BEVEL_AFFECT_EDGES = 1,
@@ -553,7 +567,7 @@ typedef struct FluidModifierData {
void *_pad1;
} FluidModifierData;
-/* Fluid modifier flags */
+/** #FluidModifierData.type */
enum {
MOD_FLUID_TYPE_DOMAIN = (1 << 0),
MOD_FLUID_TYPE_FLOW = (1 << 1),
@@ -563,7 +577,8 @@ enum {
typedef struct DisplaceModifierData {
ModifierData modifier;
- /* keep in sync with MappingInfoModifierData */
+ /* Keep in sync with #MappingInfoModifierData. */
+
struct Tex *texture;
struct Object *map_object;
char map_bone[64];
@@ -583,12 +598,12 @@ typedef struct DisplaceModifierData {
char _pad[6];
} DisplaceModifierData;
-/* DisplaceModifierData->flag */
+/** #DisplaceModifierData.flag */
enum {
MOD_DISP_INVERT_VGROUP = (1 << 0),
};
-/* DisplaceModifierData->direction */
+/** #DisplaceModifierData.direction */
enum {
MOD_DISP_DIR_X = 0,
MOD_DISP_DIR_Y = 1,
@@ -598,7 +613,7 @@ enum {
MOD_DISP_DIR_CLNOR = 5,
};
-/* DisplaceModifierData->texmapping */
+/** #DisplaceModifierData.texmapping */
enum {
MOD_DISP_MAP_LOCAL = 0,
MOD_DISP_MAP_GLOBAL = 1,
@@ -606,7 +621,7 @@ enum {
MOD_DISP_MAP_UV = 3,
};
-/* DisplaceModifierData->space */
+/** #DisplaceModifierData.space */
enum {
MOD_DISP_SPACE_LOCAL = 0,
MOD_DISP_SPACE_GLOBAL = 1,
@@ -614,9 +629,10 @@ enum {
typedef struct UVProjectModifierData {
ModifierData modifier;
-
- /* the objects which do the projecting */
- /** MOD_UVPROJECT_MAXPROJECTORS. */
+ /**
+ * The objects which do the projecting.
+ * \note 10=MOD_UVPROJECT_MAXPROJECTORS.
+ */
struct Object *projectors[10];
char _pad2[4];
int num_projectors;
@@ -649,7 +665,7 @@ typedef struct DecimateModifierData {
float defgrp_factor;
short flag, mode;
- /* runtime only */
+ /** runtime only. */
int face_count;
} DecimateModifierData;
@@ -678,7 +694,7 @@ typedef struct SmoothModifierData {
} SmoothModifierData;
-/* Smooth modifier flags */
+/** #SmoothModifierData.flag */
enum {
MOD_SMOOTH_INVERT_VGROUP = (1 << 0),
MOD_SMOOTH_X = (1 << 1),
@@ -695,11 +711,13 @@ typedef struct CastModifierData {
float size;
/** MAX_VGROUP_NAME. */
char defgrp_name[64];
- short flag, type;
+ short flag;
+ /** Cast modifier projection type. */
+ short type;
void *_pad1;
} CastModifierData;
-/* Cast modifier flags */
+/** #CastModifierData.flag */
enum {
/* And what bout (1 << 0) flag? ;) */
MOD_CAST_INVERT_VGROUP = (1 << 0),
@@ -710,7 +728,7 @@ enum {
MOD_CAST_SIZE_FROM_RADIUS = (1 << 5),
};
-/* Cast modifier projection types */
+/** #CastModifierData.type */
enum {
MOD_CAST_TYPE_SPHERE = 0,
MOD_CAST_TYPE_CYLINDER = 1,
@@ -720,7 +738,8 @@ enum {
typedef struct WaveModifierData {
ModifierData modifier;
- /* keep in sync with MappingInfoModifierData */
+ /* Keep in sync with #MappingInfoModifierData. */
+
struct Tex *texture;
struct Object *map_object;
char map_bone[64];
@@ -728,7 +747,7 @@ typedef struct WaveModifierData {
char uvlayer_name[64];
int uvlayer_tmp;
int texmapping;
- /* end MappingInfoModifierData */
+ /* End MappingInfoModifierData. */
struct Object *objectcenter;
/** MAX_VGROUP_NAME. */
@@ -745,7 +764,7 @@ typedef struct WaveModifierData {
void *_pad2;
} WaveModifierData;
-/* WaveModifierData.flag */
+/** #WaveModifierData.flag */
enum {
MOD_WAVE_INVERT_VGROUP = (1 << 0),
MOD_WAVE_X = (1 << 1),
@@ -775,7 +794,7 @@ enum {
MOD_HOOK_INVERT_VGROUP = (1 << 1),
};
-/* same as WarpModifierFalloff */
+/** \note same as #WarpModifierFalloff */
typedef enum {
eHook_Falloff_None = 0,
eHook_Falloff_Curve = 1,
@@ -832,15 +851,17 @@ typedef struct ClothModifierData {
/** Definition is in DNA_cloth_types.h. */
struct ClothCollSettings *coll_parms;
- /* PointCache can be shared with other instances of ClothModifierData.
- * Inspect (modifier.flag & eModifierFlag_SharedCaches) to find out. */
+ /**
+ * PointCache can be shared with other instances of #ClothModifierData.
+ * Inspect `modifier.flag & eModifierFlag_SharedCaches` to find out.
+ */
/** Definition is in DNA_object_force_types.h. */
struct PointCache *point_cache;
struct ListBase ptcaches;
- /* XXX nasty hack, remove once hair can be separated from cloth modifier data */
+ /** XXX: nasty hack, remove once hair can be separated from cloth modifier data. */
struct ClothHairData *hairdata;
- /* grid geometry values of hair continuum */
+ /** Grid geometry values of hair continuum. */
float hair_grid_min[3];
float hair_grid_max[3];
int hair_grid_res[3];
@@ -907,20 +928,20 @@ typedef struct BooleanModifierData {
char bm_flag;
} BooleanModifierData;
-/* BooleanModifierData->operation */
+/** #BooleanModifierData.operation */
typedef enum {
eBooleanModifierOp_Intersect = 0,
eBooleanModifierOp_Union = 1,
eBooleanModifierOp_Difference = 2,
} BooleanModifierOp;
-/* BooleanModifierData->solver */
+/** #BooleanModifierData.solver */
typedef enum {
eBooleanModifierSolver_Fast = 0,
eBooleanModifierSolver_Exact = 1,
} BooleanModifierSolver;
-/* BooleanModifierData->flag */
+/** #BooleanModifierData.flag */
enum {
eBooleanModifierFlag_Self = (1 << 0),
eBooleanModifierFlag_Object = (1 << 1),
@@ -928,7 +949,7 @@ enum {
eBooleanModifierFlag_HoleTolerant = (1 << 3),
};
-/* bm_flag only used when G_DEBUG. */
+/** #BooleanModifierData.bm_flag (only used when #G_DEBUG is set). */
enum {
eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 0),
eBooleanModifierBMeshFlag_BMesh_NoDissolve = (1 << 1),
@@ -1102,7 +1123,7 @@ typedef enum {
eMultiresModifierFlag_UseSculptBaseMesh = (1 << 4),
} MultiresModifierFlag;
-/* DEPRECATED, only used for versioning. */
+/** DEPRECATED: only used for versioning. */
typedef struct FluidsimModifierData {
ModifierData modifier;
@@ -1111,7 +1132,7 @@ typedef struct FluidsimModifierData {
void *_pad1;
} FluidsimModifierData;
-/* DEPRECATED, only used for versioning. */
+/** DEPRECATED: only used for versioning. */
typedef struct SmokeModifierData {
ModifierData modifier;
@@ -1150,7 +1171,7 @@ typedef struct ShrinkwrapModifierData {
char _pad[2];
} ShrinkwrapModifierData;
-/* Shrinkwrap->shrinkType */
+/** #ShrinkwrapModifierData.shrinkType */
enum {
MOD_SHRINKWRAP_NEAREST_SURFACE = 0,
MOD_SHRINKWRAP_PROJECT = 1,
@@ -1158,7 +1179,7 @@ enum {
MOD_SHRINKWRAP_TARGET_PROJECT = 3,
};
-/* Shrinkwrap->shrinkMode */
+/** #ShrinkwrapModifierData.shrinkMode */
enum {
/** Move vertex to the surface of the target object (keepDist towards original position) */
MOD_SHRINKWRAP_ON_SURFACE = 0,
@@ -1172,7 +1193,7 @@ enum {
MOD_SHRINKWRAP_ABOVE_SURFACE = 4,
};
-/* Shrinkwrap->shrinkOpts */
+/** #ShrinkwrapModifierData.shrinkOpts */
enum {
/** allow shrinkwrap to move the vertex in the positive direction of axis */
MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR = (1 << 0),
@@ -1196,7 +1217,7 @@ enum {
#define MOD_SHRINKWRAP_CULL_TARGET_MASK \
(MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)
-/* Shrinkwrap->projAxis */
+/** #ShrinkwrapModifierData.projAxis */
enum {
/** projection over normal is used if no axis is selected */
MOD_SHRINKWRAP_PROJECT_OVER_NORMAL = 0,
@@ -1228,7 +1249,7 @@ typedef struct SimpleDeformModifierData {
void *_pad1;
} SimpleDeformModifierData;
-/* SimpleDeform->flag */
+/** #SimpleDeformModifierData.flag */
enum {
MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP = (1 << 0),
};
@@ -1434,7 +1455,9 @@ enum {
typedef struct WarpModifierData {
ModifierData modifier;
- /* keep in sync with MappingInfoModifierData */
+
+ /* Keep in sync with #MappingInfoModifierData. */
+
struct Tex *texture;
struct Object *map_object;
char map_bone[64];
@@ -1442,7 +1465,7 @@ typedef struct WarpModifierData {
char uvlayer_name[64];
int uvlayer_tmp;
int texmapping;
- /* end MappingInfoModifierData */
+ /* End #MappingInfoModifierData. */
struct Object *object_from;
struct Object *object_to;
@@ -1462,12 +1485,13 @@ typedef struct WarpModifierData {
void *_pad1;
} WarpModifierData;
-/* WarpModifierData->flag */
+/** #WarpModifierData.flag */
enum {
MOD_WARP_VOLUME_PRESERVE = (1 << 0),
MOD_WARP_INVERT_VGROUP = (1 << 1),
};
+/** \note same as #HookModifierFalloff. */
typedef enum {
eWarp_Falloff_None = 0,
eWarp_Falloff_Curve = 1,
@@ -1508,7 +1532,7 @@ typedef struct WeightVGEditModifierData {
char mask_defgrp_name[64];
/* Texture masking. */
- /** Which channel to use as weightf. */
+ /** Which channel to use as weight/mask. */
int mask_tex_use_channel;
/** The texture. */
struct Tex *mask_texture;
@@ -1526,7 +1550,7 @@ typedef struct WeightVGEditModifierData {
void *_pad1;
} WeightVGEditModifierData;
-/* WeightVGEdit flags. */
+/** #WeightVGEdit.edit_flags */
enum {
MOD_WVG_EDIT_WEIGHTS_NORMALIZE = (1 << 0),
MOD_WVG_INVERT_FALLOFF = (1 << 1),
@@ -1581,7 +1605,7 @@ typedef struct WeightVGMixModifierData {
char _pad1[3];
} WeightVGMixModifierData;
-/* How second vgroup's weights affect first ones. */
+/** #WeightVGMixModifierData.mix_mode (how second vgroup's weights affect first ones). */
enum {
/** Second weights replace weights. */
MOD_WVG_MIX_SET = 1,
@@ -1599,7 +1623,7 @@ enum {
MOD_WVG_MIX_AVG = 7,
};
-/* What vertices to affect. */
+/** #WeightVGMixModifierData.mix_set (what vertices to affect). */
enum {
/** Affect all vertices. */
MOD_WVG_SET_ALL = 1,
@@ -1613,7 +1637,7 @@ enum {
MOD_WVG_SET_AND = 5,
};
-/* WeightVGMix->flag */
+/** #WeightVGMixModifierData.flag */
enum {
MOD_WVG_MIX_INVERT_VGROUP_MASK = (1 << 0),
MOD_WVG_MIX_WEIGHTS_NORMALIZE = (1 << 1),
@@ -1631,8 +1655,9 @@ typedef struct WeightVGProximityModifierData {
/** The custom mapping curve. */
struct CurveMapping *cmap_curve;
- /* Proximity modes. */
+ /** Modes of proximity weighting. */
int proximity_mode;
+ /** Options for proximity weighting. */
int proximity_flags;
/* Target object from which to calculate vertices distances. */
@@ -1662,20 +1687,21 @@ typedef struct WeightVGProximityModifierData {
float min_dist, max_dist;
/* Put here to avoid breaking existing struct... */
- /** Using MOD_WVG_MAPPING_* enums. */
+ /**
+ * Mapping modes (using MOD_WVG_MAPPING_* enums). */
short falloff_type;
/* Padding... */
char _pad0[2];
} WeightVGProximityModifierData;
-/* Modes of proximity weighting. */
+/** #WeightVGProximityModifierData.proximity_mode */
enum {
MOD_WVG_PROXIMITY_OBJECT = 1, /* source vertex to other location */
MOD_WVG_PROXIMITY_GEOMETRY = 2, /* source vertex to other geometry */
};
-/* Flags options for proximity weighting. */
+/** #WeightVGProximityModifierData.proximity_flags */
enum {
/* Use nearest vertices of target obj, in MOD_WVG_PROXIMITY_GEOMETRY mode. */
MOD_WVG_PROXIMITY_GEOM_VERTS = (1 << 0),
@@ -1689,7 +1715,8 @@ enum {
};
/* Defines common to all WeightVG modifiers. */
-/* Mapping modes. */
+
+/** #WeightVGProximityModifierData.falloff_type */
enum {
MOD_WVG_MAPPING_NONE = 0,
MOD_WVG_MAPPING_CURVE = 1,
@@ -1703,7 +1730,7 @@ enum {
MOD_WVG_MAPPING_STEP = 9, /* Median Step. */
};
-/* Tex channel to be used as mask. */
+/** #WeightVGProximityModifierData.mask_tex_use_channel */
enum {
MOD_WVG_MASK_TEX_USE_INT = 1,
MOD_WVG_MASK_TEX_USE_RED = 2,
@@ -1725,13 +1752,13 @@ typedef struct DynamicPaintModifierData {
char _pad[4];
} DynamicPaintModifierData;
-/* Dynamic paint modifier flags */
+/** #DynamicPaintModifierData.type */
enum {
MOD_DYNAMICPAINT_TYPE_CANVAS = (1 << 0),
MOD_DYNAMICPAINT_TYPE_BRUSH = (1 << 1),
};
-/* Remesh modifier */
+/** Remesh modifier. */
typedef enum eRemeshModifierFlags {
MOD_REMESH_FLOOD_FILL = (1 << 0),
MOD_REMESH_SMOOTH_SHADING = (1 << 1),
@@ -1770,7 +1797,7 @@ typedef struct RemeshModifierData {
float adaptivity;
} RemeshModifierData;
-/* Skin modifier */
+/** Skin modifier. */
typedef struct SkinModifierData {
ModifierData modifier;
@@ -1783,19 +1810,19 @@ typedef struct SkinModifierData {
char _pad[2];
} SkinModifierData;
-/* SkinModifierData.symmetry_axes */
+/** #SkinModifierData.symmetry_axes */
enum {
MOD_SKIN_SYMM_X = (1 << 0),
MOD_SKIN_SYMM_Y = (1 << 1),
MOD_SKIN_SYMM_Z = (1 << 2),
};
-/* SkinModifierData.flag */
+/** #SkinModifierData.flag */
enum {
MOD_SKIN_SMOOTH_SHADING = 1,
};
-/* Triangulate modifier */
+/** Triangulate modifier. */
typedef struct TriangulateModifierData {
ModifierData modifier;
@@ -1805,7 +1832,7 @@ typedef struct TriangulateModifierData {
int min_vertices;
} TriangulateModifierData;
-/* TriangulateModifierData.flag */
+/** #TriangulateModifierData.flag */
enum {
#ifdef DNA_DEPRECATED_ALLOW
MOD_TRIANGULATE_BEAUTY = (1 << 0), /* deprecated */
@@ -1813,13 +1840,13 @@ enum {
MOD_TRIANGULATE_KEEP_CUSTOMLOOP_NORMALS = 1 << 1,
};
-/* Triangulate methods - NGons */
+/** #TriangulateModifierData.ngon_method triangulate method (N-gons). */
enum {
MOD_TRIANGULATE_NGON_BEAUTY = 0,
MOD_TRIANGULATE_NGON_EARCLIP = 1,
};
-/* Triangulate methods - Quads */
+/** #TriangulateModifierData.quad_method triangulate method (quads). */
enum {
MOD_TRIANGULATE_QUAD_BEAUTY = 0,
MOD_TRIANGULATE_QUAD_FIXED = 1,
@@ -1837,7 +1864,7 @@ typedef struct LaplacianSmoothModifierData {
short flag, repeat;
} LaplacianSmoothModifierData;
-/* Smooth modifier flags */
+/** #LaplacianSmoothModifierData.flag */
enum {
MOD_LAPLACIANSMOOTH_X = (1 << 1),
MOD_LAPLACIANSMOOTH_Y = (1 << 2),
@@ -1892,7 +1919,7 @@ enum {
MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND = 1,
};
-/* Corrective Smooth modifier flags */
+/** #CorrectiveSmoothModifierData.flag */
enum {
MOD_CORRECTIVESMOOTH_INVERT_VGROUP = (1 << 0),
MOD_CORRECTIVESMOOTH_ONLY_SMOOTH = (1 << 1),
@@ -1926,12 +1953,12 @@ typedef struct UVWarpModifierData {
char uvlayer_name[64];
} UVWarpModifierData;
-/* UVWarp modifier flags */
+/** #UVWarpModifierData.flag */
enum {
MOD_UVWARP_INVERT_VGROUP = 1 << 0,
};
-/* cache modifier */
+/** Mesh cache modifier. */
typedef struct MeshCacheModifierData {
ModifierData modifier;
@@ -1967,7 +1994,7 @@ typedef struct MeshCacheModifierData {
char filepath[1024];
} MeshCacheModifierData;
-/* MeshCache modifier flags. */
+/** #MeshCacheModifierData.flag */
enum {
MOD_MESHCACHE_INVERT_VERTEX_GROUP = 1 << 0,
};
@@ -2012,13 +2039,15 @@ typedef struct LaplacianDeformModifierData {
} LaplacianDeformModifierData;
-/* Laplacian Deform modifier flags */
+/** #LaplacianDeformModifierData.flag */
enum {
MOD_LAPLACIANDEFORM_BIND = 1 << 0,
MOD_LAPLACIANDEFORM_INVERT_VGROUP = 1 << 1,
};
-/* many of these options match 'solidify' */
+/**
+ * \note many of these options match 'solidify'.
+ */
typedef struct WireframeModifierData {
ModifierData modifier;
/** MAX_VGROUP_NAME. */
@@ -2053,13 +2082,13 @@ typedef struct WeldModifierData {
char _pad[2];
} WeldModifierData;
-/* WeldModifierData->flag */
+/** #WeldModifierData.flag */
enum {
MOD_WELD_INVERT_VGROUP = (1 << 0),
MOD_WELD_LOOSE_EDGES = (1 << 1),
};
-/* #WeldModifierData.mode */
+/** #WeldModifierData.mode */
enum {
MOD_WELD_MODE_ALL = 0,
MOD_WELD_MODE_CONNECTED = 1,
@@ -2100,7 +2129,7 @@ typedef struct DataTransferModifierData {
void *_pad2;
} DataTransferModifierData;
-/* DataTransferModifierData.flags */
+/** #DataTransferModifierData.flags */
enum {
MOD_DATATRANSFER_OBSRC_TRANSFORM = 1 << 0,
MOD_DATATRANSFER_MAP_MAXDIST = 1 << 1,
@@ -2113,7 +2142,7 @@ enum {
MOD_DATATRANSFER_USE_POLY = 1u << 31,
};
-/* Set Split Normals modifier */
+/** Set Split Normals modifier. */
typedef struct NormalEditModifierData {
ModifierData modifier;
/** MAX_VGROUP_NAME. */
@@ -2131,20 +2160,20 @@ typedef struct NormalEditModifierData {
void *_pad1;
} NormalEditModifierData;
-/* NormalEditModifierData.mode */
+/** #NormalEditModifierData.mode */
enum {
MOD_NORMALEDIT_MODE_RADIAL = 0,
MOD_NORMALEDIT_MODE_DIRECTIONAL = 1,
};
-/* NormalEditModifierData.flags */
+/** #NormalEditModifierData.flags */
enum {
MOD_NORMALEDIT_INVERT_VGROUP = (1 << 0),
MOD_NORMALEDIT_USE_DIRECTION_PARALLEL = (1 << 1),
MOD_NORMALEDIT_NO_POLYNORS_FIX = (1 << 2),
};
-/* NormalEditModifierData.mix_mode */
+/** #NormalEditModifierData.mix_mode */
enum {
MOD_NORMALEDIT_MIX_COPY = 0,
MOD_NORMALEDIT_MIX_ADD = 1,
@@ -2169,7 +2198,7 @@ typedef struct MeshSeqCacheModifierData {
char reader_object_path[1024];
} MeshSeqCacheModifierData;
-/* MeshSeqCacheModifierData.read_flag */
+/** #MeshSeqCacheModifierData.read_flag */
enum {
MOD_MESHSEQ_READ_VERT = (1 << 0),
MOD_MESHSEQ_READ_POLY = (1 << 1),
@@ -2214,7 +2243,7 @@ typedef struct SurfaceDeformModifierData {
void *_pad1;
} SurfaceDeformModifierData;
-/* Surface Deform modifier flags */
+/** Surface Deform modifier flags. */
enum {
/* This indicates "do bind on next modifier evaluation" as well as "is bound". */
MOD_SDEF_BIND = (1 << 0),
@@ -2223,7 +2252,7 @@ enum {
MOD_SDEF_SPARSE_BIND = (1 << 2),
};
-/* Surface Deform vertex bind modes */
+/** Surface Deform vertex bind modes. */
enum {
MOD_SDEF_MODE_LOOPTRI = 0,
MOD_SDEF_MODE_NGON = 1,
@@ -2243,14 +2272,14 @@ typedef struct WeightedNormalModifierData {
/* Name/id of the generic PROP_INT cdlayer storing face weights. */
#define MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID "__mod_weightednormals_faceweight"
-/* WeightedNormalModifierData.mode */
+/** #WeightedNormalModifierData.mode */
enum {
MOD_WEIGHTEDNORMAL_MODE_FACE = 0,
MOD_WEIGHTEDNORMAL_MODE_ANGLE = 1,
MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE = 2,
};
-/* WeightedNormalModifierData.flag */
+/** #WeightedNormalModifierData.flag */
enum {
MOD_WEIGHTEDNORMAL_KEEP_SHARP = (1 << 0),
MOD_WEIGHTEDNORMAL_INVERT_VGROUP = (1 << 1),
@@ -2270,8 +2299,10 @@ typedef struct NodesModifierData {
struct bNodeTree *node_group;
struct NodesModifierSettings settings;
- /* Contains logged information from the last evaluation. This can be used to help the user to
- * debug a node tree. */
+ /**
+ * Contains logged information from the last evaluation.
+ * This can be used to help the user to debug a node tree.
+ */
void *runtime_eval_log;
void *_pad1;
} NodesModifierData;
@@ -2304,7 +2335,7 @@ typedef struct MeshToVolumeModifierData {
void *_pad3;
} MeshToVolumeModifierData;
-/* MeshToVolumeModifierData->resolution_mode */
+/** #MeshToVolumeModifierData.resolution_mode */
typedef enum MeshToVolumeModifierResolutionMode {
MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT = 0,
MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE = 1,
@@ -2322,7 +2353,7 @@ typedef struct VolumeDisplaceModifierData {
float texture_sample_radius;
} VolumeDisplaceModifierData;
-/* VolumeDisplaceModifierData->texture_map_mode */
+/** #VolumeDisplaceModifierData.texture_map_mode */
enum {
MOD_VOLUME_DISPLACE_MAP_LOCAL = 0,
MOD_VOLUME_DISPLACE_MAP_GLOBAL = 1,
diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h
index 8e01a9e1f1f..08064e6242b 100644
--- a/source/blender/makesdna/DNA_movieclip_types.h
+++ b/source/blender/makesdna/DNA_movieclip_types.h
@@ -160,7 +160,7 @@ typedef struct MovieClipScopes {
float slide_scale[2];
} MovieClipScopes;
-/* MovieClipProxy->build_size_flag */
+/** #MovieClipProxy.build_size_flag */
enum {
MCLIP_PROXY_SIZE_25 = (1 << 0),
MCLIP_PROXY_SIZE_50 = (1 << 1),
@@ -172,13 +172,13 @@ enum {
MCLIP_PROXY_UNDISTORTED_SIZE_100 = (1 << 7),
};
-/* MovieClip->source */
+/** #MovieClip.source */
enum {
MCLIP_SRC_SEQUENCE = 1,
MCLIP_SRC_MOVIE = 2,
};
-/* MovieClip->flag */
+/** #MovieClip.flag */
enum {
MCLIP_USE_PROXY = (1 << 0),
MCLIP_USE_PROXY_CUSTOM_DIR = (1 << 1),
@@ -188,7 +188,7 @@ enum {
MCLIP_TIMECODE_FLAGS = (MCLIP_USE_PROXY | MCLIP_USE_PROXY_CUSTOM_DIR),
};
-/* MovieClip->render_size */
+/** #MovieClip.render_size */
enum {
MCLIP_PROXY_RENDER_SIZE_FULL = 0,
MCLIP_PROXY_RENDER_SIZE_25 = 1,
@@ -197,7 +197,7 @@ enum {
MCLIP_PROXY_RENDER_SIZE_100 = 4,
};
-/* MovieClip->render_flag */
+/** #MovieClip.render_flag */
enum {
MCLIP_PROXY_RENDER_UNDISTORT = 1,
/** Use original, if proxy is not found. */
diff --git a/source/blender/makesdna/DNA_nla_types.h b/source/blender/makesdna/DNA_nla_types.h
index 7808dd68384..82edc0e1816 100644
--- a/source/blender/makesdna/DNA_nla_types.h
+++ b/source/blender/makesdna/DNA_nla_types.h
@@ -33,7 +33,7 @@ struct Ipo;
struct Object;
struct bAction;
-/* simple uniform modifier structure, assumed it can hold all type info */
+/** Simple uniform modifier structure, assumed it can hold all type info. */
typedef struct bActionModifier {
struct bActionModifier *next, *prev;
short type, flag;
@@ -95,7 +95,7 @@ typedef struct bActionStrip {
#define ACTSTRIPMODE_BLEND 0
#define ACTSTRIPMODE_ADD 1
-/* strip->flag */
+/** #bActionStrip.flag */
typedef enum eActStrip_Flag {
ACTSTRIP_SELECT = (1 << 0),
ACTSTRIP_USESTRIDE = (1 << 1),
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index dc5acb9d5b2..e349dfd8704 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -95,7 +95,7 @@ typedef struct SocketDeclarationHandle SocketDeclarationHandle;
#endif
typedef struct bNodeSocket {
- struct bNodeSocket *next, *prev, *new_sock;
+ struct bNodeSocket *next, *prev;
/** User-defined properties. */
IDProperty *prop;
@@ -159,7 +159,7 @@ typedef struct bNodeSocket {
* restores pointer from matching own_index. */
struct bNodeSocket *groupsock DNA_DEPRECATED;
- /** A link pointer, set in ntreeUpdateTree. */
+ /** A link pointer, set in #BKE_ntree_update_main. */
struct bNodeLink *link;
/* XXX deprecated, socket input values are stored in default_value now.
@@ -172,9 +172,13 @@ typedef struct bNodeSocket {
* data. It has to be updated when the node declaration changes.
*/
const SocketDeclarationHandle *declaration;
+
+ /** #eNodeTreeChangedFlag. */
+ uint32_t changed_flag;
+ char _pad[4];
} bNodeSocket;
-/* sock->type */
+/** #bNodeSocket.type & #bNodeSocketType.type */
typedef enum eNodeSocketDatatype {
SOCK_CUSTOM = -1, /* socket has no integer type */
SOCK_FLOAT = 0,
@@ -193,7 +197,7 @@ typedef enum eNodeSocketDatatype {
SOCK_MATERIAL = 13,
} eNodeSocketDatatype;
-/* Socket shape. */
+/** Socket shape. */
typedef enum eNodeSocketDisplayShape {
SOCK_DISPLAY_SHAPE_CIRCLE = 0,
SOCK_DISPLAY_SHAPE_SQUARE = 1,
@@ -203,13 +207,13 @@ typedef enum eNodeSocketDisplayShape {
SOCK_DISPLAY_SHAPE_DIAMOND_DOT = 5,
} eNodeSocketDisplayShape;
-/* Socket side (input/output). */
+/** Socket side (input/output). */
typedef enum eNodeSocketInOut {
SOCK_IN = 1 << 0,
SOCK_OUT = 1 << 1,
} eNodeSocketInOut;
-/* #bNodeSocket.flag, first bit is selection. */
+/** #bNodeSocket.flag, first bit is selection. */
typedef enum eNodeSocketFlag {
/** Hidden is user defined, to hide unused sockets. */
SOCK_HIDDEN = (1 << 1),
@@ -239,9 +243,9 @@ typedef enum eNodeSocketFlag {
SOCK_HIDE_LABEL = (1 << 12),
} eNodeSocketFlag;
-/* TODO: Limit data in bNode to what we want to see saved. */
+/** TODO: Limit data in #bNode to what we want to see saved. */
typedef struct bNode {
- struct bNode *next, *prev, *new_node;
+ struct bNode *next, *prev;
/** User-defined properties. */
IDProperty *prop;
@@ -260,8 +264,9 @@ typedef struct bNode {
/** Used as a boolean for execution. */
uint8_t need_exec;
-
- char _pad[1];
+ char _pad2[5];
+ /** #eNodeTreeChangedFlag. */
+ uint32_t changed_flag;
/** Custom user-defined color. */
float color[3];
@@ -400,10 +405,6 @@ typedef struct bNode {
#define __NODE_ACTIVE_PREVIEW (1 << 18) /* deprecated */
/* node->update */
-/* XXX NODE_UPDATE is a generic update flag. More fine-grained updates
- * might be used in the future, but currently all work the same way.
- */
-#define NODE_UPDATE 0xFFFF /* generic update flag (includes all others) */
#define NODE_UPDATE_ID 1 /* associated id data block has changed */
#define NODE_UPDATE_OPERATOR 2 /* node update triggered from update operator */
@@ -511,8 +512,12 @@ typedef struct bNodeTree {
*/
int cur_index;
int flag;
- /** Update flags. */
- int update;
+ /**
+ * Keeps track of what changed in the node tree until the next update.
+ * Should not be changed directly, instead use the functions in `BKE_node_tree_update.h`.
+ * #eNodeTreeChangedFlag.
+ */
+ uint32_t changed_flag;
/** Flag to prevent re-entrant update calls. */
short is_updating;
/** Generic temporary flag for recursion check (DFS/BFS). */
@@ -546,7 +551,11 @@ typedef struct bNodeTree {
* in case multiple different editors are used and make context ambiguous.
*/
bNodeInstanceKey active_viewer_key;
- char _pad[4];
+ /**
+ * A hash of the topology of the node tree leading up to the outputs. This is used to determine
+ * of the node tree changed in a way that requires updating geometry nodes or shaders.
+ */
+ uint32_t output_topology_hash;
/** Execution data.
*
@@ -571,7 +580,7 @@ typedef struct bNodeTree {
struct PreviewImage *preview;
} bNodeTree;
-/* ntree->type, index */
+/** #NodeTree.type, index */
#define NTREE_UNDEFINED -2 /* Represents #NodeTreeTypeUndefined type. */
#define NTREE_CUSTOM -1 /* for dynamically registered custom types */
@@ -580,10 +589,10 @@ typedef struct bNodeTree {
#define NTREE_TEXTURE 2
#define NTREE_GEOMETRY 3
-/* ntree->init, flag */
+/** #NodeTree.init, flag */
#define NTREE_TYPE_INIT 1
-/* ntree->flag */
+/** #NodeTree.flag */
#define NTREE_DS_EXPAND (1 << 0) /* for animation editors */
#define NTREE_COM_OPENCL (1 << 1) /* use opencl */
#define NTREE_TWO_PASS (1 << 2) /* two pass */
@@ -594,20 +603,6 @@ typedef struct bNodeTree {
/* tree is localized copy, free when deleting node groups */
/* #define NTREE_IS_LOCALIZED (1 << 5) */
-/* ntree->update */
-typedef enum eNodeTreeUpdate {
- NTREE_UPDATE = 0xFFFF, /* generic update flag (includes all others) */
- NTREE_UPDATE_LINKS = (1 << 0), /* links have been added or removed */
- NTREE_UPDATE_NODES = (1 << 1), /* nodes or sockets have been added or removed */
- NTREE_UPDATE_GROUP_IN = (1 << 4), /* group inputs have changed */
- NTREE_UPDATE_GROUP_OUT = (1 << 5), /* group outputs have changed */
- /* The field interface has changed. So e.g. an output that was always a field before is not
- * anymore. This implies that the field type inferencing has to be done again. */
- NTREE_UPDATE_FIELD_INFERENCING = (1 << 6),
- /* group has changed (generic flag including all other group flags) */
- NTREE_UPDATE_GROUP = (NTREE_UPDATE_GROUP_IN | NTREE_UPDATE_GROUP_OUT),
-} eNodeTreeUpdate;
-
/* tree->execution_mode */
typedef enum eNodeTreeExecutionMode {
NTREE_EXECUTION_MODE_TILED = 0,
@@ -674,7 +669,8 @@ typedef struct bNodeSocketValueMaterial {
struct Material *value;
} bNodeSocketValueMaterial;
-/* Data structs, for node->storage. */
+/* Data structs, for `node->storage`. */
+
enum {
CMP_NODE_MASKTYPE_ADD = 0,
CMP_NODE_MASKTYPE_SUBTRACT = 1,
@@ -713,7 +709,7 @@ typedef struct NodeFrame {
short label_size;
} NodeFrame;
-/* This one has been replaced with ImageUser, keep it for do_versions(). */
+/** \note This one has been replaced with #ImageUser, keep it for do_versions(). */
typedef struct NodeImageAnim {
int frames DNA_DEPRECATED;
int sfra DNA_DEPRECATED;
@@ -767,7 +763,7 @@ typedef struct NodeEllipseMask {
char _pad[4];
} NodeEllipseMask;
-/* Layer info for image node outputs. */
+/** Layer info for image node outputs. */
typedef struct NodeImageLayer {
/* index in the Image->layers->passes lists */
int pass_index DNA_DEPRECATED;
@@ -805,7 +801,7 @@ typedef struct NodeAntiAliasingData {
float corner_rounding;
} NodeAntiAliasingData;
-/* NOTE: Only for do-version code. */
+/** \note Only for do-version code. */
typedef struct NodeHueSat {
float hue, sat, val;
} NodeHueSat;
@@ -817,7 +813,9 @@ typedef struct NodeImageFile {
int sfra, efra;
} NodeImageFile;
-/* XXX first struct fields should match NodeImageFile to ensure forward compatibility */
+/**
+ * XXX: first struct fields should match #NodeImageFile to ensure forward compatibility.
+ */
typedef struct NodeImageMultiFile {
/** 1024 = FILE_MAX. */
char base_path[1024];
@@ -1066,7 +1064,7 @@ typedef struct NodeShaderPrincipled {
char _pad[3];
} NodeShaderPrincipled;
-/* TEX_output */
+/** TEX_output. */
typedef struct TexNodeOutput {
char name[64];
} TexNodeOutput;
@@ -1266,6 +1264,13 @@ typedef struct NodeRandomValue {
uint8_t data_type;
} NodeRandomValue;
+typedef struct NodeAccumulateField {
+ /* CustomDataType. */
+ uint8_t data_type;
+ /* AttributeDomain. */
+ uint8_t domain;
+} NodeAccumulateField;
+
typedef struct NodeAttributeRandomize {
/* CustomDataType. */
uint8_t data_type;
@@ -1632,14 +1637,17 @@ typedef struct NodeFunctionCompare {
#define NODE_IES_INTERNAL 0
#define NODE_IES_EXTERNAL 1
-/* frame node flags */
+/* Frame node flags. */
+
#define NODE_FRAME_SHRINK 1 /* keep the bounding box minimal */
#define NODE_FRAME_RESIZEABLE 2 /* test flag, if frame can be resized by user */
-/* proxy node flags */
+/* Proxy node flags. */
+
#define NODE_PROXY_AUTOTYPE 1 /* automatically change output type based on link */
-/* comp channel matte */
+/* Comp channel matte. */
+
#define CMP_NODE_CHANNEL_MATTE_CS_RGB 1
#define CMP_NODE_CHANNEL_MATTE_CS_HSV 2
#define CMP_NODE_CHANNEL_MATTE_CS_YUV 3
@@ -1661,7 +1669,7 @@ typedef struct NodeFunctionCompare {
#define SHD_VECT_TRANSFORM_SPACE_OBJECT 1
#define SHD_VECT_TRANSFORM_SPACE_CAMERA 2
-/* attribute */
+/** #NodeShaderAttribute.type */
enum {
SHD_ATTRIBUTE_GEOMETRY = 0,
SHD_ATTRIBUTE_OBJECT = 1,
@@ -1795,7 +1803,7 @@ enum {
#define SHD_AO_INSIDE 1
#define SHD_AO_LOCAL 2
-/* Mapping node vector types. */
+/** Mapping node vector types. */
enum {
NODE_MAPPING_TYPE_POINT = 0,
NODE_MAPPING_TYPE_TEXTURE = 1,
@@ -1803,7 +1811,7 @@ enum {
NODE_MAPPING_TYPE_NORMAL = 3,
};
-/* Rotation node vector types. */
+/** Rotation node vector types. */
enum {
NODE_VECTOR_ROTATE_TYPE_AXIS = 0,
NODE_VECTOR_ROTATE_TYPE_AXIS_X = 1,
@@ -1815,7 +1823,7 @@ enum {
/* math node clamp */
#define SHD_MATH_CLAMP 1
-/* Math node operations. */
+/** Math node operations. */
typedef enum NodeMathOperation {
NODE_MATH_ADD = 0,
NODE_MATH_SUBTRACT = 1,
@@ -1859,7 +1867,7 @@ typedef enum NodeMathOperation {
NODE_MATH_SMOOTH_MAX = 39,
} NodeMathOperation;
-/* Vector Math node operations. */
+/** Vector Math node operations. */
typedef enum NodeVectorMathOperation {
NODE_VECTOR_MATH_ADD = 0,
NODE_VECTOR_MATH_SUBTRACT = 1,
@@ -1893,14 +1901,14 @@ typedef enum NodeVectorMathOperation {
NODE_VECTOR_MATH_MULTIPLY_ADD = 26,
} NodeVectorMathOperation;
-/* Boolean math node operations. */
+/** Boolean math node operations. */
enum {
NODE_BOOLEAN_MATH_AND = 0,
NODE_BOOLEAN_MATH_OR = 1,
NODE_BOOLEAN_MATH_NOT = 2,
};
-/* Float compare node operations. */
+/** Float compare node operations. */
typedef enum NodeCompareMode {
NODE_COMPARE_MODE_ELEMENT = 0,
NODE_COMPARE_MODE_LENGTH = 1,
@@ -1921,7 +1929,7 @@ typedef enum NodeCompareOperation {
} NodeCompareOperation;
-/* Float to Int node operations. */
+/** Float to Int node operations. */
typedef enum FloatToIntRoundingMode {
FN_NODE_FLOAT_TO_INT_ROUND = 0,
FN_NODE_FLOAT_TO_INT_FLOOR = 1,
@@ -1929,13 +1937,13 @@ typedef enum FloatToIntRoundingMode {
FN_NODE_FLOAT_TO_INT_TRUNCATE = 3,
} FloatToIntRoundingMode;
-/* Clamp node types. */
+/** Clamp node types. */
enum {
NODE_CLAMP_MINMAX = 0,
NODE_CLAMP_RANGE = 1,
};
-/* Map range node types. */
+/** Map range node types. */
enum {
NODE_MAP_RANGE_LINEAR = 0,
NODE_MAP_RANGE_STEPPED = 1,
@@ -1947,7 +1955,8 @@ enum {
#define SHD_MIXRGB_USE_ALPHA 1
#define SHD_MIXRGB_CLAMP 2
-/* subsurface */
+/* Subsurface. */
+
enum {
#ifdef DNA_DEPRECATED_ALLOW
SHD_SUBSURFACE_COMPATIBLE = 0, /* Deprecated */
@@ -1978,25 +1987,29 @@ enum {
/* viewer and composite output. */
#define CMP_NODE_OUTPUT_IGNORE_ALPHA 1
-/* Plane track deform node */
+/* Plane track deform node. */
+
enum {
CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR = 1,
};
-/* Stabilization node */
+/* Stabilization node. */
+
enum {
CMP_NODEFLAG_STABILIZE_INVERSE = 1,
};
/* Set Alpha Node. */
-/* `NodeSetAlpha.mode` */
+
+/** #NodeSetAlpha.mode */
typedef enum CMPNodeSetAlphaMode {
CMP_NODE_SETALPHA_MODE_APPLY = 0,
CMP_NODE_SETALPHA_MODE_REPLACE_ALPHA = 1,
} CMPNodeSetAlphaMode;
/* Denoise Node. */
-/* `NodeDenoise.prefilter` */
+
+/** #NodeDenoise.prefilter */
typedef enum CMPNodeDenoisePrefilter {
CMP_NODE_DENOISE_PREFILTER_FAST = 0,
CMP_NODE_DENOISE_PREFILTER_NONE = 1,
diff --git a/source/blender/makesdna/DNA_object_force_types.h b/source/blender/makesdna/DNA_object_force_types.h
index 0aa4a171511..7d0d4c0d460 100644
--- a/source/blender/makesdna/DNA_object_force_types.h
+++ b/source/blender/makesdna/DNA_object_force_types.h
@@ -32,7 +32,7 @@ extern "C" {
struct BodySpring;
-/* pd->forcefield: Effector Fields types */
+/** #PartDeflect.forcefield: Effector Fields types. */
typedef enum ePFieldType {
/** (this is used for general effector weight). */
PFIELD_NULL = 0,
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 57c8ef200ae..13a368e4263 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -57,7 +57,7 @@ struct SculptSession;
struct SoftBody;
struct bGPdata;
-/* Vertex Groups - Name Info */
+/** Vertex Groups - Name Info */
typedef struct bDeformGroup {
struct bDeformGroup *next, *prev;
/** MAX_VGROUP_NAME. */
@@ -66,7 +66,7 @@ typedef struct bDeformGroup {
char flag, _pad0[7];
} bDeformGroup;
-/* Face Maps. */
+/** Face Maps. */
typedef struct bFaceMap {
struct bFaceMap *next, *prev;
/** MAX_VGROUP_NAME. */
@@ -107,7 +107,7 @@ typedef struct BoundBox {
char _pad0[4];
} BoundBox;
-/* boundbox flag */
+/** #BoundBox.flag */
enum {
BOUNDBOX_DISABLED = (1 << 0),
BOUNDBOX_DIRTY = (1 << 1),
@@ -115,7 +115,7 @@ enum {
struct CustomData_MeshMasks;
-/* Not saved in file! */
+/** Not saved in file! */
typedef struct Object_Runtime {
/**
* The custom data layer mask that was last used
@@ -126,7 +126,12 @@ typedef struct Object_Runtime {
/** Did last modifier stack generation need mapping support? */
char last_need_mapping;
- char _pad0[3];
+ /** Opaque data reserved for management of objects in collection context.
+ * E.g. used currently to check for potential duplicates of objects in a collection, after
+ * remapping process. */
+ char collection_management;
+
+ char _pad0[2];
/** Only used for drawing the parent/child help-line. */
float parent_display_origin[3];
@@ -246,7 +251,7 @@ typedef struct Object {
/** String describing subobject info, MAX_ID_NAME-2. */
char parsubstr[64];
struct Object *parent, *track;
- /* if ob->proxy (or proxy_group), this object is proxy for object ob->proxy */
+ /* If `ob->proxy` (or proxy_group), this object is proxy for object `ob->proxy`. */
/* proxy_from is set in target back to the proxy. */
struct Object *proxy, *proxy_group, *proxy_from;
/** Old animation system, deprecated for 2.5. */
@@ -322,8 +327,7 @@ typedef struct Object {
* Inverse matrix of 'obmat' for any other use than rendering!
*
* \note this isn't assured to be valid as with 'obmat',
- * before using this value you should do...
- * invert_m4_m4(ob->imat, ob->obmat);
+ * before using this value you should do: `invert_m4_m4(ob->imat, ob->obmat)`
*/
float imat[4][4];
@@ -436,7 +440,7 @@ typedef struct Object {
Object_Runtime runtime;
} Object;
-/* Warning, this is not used anymore because hooks are now modifiers */
+/** DEPRECATED: this is not used anymore because hooks are now modifiers. */
typedef struct ObHook {
struct ObHook *next, *prev;
@@ -466,7 +470,7 @@ typedef struct ObHook {
/* used many places, should be specialized. */
#define SELECT 1
-/* type */
+/** #Object.type */
enum {
OB_EMPTY = 0,
OB_MESH = 1,
@@ -544,7 +548,7 @@ enum {
case ID_PT: \
case ID_VO
-/* partype: first 4 bits: type */
+/** #Object.partype: first 4 bits: type. */
enum {
PARTYPE = (1 << 4) - 1,
PAROBJECT = 0,
@@ -555,7 +559,7 @@ enum {
};
-/* (short) transflag */
+/** #Object.transflag (short) */
enum {
OB_TRANSFORM_ADJUST_ROOT_PARENT_FOR_VIEW_LOCK = 1 << 0,
OB_TRANSFLAG_UNUSED_1 = 1 << 1, /* cleared */
@@ -577,7 +581,7 @@ enum {
OB_DUPLI = OB_DUPLIVERTS | OB_DUPLICOLLECTION | OB_DUPLIFACES | OB_DUPLIPARTS,
};
-/* (short) trackflag / upflag */
+/** #Object.trackflag / #Object.upflag (short) */
enum {
OB_POSX = 0,
OB_POSY = 1,
@@ -587,7 +591,7 @@ enum {
OB_NEGZ = 5,
};
-/* dtx: flags (short) */
+/** #Object.dtx draw type extra flags (short) */
enum {
OB_DRAWBOUNDOX = 1 << 0,
OB_AXIS = 1 << 1,
@@ -606,7 +610,7 @@ enum {
OB_USE_GPENCIL_LIGHTS = 1 << 10,
};
-/* empty_drawtype: no flags */
+/** #Object.empty_drawtype: no flags */
enum {
OB_ARROWS = 1,
OB_PLAINAXES = 2,
@@ -618,7 +622,10 @@ enum {
OB_EMPTY_IMAGE = 8,
};
-/* gpencil add types */
+/**
+ * Grease-pencil add types.
+ * TODO: doesn't need to be DNA, local to `OBJECT_OT_gpencil_add`.
+ */
enum {
GP_EMPTY = 0,
GP_STROKE = 1,
@@ -628,7 +635,7 @@ enum {
GP_LRT_COLLECTION = 5,
};
-/* boundtype */
+/** #Object.boundtype */
enum {
OB_BOUND_BOX = 0,
OB_BOUND_SPHERE = 1,
@@ -642,7 +649,7 @@ enum {
/* **************** BASE ********************* */
-/* base->flag_legacy */
+/** #Base.flag_legacy */
enum {
BA_WAS_SEL = (1 << 1),
/* NOTE: BA_HAS_RECALC_DATA can be re-used later if freed in readfile.c. */
@@ -671,7 +678,7 @@ enum {
# define OB_FLAG_UNUSED_12 (1 << 12) /* cleared */
#endif
-/* ob->visibility_flag */
+/** #Object.visibility_flag */
enum {
OB_HIDE_VIEWPORT = 1 << 0,
OB_HIDE_SELECT = 1 << 1,
@@ -686,7 +693,7 @@ enum {
OB_SHADOW_CATCHER = 1 << 10
};
-/* ob->shapeflag */
+/** #Object.shapeflag */
enum {
OB_SHAPE_LOCK = 1 << 0,
#ifdef DNA_DEPRECATED_ALLOW
@@ -695,7 +702,7 @@ enum {
OB_SHAPE_EDIT_MODE = 1 << 2,
};
-/* ob->nlaflag */
+/** #Object.nlaflag */
enum {
OB_ADS_UNUSED_1 = 1 << 0, /* cleared */
OB_ADS_UNUSED_2 = 1 << 1, /* cleared */
@@ -711,7 +718,7 @@ enum {
/* OB_ADS_SHOWPARTS = 1 << 14, */ /* UNUSED */
};
-/* ob->protectflag */
+/** #Object.protectflag */
enum {
OB_LOCK_LOCX = 1 << 0,
OB_LOCK_LOCY = 1 << 1,
@@ -729,13 +736,13 @@ enum {
OB_LOCK_ROT4D = 1 << 10,
};
-/* ob->duplicator_visibility_flag */
+/** #Object.duplicator_visibility_flag */
enum {
OB_DUPLI_FLAG_VIEWPORT = 1 << 0,
OB_DUPLI_FLAG_RENDER = 1 << 1,
};
-/* ob->empty_image_depth */
+/** #Object.empty_image_depth */
#define OB_EMPTY_IMAGE_DEPTH_DEFAULT 0
#define OB_EMPTY_IMAGE_DEPTH_FRONT 1
#define OB_EMPTY_IMAGE_DEPTH_BACK 2
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index a51c532dfb3..5add664f624 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -72,7 +72,7 @@ typedef struct ParticleSpring {
unsigned int particle_index[2], delete_flag;
} ParticleSpring;
-/* Child particles are created around or between parent particles */
+/** Child particles are created around or between parent particles. */
typedef struct ChildParticle {
/** Face index on the final derived mesh. */
int num;
@@ -364,8 +364,7 @@ typedef struct ParticleSystem {
int flag, totpart, totunexist, totchild, totcached, totchildcache;
/* NOTE: Recalc is one of ID_RECALC_PSYS_ALL flags.
*
- * TODO(sergey): Use part->id.recalc instead of this duplicated flag
- * somehow. */
+ * TODO(sergey): Use #ParticleSettings.id.recalc instead of this duplicated flag somehow. */
int recalc;
short target_psys, totkeyed, bakespace;
char _pad1[6];
@@ -438,9 +437,11 @@ typedef enum eParticleDrawFlag {
PART_DRAW_HAIR_GRID = (1 << 18),
} eParticleDrawFlag;
-/* part->type
+/**
+ * #ParticleSettings.type
* Hair is always baked static in object/geometry space.
- * Other types (normal particles) are in global space and not static baked. */
+ * Other types (normal particles) are in global space and not static baked.
+ */
enum {
PART_EMITTER = 0,
/* REACTOR type currently unused */
@@ -458,7 +459,7 @@ enum {
PART_FLUID_SPRAYFOAMBUBBLE = 12,
};
-/* Mirroring Mantaflow particle types from particle.h (Mantaflow header). */
+/** Mirroring Mantaflow particle types from particle.h (Mantaflow header). */
enum {
/* PARTICLE_TYPE_NONE = (0 << 0), */ /* UNUSED */
/* PARTICLE_TYPE_NEW = (1 << 0), */ /* UNUSED */
@@ -470,7 +471,7 @@ enum {
/* PARTICLE_TYPE_INVALID = (1 << 30), */ /* UNUSED */
};
-/* part->flag */
+/** #ParticleSettings.flag */
#define PART_REACT_STA_END 1
#define PART_REACT_MULTIPLE 2
@@ -514,26 +515,26 @@ enum {
#define PART_SELF_EFFECT (1 << 22)
-/* part->from */
+/** #ParticleSettings.from */
#define PART_FROM_VERT 0
#define PART_FROM_FACE 1
#define PART_FROM_VOLUME 2
/* #define PART_FROM_PARTICLE 3 deprecated! */
#define PART_FROM_CHILD 4
-/* part->distr */
+/** #ParticleSettings.distr */
#define PART_DISTR_JIT 0
#define PART_DISTR_RAND 1
#define PART_DISTR_GRID 2
-/* part->phystype */
+/** #ParticleSettings.phystype */
#define PART_PHYS_NO 0
#define PART_PHYS_NEWTON 1
#define PART_PHYS_KEYED 2
#define PART_PHYS_BOIDS 3
#define PART_PHYS_FLUID 4
-/* part->kink */
+/** #ParticleSettings.kink */
typedef enum eParticleKink {
PART_KINK_NO = 0,
PART_KINK_CURL = 1,
@@ -543,7 +544,7 @@ typedef enum eParticleKink {
PART_KINK_SPIRAL = 5,
} eParticleKink;
-/* part->child_flag */
+/** #ParticleSettings.child_flag */
typedef enum eParticleChildFlag {
PART_CHILD_USE_CLUMP_NOISE = (1 << 0),
PART_CHILD_USE_CLUMP_CURVE = (1 << 1),
@@ -551,22 +552,22 @@ typedef enum eParticleChildFlag {
PART_CHILD_USE_TWIST_CURVE = (1 << 3),
} eParticleChildFlag;
-/* part->shape_flag */
+/** #ParticleSettings.shape_flag */
typedef enum eParticleShapeFlag {
PART_SHAPE_CLOSE_TIP = (1 << 0),
} eParticleShapeFlag;
-/* part->draw_col */
+/* #ParticleSettings.draw_col */
#define PART_DRAW_COL_NONE 0
#define PART_DRAW_COL_MAT 1
#define PART_DRAW_COL_VEL 2
#define PART_DRAW_COL_ACC 3
-/* part->time_flag */
+/* #ParticleSettings.time_flag */
#define PART_TIME_AUTOSF 1 /* Automatic subframes */
-/* part->draw_as */
-/* part->ren_as */
+/* #ParticleSettings.draw_as */
+/* #ParticleSettings.ren_as */
#define PART_DRAW_NOT 0
#define PART_DRAW_DOT 1
#define PART_DRAW_HALO 1
@@ -580,13 +581,13 @@ typedef enum eParticleShapeFlag {
#define PART_DRAW_BB 9 /* deprecated */
#define PART_DRAW_REND 10
-/* part->integrator */
+/* #ParticleSettings.integrator */
#define PART_INT_EULER 0
#define PART_INT_MIDPOINT 1
#define PART_INT_RK4 2
#define PART_INT_VERLET 3
-/* part->rotmode */
+/* #ParticleSettings.rotmode */
#define PART_ROT_NOR 1
#define PART_ROT_VEL 2
#define PART_ROT_GLOB_X 3
@@ -597,7 +598,7 @@ typedef enum eParticleShapeFlag {
#define PART_ROT_OB_Z 8
#define PART_ROT_NOR_TAN 9
-/* part->avemode */
+/* #ParticleSettings.avemode */
#define PART_AVE_VELOCITY 1
#define PART_AVE_RAND 2
#define PART_AVE_HORIZONTAL 3
@@ -606,12 +607,12 @@ typedef enum eParticleShapeFlag {
#define PART_AVE_GLOBAL_Y 6
#define PART_AVE_GLOBAL_Z 7
-/* part->reactevent */
+/* #ParticleSettings.reactevent */
#define PART_EVENT_DEATH 0
#define PART_EVENT_COLLIDE 1
#define PART_EVENT_NEAR 2
-/* part->childtype */
+/* #ParticleSettings.childtype */
#define PART_CHILD_PARTICLES 1
#define PART_CHILD_FACES 2
@@ -675,7 +676,7 @@ typedef enum eParticleShapeFlag {
#define PTARGET_MODE_FRIEND 1
#define PTARGET_MODE_ENEMY 2
-/* mapto */
+/** #MTex.mapto */
typedef enum eParticleTextureInfluence {
/* init */
PAMAP_TIME = (1 << 0), /* emission time */
diff --git a/source/blender/makesdna/DNA_pointcloud_types.h b/source/blender/makesdna/DNA_pointcloud_types.h
index 26f1db3324b..53fda29a33a 100644
--- a/source/blender/makesdna/DNA_pointcloud_types.h
+++ b/source/blender/makesdna/DNA_pointcloud_types.h
@@ -54,7 +54,7 @@ typedef struct PointCloud {
void *batch_cache;
} PointCloud;
-/* PointCloud.flag */
+/** #PointCloud.flag */
enum {
PT_DS_EXPAND = (1 << 0),
};
diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h
index aa11e74e89d..f653905e169 100644
--- a/source/blender/makesdna/DNA_rigidbody_types.h
+++ b/source/blender/makesdna/DNA_rigidbody_types.h
@@ -38,7 +38,7 @@ struct EffectorWeights;
/* ******************************** */
/* RigidBody World */
-/* Container for data shared by original and evaluated copies of RigidBodyWorld */
+/** Container for data shared by original and evaluated copies of #RigidBodyWorld. */
typedef struct RigidBodyWorld_Shared {
/* cache */
struct PointCache *pointcache;
@@ -90,7 +90,7 @@ typedef struct RigidBodyWorld {
float time_scale;
} RigidBodyWorld;
-/* Flags for RigidBodyWorld */
+/** RigidBodyWorld.flag */
typedef enum eRigidBodyWorld_Flag {
/* should sim world be skipped when evaluating (user setting) */
RBW_FLAG_MUTED = (1 << 0),
@@ -170,7 +170,7 @@ typedef struct RigidBodyOb {
struct RigidBodyOb_Shared *shared;
} RigidBodyOb;
-/* Participation types for RigidBodyOb */
+/** #RigidBodyOb.type */
typedef enum eRigidBodyOb_Type {
/* active geometry participant in simulation. is directly controlled by sim */
RBO_TYPE_ACTIVE = 0,
@@ -178,7 +178,7 @@ typedef enum eRigidBodyOb_Type {
RBO_TYPE_PASSIVE = 1,
} eRigidBodyOb_Type;
-/* Flags for RigidBodyOb */
+/** #RigidBodyOb.flag */
typedef enum eRigidBodyOb_Flag {
/* rigidbody is kinematic (controlled by the animation system) */
RBO_FLAG_KINEMATIC = (1 << 0),
@@ -198,7 +198,7 @@ typedef enum eRigidBodyOb_Flag {
RBO_FLAG_USE_DEFORM = (1 << 7),
} eRigidBodyOb_Flag;
-/* RigidBody Collision Shape */
+/** Rigid Body Collision Shape. */
typedef enum eRigidBody_Shape {
/** Simple box (i.e. bounding box). */
RB_SHAPE_BOX = 0,
@@ -304,7 +304,7 @@ typedef struct RigidBodyCon {
void *physics_constraint;
} RigidBodyCon;
-/* Participation types for RigidBodyOb */
+/** Participation types for #RigidBodyOb.type */
typedef enum eRigidBodyCon_Type {
/** lets bodies rotate around a specified point */
RBC_TYPE_POINT = 0,
@@ -333,13 +333,13 @@ typedef enum eRigidBodyCon_Type {
RBC_TYPE_MOTOR = 11,
} eRigidBodyCon_Type;
-/* Spring implementation type for RigidBodyOb */
+/** Spring implementation type for RigidBodyOb. */
typedef enum eRigidBodyCon_SpringType {
RBC_SPRING_TYPE1 = 0, /* btGeneric6DofSpringConstraint */
RBC_SPRING_TYPE2 = 1, /* btGeneric6DofSpring2Constraint */
} eRigidBodyCon_SpringType;
-/* Flags for RigidBodyCon */
+/** #RigidBodyCon.flag */
typedef enum eRigidBodyCon_Flag {
/* constraint influences rigid body motion */
RBC_FLAG_ENABLED = (1 << 0),
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index c66ac3a6211..4607a47a9a8 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -195,7 +195,7 @@ typedef struct AudioData {
/* *************************************************************** */
/* Render Layers */
-/* Render Layer */
+/** Render Layer. */
typedef struct SceneRenderLayer {
struct SceneRenderLayer *next, *prev;
@@ -323,7 +323,7 @@ typedef enum eScenePassType {
#define RE_PASSNAME_BLOOM "BloomCol"
#define RE_PASSNAME_VOLUME_LIGHT "VolumeDir"
-/* View - MultiView */
+/** View - MultiView. */
typedef struct SceneRenderView {
struct SceneRenderView *next, *prev;
@@ -785,12 +785,12 @@ typedef struct RenderData {
struct CurveMapping mblur_shutter_curve;
} RenderData;
-/* RenderData.quality_flag */
+/** #RenderData.quality_flag */
typedef enum eQualityOption {
SCE_PERF_HQ_NORMALS = (1 << 0),
} eQualityOption;
-/* RenderData.hair_type */
+/** #RenderData.hair_type */
typedef enum eHairType {
SCE_HAIR_SHAPE_STRAND = 0,
SCE_HAIR_SHAPE_STRIP = 1,
@@ -799,7 +799,7 @@ typedef enum eHairType {
/* *************************************************************** */
/* Render Conversion/Simplification Settings */
-/* control render convert and shading engine */
+/** Control render convert and shading engine. */
typedef struct RenderProfile {
struct RenderProfile *next, *prev;
char name[32];
@@ -829,7 +829,7 @@ typedef struct RenderProfile {
#define STEREO_RIGHT_SUFFIX "_R"
#define STEREO_LEFT_SUFFIX "_L"
-/* View3D.stereo3d_camera / View3D.multiview_eye / ImageUser.multiview_eye */
+/** #View3D.stereo3d_camera / #View3D.multiview_eye / #ImageUser.multiview_eye */
typedef enum eStereoViews {
STEREO_LEFT_ID = 0,
STEREO_RIGHT_ID = 1,
@@ -861,12 +861,12 @@ typedef struct Paint_Runtime {
char _pad[2];
} Paint_Runtime;
-/* We might want to store other things here. */
+/** We might want to store other things here. */
typedef struct PaintToolSlot {
struct Brush *brush;
} PaintToolSlot;
-/* Paint Tool Base */
+/** Paint Tool Base. */
typedef struct Paint {
struct Brush *brush;
@@ -903,7 +903,7 @@ typedef struct Paint {
/* ------------------------------------------- */
/* Image Paint */
-/* Texture/Image Editor */
+/** Texture/Image Editor. */
typedef struct ImagePaintSettings {
Paint paint;
@@ -934,7 +934,7 @@ typedef struct ImagePaintSettings {
/* ------------------------------------------- */
/* Particle Edit */
-/* Settings for a Particle Editing Brush */
+/** Settings for a Particle Editing Brush. */
typedef struct ParticleBrushData {
/** Common setting. */
short size;
@@ -944,7 +944,7 @@ typedef struct ParticleBrushData {
float strength;
} ParticleBrushData;
-/* Particle Edit Mode Settings */
+/** Particle Edit Mode Settings. */
typedef struct ParticleEditSettings {
short flag;
short totrekey;
@@ -971,7 +971,7 @@ typedef struct ParticleEditSettings {
/* ------------------------------------------- */
/* Sculpt */
-/* Sculpt */
+/** Sculpt. */
typedef struct Sculpt {
Paint paint;
@@ -1006,7 +1006,7 @@ typedef struct UvSculpt {
Paint paint;
} UvSculpt;
-/* grease pencil drawing brushes */
+/** Grease pencil drawing brushes. */
typedef struct GpPaint {
Paint paint;
int flag;
@@ -1020,21 +1020,21 @@ enum {
GPPAINT_FLAG_USE_VERTEXCOLOR = 1,
};
-/* Grease pencil vertex paint. */
+/** Grease pencil vertex paint. */
typedef struct GpVertexPaint {
Paint paint;
int flag;
char _pad[4];
} GpVertexPaint;
-/* Grease pencil sculpt paint. */
+/** Grease pencil sculpt paint. */
typedef struct GpSculptPaint {
Paint paint;
int flag;
char _pad[4];
} GpSculptPaint;
-/* Grease pencil weight paint. */
+/** Grease pencil weight paint. */
typedef struct GpWeightPaint {
Paint paint;
int flag;
@@ -1044,7 +1044,7 @@ typedef struct GpWeightPaint {
/* ------------------------------------------- */
/* Vertex Paint */
-/* Vertex Paint */
+/** Vertex Paint. */
typedef struct VPaint {
Paint paint;
char flag;
@@ -1062,7 +1062,7 @@ enum {
/* ------------------------------------------- */
/* GPencil Stroke Sculpting */
-/* GP_Sculpt_Settings.lock_axis */
+/** #GP_Sculpt_Settings.lock_axis */
typedef enum eGP_Lockaxis_Types {
GP_LOCKAXIS_VIEW = 0,
GP_LOCKAXIS_X = 1,
@@ -1071,7 +1071,7 @@ typedef enum eGP_Lockaxis_Types {
GP_LOCKAXIS_CURSOR = 4,
} eGP_Lockaxis_Types;
-/* Settings for a GPencil Speed Guide */
+/** Settings for a GPencil Speed Guide. */
typedef struct GP_Sculpt_Guide {
char use_guide;
char use_snapping;
@@ -1085,7 +1085,7 @@ typedef struct GP_Sculpt_Guide {
struct Object *reference_object;
} GP_Sculpt_Guide;
-/* GPencil Stroke Sculpting Settings */
+/** GPencil Stroke Sculpting Settings. */
typedef struct GP_Sculpt_Settings {
/** Runtime. */
void *paintcursor;
@@ -1134,7 +1134,7 @@ typedef enum eGP_vertex_SelectMaskFlag {
GP_VERTEX_MASK_SELECTMODE_SEGMENT = (1 << 2),
} eGP_Vertex_SelectMaskFlag;
-/* Settings for GP Interpolation Operators */
+/** Settings for GP Interpolation Operators. */
typedef struct GP_Interpolate_Settings {
/** Custom interpolation curve (for use with GP_IPO_CURVEMAP). */
struct CurveMapping *custom_ipo;
@@ -1255,7 +1255,7 @@ typedef struct UnifiedPaintSettings {
struct ColorSpace *colorspace;
} UnifiedPaintSettings;
-/* UnifiedPaintSettings.flag */
+/** #UnifiedPaintSettings.flag */
typedef enum {
UNIFIED_PAINT_SIZE = (1 << 0),
UNIFIED_PAINT_ALPHA = (1 << 1),
@@ -1313,7 +1313,7 @@ enum {
/* *************************************************************** */
/* Stats */
-/* Stats for Meshes */
+/** Stats for Meshes. */
typedef struct MeshStatVis {
char type;
char _pad1[2];
@@ -1570,8 +1570,8 @@ typedef struct PhysicsSettings {
char _pad0[4];
} PhysicsSettings;
-/* ------------------------------------------- */
-/* Safe Area options used in Camera View & Sequencer
+/**
+ * Safe Area options used in Camera View & Sequencer.
*/
typedef struct DisplaySafeAreas {
/* each value represents the (x,y) margins as a multiplier.
@@ -1587,8 +1587,9 @@ typedef struct DisplaySafeAreas {
float action_center[2];
} DisplaySafeAreas;
-/* ------------------------------------------- */
-/* Scene Display - used for store scene specific display settings for the 3d view */
+/**
+ * Scene Display - used for store scene specific display settings for the 3d view.
+ */
typedef struct SceneDisplay {
/** Light direction for shadows/highlight. */
float light_direction[3];
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index a4c254d6e5a..1a1d7cba7af 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -244,7 +244,7 @@ typedef struct PanelCategoryDyn {
rcti rect;
} PanelCategoryDyn;
-/* region stack of active tabs */
+/** Region stack of active tabs. */
typedef struct PanelCategoryStack {
struct PanelCategoryStack *next, *prev;
char idname[64];
@@ -654,8 +654,10 @@ enum {
#define UILST_FLT_SORT_MASK (((unsigned int)(UILST_FLT_SORT_REVERSE | UILST_FLT_SORT_LOCK)) - 1)
-/* regiontype, first two are the default set */
-/* Do NOT change order, append on end. Types are hardcoded needed */
+/**
+ * regiontype, first two are the default set.
+ * \warning Do NOT change order, append on end. Types are hard-coded needed.
+ */
typedef enum eRegion_Type {
RGN_TYPE_WINDOW = 0,
RGN_TYPE_HEADER = 1,
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index e1bba60396a..5fe67a34dae 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -47,6 +47,10 @@ struct SequenceLookup;
struct VFont;
struct bSound;
+/* -------------------------------------------------------------------- */
+/** \name Sequence & Editing Structs
+ * \{ */
+
/* strlens; 256= FILE_MAXFILE, 768= FILE_MAXDIR */
typedef struct StripAnim {
@@ -311,7 +315,12 @@ typedef struct Editing {
void *_pad1;
} Editing;
-/* ************* Effect Variable Structs ********* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Effect Variable Structs
+ * \{ */
+
typedef struct WipeVars {
float edgeWidth, angle;
short forward, wipetype;
@@ -360,7 +369,7 @@ typedef struct SpeedControlVars {
float speed_fader_frame_number;
} SpeedControlVars;
-/* SpeedControlVars.speed_control_type */
+/** #SpeedControlVars.speed_control_type */
enum {
SEQ_SPEED_STRETCH = 0,
SEQ_SPEED_MULTIPLY = 1,
@@ -387,7 +396,7 @@ typedef struct TextVars {
char _pad[5];
} TextVars;
-/* TextVars.flag */
+/** #TextVars.flag */
enum {
SEQ_TEXT_SHADOW = (1 << 0),
SEQ_TEXT_BOX = (1 << 1),
@@ -395,14 +404,14 @@ enum {
SEQ_TEXT_ITALIC = (1 << 3),
};
-/* TextVars.align */
+/** #TextVars.align */
enum {
SEQ_TEXT_ALIGN_X_LEFT = 0,
SEQ_TEXT_ALIGN_X_CENTER = 1,
SEQ_TEXT_ALIGN_X_RIGHT = 2,
};
-/* TextVars.align_y */
+/** #TextVars.align_y */
enum {
SEQ_TEXT_ALIGN_Y_TOP = 0,
SEQ_TEXT_ALIGN_Y_CENTER = 1,
@@ -418,7 +427,11 @@ typedef struct ColorMixVars {
float factor;
} ColorMixVars;
-/* ***************** Sequence modifiers ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sequence Modifiers
+ * \{ */
typedef struct SequenceModifierData {
struct SequenceModifierData *next, *prev;
@@ -489,7 +502,11 @@ enum {
SEQ_TONEMAP_RD_PHOTORECEPTOR = 1,
};
-/* ***************** Scopes ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scopes
+ * \{ */
typedef struct SequencerScopes {
struct ImBuf *reference_ibuf;
@@ -522,10 +539,15 @@ typedef struct SequencerScopes {
#define SEQ_SPEED_UNUSED_3 (1 << 2) /* cleared */
#define SEQ_SPEED_USE_INTERPOLATION (1 << 3)
-/* ***************** SEQUENCE ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flags & Types
+ * \{ */
+
#define SEQ_NAME_MAXSTR 64
-/* seq->flag */
+/** #Sequence.flag */
enum {
/* SELECT */
SEQ_LEFTSEL = (1 << 1),
@@ -568,7 +590,7 @@ enum {
SEQ_INVALID_EFFECT = (1u << 31),
};
-/* StripProxy->storage */
+/** #StripProxy.storage */
enum {
SEQ_STORAGE_PROXY_CUSTOM_FILE = (1 << 1), /* store proxy in custom directory */
SEQ_STORAGE_PROXY_CUSTOM_DIR = (1 << 2), /* store proxy in custom file */
@@ -601,18 +623,22 @@ enum {
#define SEQ_PROXY_TC_RECORD_RUN_NO_GAPS 8
#define SEQ_PROXY_TC_ALL 15
-/* SeqProxy->build_flags */
+/** SeqProxy.build_flags */
enum {
SEQ_PROXY_SKIP_EXISTING = 1,
};
-/* seq->alpha_mode */
+/** #Sequence.alpha_mode */
enum {
SEQ_ALPHA_STRAIGHT = 0,
SEQ_ALPHA_PREMUL = 1,
};
-/* seq->type WATCH IT: SEQ_TYPE_EFFECT BIT is used to determine if this is an effect strip!!! */
+/**
+ * #Sequence.type
+ *
+ * \warning #SEQ_TYPE_EFFECT BIT is used to determine if this is an effect strip!
+ */
enum {
SEQ_TYPE_IMAGE = 0,
SEQ_TYPE_META = 1,
@@ -681,7 +707,7 @@ enum {
/* modifiers */
-/* SequenceModifierData->type */
+/** #SequenceModifierData.type */
enum {
seqModifierType_ColorBalance = 1,
seqModifierType_Curves = 2,
@@ -694,7 +720,7 @@ enum {
NUM_SEQUENCE_MODIFIER_TYPES,
};
-/* SequenceModifierData->flag */
+/** #SequenceModifierData.flag */
enum {
SEQUENCE_MODIFIER_MUTE = (1 << 0),
SEQUENCE_MODIFIER_EXPANDED = (1 << 1),
@@ -712,13 +738,14 @@ enum {
SEQUENCE_MASK_TIME_ABSOLUTE = 1,
};
-/* Sequence->cache_flag
- * SEQ_CACHE_STORE_RAW
- * SEQ_CACHE_STORE_PREPROCESSED
- * SEQ_CACHE_STORE_COMPOSITE
- * FINAL_OUT is ignored
+/**
+ * #Sequence.cache_flag
+ * - #SEQ_CACHE_STORE_RAW
+ * - #SEQ_CACHE_STORE_PREPROCESSED
+ * - #SEQ_CACHE_STORE_COMPOSITE
+ * - #FINAL_OUT is ignored
*
- * Editing->cache_flag
+ * #Editing.cache_flag
* all entries
*/
enum {
@@ -745,7 +772,7 @@ enum {
SEQ_CACHE_STORE_THUMBNAIL = (1 << 12),
};
-/* Sequence->color_tag. */
+/** #Sequence.color_tag. */
typedef enum SequenceColorTag {
SEQUENCE_COLOR_NONE = -1,
SEQUENCE_COLOR_01,
diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h
index 01e3b3a5230..be787c1760f 100644
--- a/source/blender/makesdna/DNA_shader_fx_types.h
+++ b/source/blender/makesdna/DNA_shader_fx_types.h
@@ -77,7 +77,7 @@ typedef struct ShaderFxData {
char *error;
} ShaderFxData;
-/* Runtime temp data */
+/** Runtime temp data. */
typedef struct ShaderFxData_Runtime {
float loc[3];
char _pad[4];
diff --git a/source/blender/makesdna/DNA_simulation_types.h b/source/blender/makesdna/DNA_simulation_types.h
index a700c9fe2f8..b14301ed32d 100644
--- a/source/blender/makesdna/DNA_simulation_types.h
+++ b/source/blender/makesdna/DNA_simulation_types.h
@@ -38,7 +38,7 @@ typedef struct Simulation {
char _pad[4];
} Simulation;
-/* Simulation.flag */
+/** #Simulation.flag */
enum {
SIM_DS_EXPAND = (1 << 0),
};
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index a7a19be5b3e..5a98277531c 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -61,16 +61,16 @@ struct bNodeTree;
struct wmOperator;
struct wmTimer;
-/* Defined in `buttons_intern.h`. */
+/** Defined in `buttons_intern.h`. */
typedef struct SpaceProperties_Runtime SpaceProperties_Runtime;
-/* Defined in `node_intern.hh`. */
+/** Defined in `node_intern.hh`. */
typedef struct SpaceNode_Runtime SpaceNode_Runtime;
-/* Defined in `file_intern.h`. */
+/** Defined in `file_intern.h`. */
typedef struct SpaceFile_Runtime SpaceFile_Runtime;
-/* Defined in `spreadsheet_intern.hh`. */
+/** Defined in `spreadsheet_intern.hh`. */
typedef struct SpaceSpreadsheet_Runtime SpaceSpreadsheet_Runtime;
/* -------------------------------------------------------------------- */
@@ -91,7 +91,7 @@ typedef struct SpaceLink {
char _pad0[6];
} SpaceLink;
-/* SpaceLink.link_flag */
+/** #SpaceLink.link_flag */
enum {
/**
* The space is not a regular one opened through the editor menu (for example) but spawned by an
@@ -113,7 +113,7 @@ enum {
/** \name Space Info
* \{ */
-/* Info Header */
+/** Info Header. */
typedef struct SpaceInfo {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -127,7 +127,7 @@ typedef struct SpaceInfo {
char _pad[7];
} SpaceInfo;
-/* SpaceInfo.rpt_mask */
+/** #SpaceInfo.rpt_mask */
typedef enum eSpaceInfo_RptMask {
INFO_RPT_DEBUG = (1 << 0),
INFO_RPT_INFO = (1 << 1),
@@ -142,7 +142,7 @@ typedef enum eSpaceInfo_RptMask {
/** \name Properties Editor
* \{ */
-/* Properties Editor */
+/** Properties Editor. */
typedef struct SpaceProperties {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -210,7 +210,7 @@ typedef struct SpaceProperties {
// #define BUTS_EFFECTS 14
#endif /* DNA_DEPRECATED_ALLOW */
-/* SpaceProperties.mainb new */
+/** #SpaceProperties.mainb new */
typedef enum eSpaceButtons_Context {
BCONTEXT_RENDER = 0,
BCONTEXT_SCENE = 1,
@@ -235,7 +235,7 @@ typedef enum eSpaceButtons_Context {
BCONTEXT_TOT,
} eSpaceButtons_Context;
-/* SpaceProperties.flag */
+/** #SpaceProperties.flag */
typedef enum eSpaceButtons_Flag {
/* SB_PRV_OSA = (1 << 0), */ /* UNUSED */
SB_PIN_CONTEXT = (1 << 1),
@@ -246,7 +246,7 @@ typedef enum eSpaceButtons_Flag {
SB_SHADING_CONTEXT = (1 << 4),
} eSpaceButtons_Flag;
-/* SpaceProperties.outliner_sync */
+/** #SpaceProperties.outliner_sync */
typedef enum eSpaceButtons_OutlinerSync {
PROPERTIES_SYNC_AUTO = 0,
PROPERTIES_SYNC_NEVER = 1,
@@ -259,10 +259,10 @@ typedef enum eSpaceButtons_OutlinerSync {
/** \name Outliner
* \{ */
-/* Defined in `outliner_intern.h`. */
+/** Defined in `outliner_intern.h`. */
typedef struct SpaceOutliner_Runtime SpaceOutliner_Runtime;
-/* Outliner */
+/** Outliner */
typedef struct SpaceOutliner {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -303,7 +303,7 @@ typedef struct SpaceOutliner {
SpaceOutliner_Runtime *runtime;
} SpaceOutliner;
-/* SpaceOutliner.flag */
+/** #SpaceOutliner.flag */
typedef enum eSpaceOutliner_Flag {
/* SO_TESTBLOCKS = (1 << 0), */ /* UNUSED */
/* SO_NEWSELECTED = (1 << 1), */ /* UNUSED */
@@ -314,7 +314,7 @@ typedef enum eSpaceOutliner_Flag {
SO_MODE_COLUMN = (1 << 6),
} eSpaceOutliner_Flag;
-/* SpaceOutliner.filter */
+/** #SpaceOutliner.filter */
typedef enum eSpaceOutliner_Filter {
SO_FILTER_SEARCH = (1 << 0), /* Run-time flag. */
SO_FILTER_CLEARED_1 = (1 << 1),
@@ -356,7 +356,7 @@ typedef enum eSpaceOutliner_Filter {
(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)
-/* SpaceOutliner.filter_state */
+/** #SpaceOutliner.filter_state */
typedef enum eSpaceOutliner_StateFilter {
SO_FILTER_OB_ALL = 0,
SO_FILTER_OB_VISIBLE = 1,
@@ -366,7 +366,7 @@ typedef enum eSpaceOutliner_StateFilter {
SO_FILTER_OB_SELECTABLE = 5,
} eSpaceOutliner_StateFilter;
-/* SpaceOutliner.show_restrict_flags */
+/** #SpaceOutliner.show_restrict_flags */
typedef enum eSpaceOutliner_ShowRestrictFlag {
SO_RESTRICT_ENABLE = (1 << 0),
SO_RESTRICT_SELECT = (1 << 1),
@@ -377,7 +377,7 @@ typedef enum eSpaceOutliner_ShowRestrictFlag {
SO_RESTRICT_INDIRECT_ONLY = (1 << 6),
} eSpaceOutliner_Restrict;
-/* SpaceOutliner.outlinevis */
+/** #SpaceOutliner.outlinevis */
typedef enum eSpaceOutliner_Mode {
SO_SCENES = 0,
/* SO_CUR_SCENE = 1, */ /* deprecated! */
@@ -398,7 +398,7 @@ typedef enum eSpaceOutliner_Mode {
SO_OVERRIDES_LIBRARY = 16,
} eSpaceOutliner_Mode;
-/* SpaceOutliner.storeflag */
+/** #SpaceOutliner.storeflag */
typedef enum eSpaceOutliner_StoreFlag {
/* cleanup tree */
SO_TREESTORE_CLEANUP = (1 << 0),
@@ -408,7 +408,7 @@ typedef enum eSpaceOutliner_StoreFlag {
SO_TREESTORE_REBUILD = (1 << 2),
} eSpaceOutliner_StoreFlag;
-/* outliner search flags (SpaceOutliner.search_flags) */
+/** Outliner search flags (#SpaceOutliner.search_flags) */
typedef enum eSpaceOutliner_Search_Flags {
SO_FIND_CASE_SENSITIVE = (1 << 0),
SO_FIND_COMPLETE = (1 << 1),
@@ -429,7 +429,7 @@ typedef struct SpaceGraph_Runtime {
ListBase ghost_curves;
} SpaceGraph_Runtime;
-/* 'Graph' Editor (formerly known as the IPO Editor) */
+/** 'Graph' Editor (formerly known as the IPO Editor). */
typedef struct SpaceGraph {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -467,7 +467,7 @@ typedef struct SpaceGraph {
SpaceGraph_Runtime runtime;
} SpaceGraph;
-/* SpaceGraph.flag (Graph Editor Settings) */
+/** #SpaceGraph.flag (Graph Editor Settings) */
typedef enum eGraphEdit_Flag {
/* OLD DEPRECATED SETTING */
/* SIPO_LOCK_VIEW = (1 << 0), */
@@ -504,7 +504,7 @@ typedef enum eGraphEdit_Flag {
SIPO_NO_DRAW_EXTRAPOLATION = (1 << 17),
} eGraphEdit_Flag;
-/* SpaceGraph.mode (Graph Editor Mode) */
+/** #SpaceGraph.mode (Graph Editor Mode) */
typedef enum eGraphEdit_Mode {
/* all animation curves (from all over Blender) */
SIPO_MODE_ANIMATION = 0,
@@ -532,7 +532,7 @@ typedef enum eGraphEdit_Runtime_Flag {
/** \name NLA Editor
* \{ */
-/* NLA Editor */
+/** NLA Editor */
typedef struct SpaceNla {
struct SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -552,7 +552,7 @@ typedef struct SpaceNla {
View2D v2d DNA_DEPRECATED;
} SpaceNla;
-/* SpaceNla.flag */
+/** #SpaceNla.flag */
typedef enum eSpaceNla_Flag {
SNLA_FLAG_UNUSED_0 = (1 << 0),
SNLA_FLAG_UNUSED_1 = (1 << 1),
@@ -581,7 +581,7 @@ typedef struct SequencerPreviewOverlay {
char _pad0[4];
} SequencerPreviewOverlay;
-/* SequencerPreviewOverlay.flag */
+/** #SequencerPreviewOverlay.flag */
typedef enum eSpaceSeq_SequencerPreviewOverlay_Flag {
SEQ_PREVIEW_SHOW_2D_CURSOR = (1 << 1),
SEQ_PREVIEW_SHOW_OUTLINE_SELECTED = (1 << 2),
@@ -596,7 +596,7 @@ typedef struct SequencerTimelineOverlay {
char _pad0[4];
} SequencerTimelineOverlay;
-/* SequencerTimelineOverlay.flag */
+/** #SequencerTimelineOverlay.flag */
typedef enum eSpaceSeq_SequencerTimelineOverlay_Flag {
SEQ_TIMELINE_SHOW_STRIP_OFFSETS = (1 << 1),
SEQ_TIMELINE_SHOW_THUMBNAILS = (1 << 2),
@@ -617,7 +617,7 @@ typedef struct SpaceSeqRuntime {
struct GHash *last_displayed_thumbnails;
} SpaceSeqRuntime;
-/* Sequencer */
+/** Sequencer. */
typedef struct SpaceSeq {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -667,7 +667,7 @@ typedef struct SpaceSeq {
SpaceSeqRuntime runtime;
} SpaceSeq;
-/* SpaceSeq.mainb */
+/** #SpaceSeq.mainb */
typedef enum eSpaceSeq_RegionType {
SEQ_DRAW_IMG_IMBUF = 1,
SEQ_DRAW_IMG_WAVEFORM = 2,
@@ -675,14 +675,14 @@ typedef enum eSpaceSeq_RegionType {
SEQ_DRAW_IMG_HISTOGRAM = 4,
} eSpaceSeq_RegionType;
-/* SpaceSeq.draw_flag */
+/** #SpaceSeq.draw_flag */
typedef enum eSpaceSeq_DrawFlag {
SEQ_DRAW_BACKDROP = (1 << 0),
SEQ_DRAW_UNUSED_1 = (1 << 1),
SEQ_DRAW_TRANSFORM_PREVIEW = (1 << 2),
} eSpaceSeq_DrawFlag;
-/* SpaceSeq.flag */
+/** #SpaceSeq.flag */
typedef enum eSpaceSeq_Flag {
SEQ_DRAWFRAMES = (1 << 0),
SEQ_MARKER_TRANS = (1 << 1),
@@ -703,14 +703,14 @@ typedef enum eSpaceSeq_Flag {
SEQ_SHOW_GRID = (1 << 18),
} eSpaceSeq_Flag;
-/* SpaceSeq.view */
+/** #SpaceSeq.view */
typedef enum eSpaceSeq_Displays {
SEQ_VIEW_SEQUENCE = 1,
SEQ_VIEW_PREVIEW = 2,
SEQ_VIEW_SEQUENCE_PREVIEW = 3,
} eSpaceSeq_Dispays;
-/* SpaceSeq.render_size */
+/** #SpaceSeq.render_size */
typedef enum eSpaceSeq_Proxy_RenderSize {
SEQ_RENDER_SIZE_NONE = -1,
SEQ_RENDER_SIZE_SCENE = 0,
@@ -740,7 +740,7 @@ enum {
SEQ_GIZMO_HIDE_TOOL = (1 << 3),
};
-/* SpaceSeq.mainb */
+/** #SpaceSeq.mainb */
typedef enum eSpaceSeq_OverlayFrameType {
SEQ_OVERLAY_FRAME_TYPE_RECT = 0,
SEQ_OVERLAY_FRAME_TYPE_REFERENCE = 1,
@@ -753,7 +753,7 @@ typedef enum eSpaceSeq_OverlayFrameType {
/** \name File Selector
* \{ */
-/* Config and Input for File Selector */
+/** Config and Input for File Selector. */
typedef struct FileSelectParams {
/** Title, also used for the text of the execute button. */
char title[96];
@@ -857,7 +857,7 @@ typedef struct FileFolderHistory {
ListBase folders_next;
} FileFolderHistory;
-/* File Browser */
+/** File Browser. */
typedef struct SpaceFile {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -921,7 +921,7 @@ typedef struct SpaceFile {
SpaceFile_Runtime *runtime;
} SpaceFile;
-/* SpaceFile.browse_mode (File Space Browsing Mode) */
+/** #SpaceFile.browse_mode (File Space Browsing Mode). */
typedef enum eFileBrowse_Mode {
/* Regular Blender File Browser */
FILE_BROWSE_MODE_FILES = 0,
@@ -929,7 +929,7 @@ typedef enum eFileBrowse_Mode {
FILE_BROWSE_MODE_ASSETS = 1,
} eFileBrowse_Mode;
-/* FileSelectParams.display */
+/** #FileSelectParams.display */
enum eFileDisplayType {
/** Internal (not exposed to users): Keep whatever display type was used during the last File
* Browser use, or the default if no such record is found. Use this unless there's a good reason
@@ -943,7 +943,7 @@ enum eFileDisplayType {
FILE_IMGDISPLAY = 3,
};
-/* FileSelectParams.sort */
+/** #FileSelectParams.sort */
enum eFileSortType {
/** Internal (not exposed to users): Sort by whatever was sorted by during the last File Browser
* use, or the default if no such record is found. Use this unless there's a good reason to set a
@@ -958,14 +958,14 @@ enum eFileSortType {
FILE_SORT_SIZE = 4,
};
-/* SpaceFile.tags */
+/** #SpaceFile.tags */
enum eFileTags {
/** Tag the space as having to update files representing or containing main data. Must be set
* after file read and undo/redo. */
FILE_TAG_REBUILD_MAIN_FILES = (1 << 0),
};
-/* FileSelectParams.details_flags */
+/** #FileSelectParams.details_flags */
enum eFileDetails {
FILE_DETAILS_SIZE = (1 << 0),
FILE_DETAILS_DATETIME = (1 << 1),
@@ -986,7 +986,7 @@ enum eFileDetails {
*/
#define FILE_SELECT_MAX_RECURSIONS (FILE_MAX_LIBEXTRA / 2)
-/* filesel types */
+/** Filesel types. */
typedef enum eFileSelectType {
FILE_LOADLIB = 1,
FILE_MAIN = 2,
@@ -1000,14 +1000,14 @@ typedef enum eFileSelectType {
FILE_SPECIAL = 9,
} eFileSelectType;
-/* filesel op property -> action */
+/** filesel op property -> action. */
typedef enum eFileSel_Action {
FILE_OPENFILE = 0,
FILE_SAVE = 1,
} eFileSel_Action;
-/* sfile->params->flag */
/**
+ * #FileSelectParams.flag / `sfile->params->flag`.
* \note short flag, also used as 16 lower bits of flags in link/append code
* (WM and BLO code area, see #eBLOLibLinkFlags in BLO_readfile.h).
*/
@@ -1022,7 +1022,7 @@ typedef enum eFileSel_Params_Flag {
FILE_DIRSEL_ONLY = (1 << 7),
FILE_FILTER = (1 << 8),
FILE_PARAMS_FLAG_UNUSED_3 = (1 << 9),
- FILE_PARAMS_FLAG_UNUSED_4 = (1 << 10),
+ FILE_PATH_TOKENS_ALLOW = (1 << 10),
FILE_SORT_INVERT = (1 << 11),
FILE_HIDE_TOOL_PROPS = (1 << 12),
FILE_CHECK_EXISTING = (1 << 13),
@@ -1037,8 +1037,10 @@ typedef enum eFileSel_Params_AssetCatalogVisibility {
FILE_SHOW_ASSETS_WITHOUT_CATALOG,
} eFileSel_Params_AssetCatalogVisibility;
-/* sfile->params->rename_flag */
-/* NOTE: short flag. Defined as bitflags, but currently only used as exclusive status markers... */
+/**
+ * #FileSelectParams.rename_flag / `sfile->params->rename_flag`.
+ * \note short flag. Defined as bit-flags, but currently only used as exclusive status markers.
+ */
typedef enum eFileSel_Params_RenameFlag {
/** Used when we only have the name of the entry we want to rename,
* but not yet access to its matching file entry. */
@@ -1084,7 +1086,7 @@ typedef enum eFileSel_File_Types {
FILE_TYPE_BLENDERLIB = (1u << 31),
} eFileSel_File_Types;
-/* Selection Flags in filesel: struct direntry, unsigned char selflag */
+/** Selection Flags in filesel: struct direntry, unsigned char selflag. */
typedef enum eDirEntry_SelectFlag {
/* FILE_SEL_ACTIVE = (1 << 1), */ /* UNUSED */
FILE_SEL_HIGHLIGHTED = (1 << 2),
@@ -1156,7 +1158,7 @@ typedef struct FileDirEntryArr {
char root[1024];
} FileDirEntryArr;
-/* FileDirEntry.flags */
+/** #FileDirEntry.flags */
enum {
/* The preview for this entry could not be generated. */
FILE_ENTRY_INVALID_PREVIEW = 1 << 0,
@@ -1243,7 +1245,7 @@ typedef struct SpaceImage {
SpaceImageOverlay overlay;
} SpaceImage;
-/* SpaceImage.dt_uv */
+/** #SpaceImage.dt_uv */
typedef enum eSpaceImage_UVDT {
SI_UVDT_OUTLINE = 0,
SI_UVDT_DASH = 1,
@@ -1251,20 +1253,20 @@ typedef enum eSpaceImage_UVDT {
SI_UVDT_WHITE = 3,
} eSpaceImage_UVDT;
-/* SpaceImage.dt_uvstretch */
+/** #SpaceImage.dt_uvstretch */
typedef enum eSpaceImage_UVDT_Stretch {
SI_UVDT_STRETCH_ANGLE = 0,
SI_UVDT_STRETCH_AREA = 1,
} eSpaceImage_UVDT_Stretch;
-/* SpaceImage.pixel_snap_mode */
+/** #SpaceImage.pixel_snap_mode */
typedef enum eSpaceImage_PixelSnapMode {
SI_PIXEL_SNAP_DISABLED = 0,
SI_PIXEL_SNAP_CENTER = 1,
SI_PIXEL_SNAP_CORNER = 2,
} eSpaceImage_Snap_Mode;
-/* SpaceImage.mode */
+/** #SpaceImage.mode */
typedef enum eSpaceImage_Mode {
SI_MODE_VIEW = 0,
SI_MODE_PAINT = 1,
@@ -1281,7 +1283,7 @@ typedef enum eSpaceImage_Sticky {
SI_STICKY_VERTEX = 2,
} eSpaceImage_Sticky;
-/* SpaceImage.flag */
+/** #SpaceImage.flag */
typedef enum eSpaceImage_Flag {
SI_FLAG_UNUSED_0 = (1 << 0), /* cleared */
SI_FLAG_UNUSED_1 = (1 << 1), /* cleared */
@@ -1375,7 +1377,7 @@ typedef struct SpaceText_Runtime {
} SpaceText_Runtime;
-/* Text Editor */
+/** Text Editor. */
typedef struct SpaceText {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1425,7 +1427,7 @@ typedef struct SpaceText {
SpaceText_Runtime runtime;
} SpaceText;
-/* SpaceText flags (moved from DNA_text_types.h) */
+/** SpaceText flags (moved from DNA_text_types.h). */
typedef enum eSpaceText_Flags {
/* scrollable */
ST_SCROLL_SELECT = (1 << 0),
@@ -1449,7 +1451,7 @@ typedef enum eSpaceText_Flags {
/** \name Script View (Obsolete)
* \{ */
-/* Script Runtime Data - Obsolete (pre 2.5) */
+/** Script Runtime Data - Obsolete (pre 2.5). */
typedef struct Script {
ID id;
@@ -1474,7 +1476,7 @@ typedef struct Script {
_script->py_globaldict = NULL; \
_script->flags = 0
-/* Script View - Obsolete (pre 2.5) */
+/** Script View - Obsolete (pre 2.5). */
typedef struct SpaceScript {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1584,7 +1586,7 @@ typedef struct SpaceNode {
SpaceNode_Runtime *runtime;
} SpaceNode;
-/* SpaceNode.flag */
+/** #SpaceNode.flag */
typedef enum eSpaceNode_Flag {
SNODE_BACKDRAW = (1 << 1),
SNODE_SHOW_GPENCIL = (1 << 2),
@@ -1602,7 +1604,7 @@ typedef enum eSpaceNode_Flag {
SNODE_SKIP_INSOFFSET = (1 << 13),
} eSpaceNode_Flag;
-/* SpaceNode.texfrom */
+/** #SpaceNode.texfrom */
typedef enum eSpaceNode_TexFrom {
/* SNODE_TEX_OBJECT = 0, */
SNODE_TEX_WORLD = 1,
@@ -1610,14 +1612,14 @@ typedef enum eSpaceNode_TexFrom {
SNODE_TEX_LINESTYLE = 3,
} eSpaceNode_TexFrom;
-/* SpaceNode.shaderfrom */
+/** #SpaceNode.shaderfrom */
typedef enum eSpaceNode_ShaderFrom {
SNODE_SHADER_OBJECT = 0,
SNODE_SHADER_WORLD = 1,
SNODE_SHADER_LINESTYLE = 2,
} eSpaceNode_ShaderFrom;
-/* SpaceNode.insert_ofs_dir */
+/** #SpaceNode.insert_ofs_dir */
enum {
SNODE_INSERTOFS_DIR_RIGHT = 0,
SNODE_INSERTOFS_DIR_LEFT = 1,
@@ -1629,7 +1631,7 @@ enum {
/** \name Console
* \{ */
-/* Console content */
+/** Console content. */
typedef struct ConsoleLine {
struct ConsoleLine *next, *prev;
@@ -1645,7 +1647,7 @@ typedef struct ConsoleLine {
int type;
} ConsoleLine;
-/* ConsoleLine.type */
+/** #ConsoleLine.type */
typedef enum eConsoleLine_Type {
CONSOLE_LINE_OUTPUT = 0,
CONSOLE_LINE_INPUT = 1,
@@ -1653,7 +1655,7 @@ typedef enum eConsoleLine_Type {
CONSOLE_LINE_ERROR = 3,
} eConsoleLine_Type;
-/* Console View */
+/** Console View. */
typedef struct SpaceConsole {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1707,7 +1709,7 @@ typedef struct SpaceUserPref {
/** \name Motion Tracking
* \{ */
-/* Clip Editor */
+/** Clip Editor. */
typedef struct SpaceClip {
SpaceLink *next, *prev;
/** Storage of regions for inactive spaces. */
@@ -1770,7 +1772,7 @@ typedef struct SpaceClip {
MaskSpaceInfo mask_info;
} SpaceClip;
-/* SpaceClip.flag */
+/** #SpaceClip.flag */
typedef enum eSpaceClip_Flag {
SC_SHOW_MARKER_PATTERN = (1 << 0),
SC_SHOW_MARKER_SEARCH = (1 << 1),
@@ -1797,7 +1799,7 @@ typedef enum eSpaceClip_Flag {
SC_SHOW_METADATA = (1 << 22),
} eSpaceClip_Flag;
-/* SpaceClip.mode */
+/** #SpaceClip.mode */
typedef enum eSpaceClip_Mode {
SC_MODE_TRACKING = 0,
// SC_MODE_RECONSTRUCTION = 1, /* DEPRECATED */
@@ -1805,14 +1807,14 @@ typedef enum eSpaceClip_Mode {
SC_MODE_MASKEDIT = 3,
} eSpaceClip_Mode;
-/* SpaceClip.view */
+/** #SpaceClip.view */
typedef enum eSpaceClip_View {
SC_VIEW_CLIP = 0,
SC_VIEW_GRAPH = 1,
SC_VIEW_DOPESHEET = 2,
} eSpaceClip_View;
-/* SpaceClip.gpencil_src */
+/** #SpaceClip.gpencil_src */
typedef enum eSpaceClip_GPencil_Source {
SC_GPENCIL_SRC_CLIP = 0,
SC_GPENCIL_SRC_TRACK = 1,
@@ -2030,8 +2032,10 @@ typedef enum eSpreadsheetColumnValueType {
/** \name Space Defines (eSpace_Type)
* \{ */
-/* space types, moved from DNA_screen_types.h */
-/* Do NOT change order, append on end. types are hardcoded needed */
+/**
+ * Space types: #SpaceLink.spacetype & #ScrArea.spacetype.
+ * \note Do NOT change order, append on end. types are hardcoded needed.
+ */
typedef enum eSpace_Type {
SPACE_EMPTY = 0,
SPACE_VIEW3D = 1,
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index 2c3cd8eab77..cd19825d29f 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -98,8 +98,10 @@ typedef struct CBData {
int cur;
} CBData;
-/* 32 = MAXCOLORBAND */
-/* note that this has to remain a single struct, for UserDef */
+/**
+ * 32 = #MAXCOLORBAND
+ * \note that this has to remain a single struct, for UserDef.
+ */
typedef struct ColorBand {
short tot, cur;
char ipotype, ipotype_hue;
@@ -454,14 +456,14 @@ typedef struct ColorMapping {
/* **************** ColorBand ********************* */
-/* colormode */
+/** color-mode. */
enum {
COLBAND_BLEND_RGB = 0,
COLBAND_BLEND_HSV = 1,
COLBAND_BLEND_HSL = 2,
};
-/* interpolation */
+/** Interpolation. */
enum {
COLBAND_INTERP_LINEAR = 0,
COLBAND_INTERP_EASE = 1,
@@ -470,7 +472,7 @@ enum {
COLBAND_INTERP_CONSTANT = 4,
};
-/* color interpolation */
+/** Color interpolation. */
enum {
COLBAND_HUE_NEAR = 0,
COLBAND_HUE_FAR = 1,
@@ -509,7 +511,7 @@ enum {
/* #define TEX_PD_NOISE_AGE 2 */ /* Deprecated */
/* #define TEX_PD_NOISE_TIME 3 */ /* Deprecated */
-/* color_source */
+/** color_source. */
enum {
TEX_PD_COLOR_CONSTANT = 0,
/* color_source: particles */
diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h
index 0e313183300..815fab59876 100644
--- a/source/blender/makesdna/DNA_tracking_types.h
+++ b/source/blender/makesdna/DNA_tracking_types.h
@@ -462,7 +462,7 @@ typedef struct MovieTracking {
MovieTrackingDopesheet dopesheet;
} MovieTracking;
-/* MovieTrackingCamera->distortion_model */
+/** #MovieTrackingCamera.distortion_model */
enum {
TRACKING_DISTORTION_MODEL_POLYNOMIAL = 0,
TRACKING_DISTORTION_MODEL_DIVISION = 1,
@@ -470,13 +470,13 @@ enum {
TRACKING_DISTORTION_MODEL_BROWN = 3,
};
-/* MovieTrackingCamera->units */
+/** #MovieTrackingCamera.units */
enum {
CAMERA_UNITS_PX = 0,
CAMERA_UNITS_MM = 1,
};
-/* MovieTrackingMarker->flag */
+/** #MovieTrackingMarker.flag */
enum {
MARKER_DISABLED = (1 << 0),
MARKER_TRACKED = (1 << 1),
@@ -485,7 +485,7 @@ enum {
MARKER_GRAPH_SEL = (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y),
};
-/* MovieTrackingTrack->flag */
+/** #MovieTrackingTrack.flag */
enum {
TRACK_HAS_BUNDLE = (1 << 1),
TRACK_DISABLE_RED = (1 << 2),
@@ -501,7 +501,7 @@ enum {
TRACK_USE_2D_STAB_ROT = (1 << 12),
};
-/* MovieTrackingTrack->motion_model */
+/** #MovieTrackingTrack.motion_model */
enum {
TRACK_MOTION_MODEL_TRANSLATION = 0,
TRACK_MOTION_MODEL_TRANSLATION_ROTATION = 1,
@@ -511,27 +511,27 @@ enum {
TRACK_MOTION_MODEL_HOMOGRAPHY = 5,
};
-/* MovieTrackingTrack->algorithm_flag */
+/** #MovieTrackingTrack.algorithm_flag */
enum {
TRACK_ALGORITHM_FLAG_USE_BRUTE = (1 << 0),
TRACK_ALGORITHM_FLAG_USE_NORMALIZATION = (1 << 2),
TRACK_ALGORITHM_FLAG_USE_MASK = (1 << 3),
};
-/* MovieTrackingTrack->pattern_match */
+/** #MovieTrackingTrack.pattern_match */
typedef enum eTrackFrameMatch {
TRACK_MATCH_KEYFRAME = 0,
TRACK_MATCH_PREVIOS_FRAME = 1,
} eTrackFrameMatch;
-/* MovieTrackingSettings->motion_flag */
+/** #MovieTrackingSettings.motion_flag */
enum {
TRACKING_MOTION_TRIPOD = (1 << 0),
TRACKING_MOTION_MODAL = (TRACKING_MOTION_TRIPOD),
};
-/* MovieTrackingSettings->speed */
+/** #MovieTrackingSettings.speed */
enum {
TRACKING_SPEED_FASTEST = 0,
TRACKING_SPEED_REALTIME = 1,
@@ -540,13 +540,13 @@ enum {
TRACKING_SPEED_DOUBLE = 5,
};
-/* MovieTrackingSettings->reconstruction_flag */
+/** #MovieTrackingSettings.reconstruction_flag */
enum {
/* TRACKING_USE_FALLBACK_RECONSTRUCTION = (1 << 0), */ /* DEPRECATED */
TRACKING_USE_KEYFRAME_SELECTION = (1 << 1),
};
-/* MovieTrackingSettings->refine_camera_intrinsics */
+/** #MovieTrackingSettings.refine_camera_intrinsics */
enum {
REFINE_NO_INTRINSICS = (0),
@@ -556,7 +556,7 @@ enum {
REFINE_TANGENTIAL_DISTORTION = (1 << 3),
};
-/* MovieTrackingStabilization->flag */
+/** #MovieTrackingStabilization.flag */
enum {
TRACKING_2D_STABILIZATION = (1 << 0),
TRACKING_AUTOSCALE = (1 << 1),
@@ -565,19 +565,19 @@ enum {
TRACKING_SHOW_STAB_TRACKS = (1 << 5),
};
-/* MovieTrackingStabilization->filter */
+/** #MovieTrackingStabilization.filter */
enum {
TRACKING_FILTER_NEAREST = 0,
TRACKING_FILTER_BILINEAR = 1,
TRACKING_FILTER_BICUBIC = 2,
};
-/* MovieTrackingReconstruction->flag */
+/** #MovieTrackingReconstruction.flag */
enum {
TRACKING_RECONSTRUCTED = (1 << 0),
};
-/* MovieTrackingObject->flag */
+/** #MovieTrackingObject.flag */
enum {
TRACKING_OBJECT_CAMERA = (1 << 0),
};
@@ -588,7 +588,7 @@ enum {
TRACKING_CLEAN_DELETE_SEGMENT = 2,
};
-/* MovieTrackingDopesheet->sort_method */
+/** #MovieTrackingDopesheet.sort_method */
enum {
TRACKING_DOPE_SORT_NAME = 0,
TRACKING_DOPE_SORT_LONGEST = 1,
@@ -598,27 +598,27 @@ enum {
TRACKING_DOPE_SORT_END = 5,
};
-/* MovieTrackingDopesheet->flag */
+/** #MovieTrackingDopesheet.flag */
enum {
TRACKING_DOPE_SORT_INVERSE = (1 << 0),
TRACKING_DOPE_SELECTED_ONLY = (1 << 1),
TRACKING_DOPE_SHOW_HIDDEN = (1 << 2),
};
-/* MovieTrackingDopesheetCoverageSegment->trackness */
+/** #MovieTrackingDopesheetCoverageSegment.trackness */
enum {
TRACKING_COVERAGE_BAD = 0,
TRACKING_COVERAGE_ACCEPTABLE = 1,
TRACKING_COVERAGE_OK = 2,
};
-/* MovieTrackingPlaneMarker->flag */
+/** #MovieTrackingPlaneMarker.flag */
enum {
PLANE_MARKER_DISABLED = (1 << 0),
PLANE_MARKER_TRACKED = (1 << 1),
};
-/* MovieTrackingPlaneTrack->flag */
+/** #MovieTrackingPlaneTrack.flag */
enum {
PLANE_TRACK_HIDDEN = (1 << 1),
PLANE_TRACK_LOCKED = (1 << 2),
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index c8fdac19b61..34415308ef6 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -30,7 +30,8 @@
extern "C" {
#endif
-/* themes; defines in BIF_resource.h */
+/* Themes; defines in `BIF_resource.h`. */
+
struct ColorBand;
/* ************************ style definitions ******************** */
@@ -50,8 +51,10 @@ typedef enum eUIFont_ID {
/* UIFONT_CUSTOM2 = 3, */ /* UNUSED */
} eUIFont_ID;
-/* default fonts to load/initialize */
-/* first font is the default (index 0), others optional */
+/**
+ * Default fonts to load/initialize.
+ * First font is the default (index 0), others optional.
+ */
typedef struct uiFont {
struct uiFont *next, *prev;
/** 1024 = FILE_MAX. */
@@ -445,7 +448,7 @@ typedef enum eBackgroundGradientTypes {
TH_BACKGROUND_GRADIENT_RADIAL = 2,
} eBackgroundGradientTypes;
-/* set of colors for use as a custom color set for Objects/Bones wire drawing */
+/** Set of colors for use as a custom color set for Objects/Bones wire drawing. */
typedef struct ThemeWireColor {
unsigned char solid[4];
unsigned char select[4];
@@ -959,7 +962,7 @@ typedef struct UserDef {
UserDef_Runtime runtime;
} UserDef;
-/* from blenkernel blender.c */
+/** From blenkernel `blender.c`. */
extern UserDef U;
/* ***************** USERDEF ****************** */
@@ -1142,6 +1145,7 @@ typedef enum eUserpref_GPU_Flag {
USER_GPU_FLAG_NO_DEPT_PICK = (1 << 0),
USER_GPU_FLAG_NO_EDIT_MODE_SMOOTH_WIRE = (1 << 1),
USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE = (1 << 2),
+ USER_GPU_FLAG_SUBDIVISION_EVALUATION = (1 << 3),
} eUserpref_GPU_Flag;
/** #UserDef.tablet_api */
diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h
index f8166305fd9..6c03422963d 100644
--- a/source/blender/makesdna/DNA_view2d_types.h
+++ b/source/blender/makesdna/DNA_view2d_types.h
@@ -31,7 +31,7 @@ extern "C" {
/* ---------------------------------- */
-/* View 2D data - stored per region */
+/** View 2D data - stored per region. */
typedef struct View2D {
/** Tot - area that data can be drawn in; cur - region of tot that is visible in viewport. */
rctf tot, cur;
@@ -83,7 +83,7 @@ typedef struct View2D {
/* ---------------------------------- */
-/* view zooming restrictions, per axis (v2d->keepzoom) */
+/** View zooming restrictions, per axis (#View2D.keepzoom) */
enum {
/* zoom is clamped to lie within limits set by minzoom and maxzoom */
V2D_LIMITZOOM = (1 << 0),
@@ -97,7 +97,7 @@ enum {
V2D_LOCKZOOM_Y = (1 << 9),
};
-/* view panning restrictions, per axis (v2d->keepofs) */
+/** View panning restrictions, per axis (#View2D.keepofs). */
enum {
/* panning on x-axis is not allowed */
V2D_LOCKOFS_X = (1 << 1),
@@ -109,7 +109,7 @@ enum {
V2D_KEEPOFS_Y = (1 << 4),
};
-/* view extent restrictions (v2d->keeptot) */
+/** View extent restrictions (#View2D.keeptot). */
enum {
/** 'cur' view can be out of extents of 'tot' */
V2D_KEEPTOT_FREE = 0,
@@ -120,7 +120,7 @@ enum {
V2D_KEEPTOT_STRICT = 2,
};
-/* general refresh settings (v2d->flag) */
+/** General refresh settings (#View2D.flag). */
enum {
/* global view2d horizontal locking (for showing same time interval) */
/* TODO: this flag may be set in old files but is not accessible currently,
@@ -138,7 +138,7 @@ enum {
V2D_IS_INIT = (1 << 10),
};
-/* scroller flags for View2D (v2d->scroll) */
+/** Scroller flags for View2D (#View2D.scroll). */
enum {
/* left scrollbar */
V2D_SCROLL_LEFT = (1 << 0),
@@ -162,13 +162,15 @@ enum {
V2D_SCROLL_HORIZONTAL_FULLR = (1 << 10),
};
-/* scroll_ui, activate flag for drawing */
+/** scroll_ui, activate flag for drawing. */
enum {
V2D_SCROLL_H_ACTIVE = (1 << 0),
V2D_SCROLL_V_ACTIVE = (1 << 1),
};
-/* alignment flags for totrect, flags use 'shading-out' convention (v2d->align) */
+/**
+ * Alignment flags for `totrect`, flags use 'shading-out' convention (#View2D.align).
+ */
enum {
/* all quadrants free */
V2D_ALIGN_FREE = 0,
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 3fd2f1208dd..5f4353b6f3a 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -245,7 +245,7 @@ typedef struct View3DOverlay {
char _pad[4];
} View3DOverlay;
-/* View3DOverlay->handle_display */
+/** #View3DOverlay.handle_display */
typedef enum eHandleDisplay {
/* Display only selected points. */
CURVE_HANDLE_SELECTED = 0,
diff --git a/source/blender/makesdna/DNA_volume_types.h b/source/blender/makesdna/DNA_volume_types.h
index 1344f295ea9..df5a122faaf 100644
--- a/source/blender/makesdna/DNA_volume_types.h
+++ b/source/blender/makesdna/DNA_volume_types.h
@@ -30,13 +30,13 @@ struct PackedFile;
struct VolumeGridVector;
typedef struct Volume_Runtime {
- /* OpenVDB Grids */
+ /** OpenVDB Grids. */
struct VolumeGridVector *grids;
- /* Current frame in sequence for evaluated volume */
+ /** Current frame in sequence for evaluated volume. */
int frame;
- /* Default simplify level for volume grids loaded from files. */
+ /** Default simplify level for volume grids loaded from files. */
int default_simplify_level;
} Volume_Runtime;
@@ -96,12 +96,12 @@ typedef struct Volume {
Volume_Runtime runtime;
} Volume;
-/* Volume.flag */
+/** #Volume.flag */
enum {
VO_DS_EXPAND = (1 << 0),
};
-/* Volume.sequence_mode */
+/** #Volume.sequence_mode */
typedef enum VolumeSequenceMode {
VOLUME_SEQUENCE_CLIP = 0,
VOLUME_SEQUENCE_EXTEND = 1,
@@ -109,7 +109,7 @@ typedef enum VolumeSequenceMode {
VOLUME_SEQUENCE_PING_PONG = 3,
} VolumeSequenceMode;
-/* VolumeDisplay.wireframe_type */
+/** #VolumeDisplay.wireframe_type */
typedef enum VolumeWireframeType {
VOLUME_WIREFRAME_NONE = 0,
VOLUME_WIREFRAME_BOUNDS = 1,
@@ -117,32 +117,32 @@ typedef enum VolumeWireframeType {
VOLUME_WIREFRAME_POINTS = 3,
} VolumeWireframeType;
-/* VolumeDisplay.wireframe_detail */
+/** #VolumeDisplay.wireframe_detail */
typedef enum VolumeWireframeDetail {
VOLUME_WIREFRAME_COARSE = 0,
VOLUME_WIREFRAME_FINE = 1,
} VolumeWireframeDetail;
-/* VolumeRender.space */
+/** #VolumeRender.space */
typedef enum VolumeRenderSpace {
VOLUME_SPACE_OBJECT = 0,
VOLUME_SPACE_WORLD = 1,
} VolumeRenderSpace;
-/* VolumeDisplay.interpolation_method */
+/** #VolumeDisplay.interpolation_method */
typedef enum VolumeDisplayInterpMethod {
VOLUME_DISPLAY_INTERP_LINEAR = 0,
VOLUME_DISPLAY_INTERP_CUBIC = 1,
VOLUME_DISPLAY_INTERP_CLOSEST = 2,
} VolumeDisplayInterpMethod;
-/* VolumeDisplay.axis_slice_method */
+/** #VolumeDisplay.axis_slice_method */
typedef enum AxisAlignedSlicingMethod {
VOLUME_AXIS_SLICE_FULL = 0,
VOLUME_AXIS_SLICE_SINGLE = 1,
} AxisAlignedSlicingMethod;
-/* VolumeDisplay.slice_axis */
+/** #VolumeDisplay.slice_axis */
typedef enum SliceAxis {
VOLUME_SLICE_AXIS_AUTO = 0,
VOLUME_SLICE_AXIS_X = 1,
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 841edaf8724..d0e4184d2a5 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -33,7 +33,8 @@
extern "C" {
#endif
-/* defined here: */
+/* Defined here: */
+
struct wmWindow;
struct wmWindowManager;
@@ -45,7 +46,8 @@ struct wmMsgBus;
struct wmOperator;
struct wmOperatorType;
-/* forwards */
+/* Forward declarations: */
+
struct PointerRNA;
struct Report;
struct ReportList;
@@ -58,7 +60,7 @@ struct wmTimer;
#define OP_MAX_TYPENAME 64
#define KMAP_MAX_NAME 64
-/* keep in sync with 'rna_enum_wm_report_items' in wm_rna.c */
+/** Keep in sync with 'rna_enum_wm_report_items' in `wm_rna.c`. */
typedef enum eReportType {
RPT_DEBUG = (1 << 0),
RPT_INFO = (1 << 1),
@@ -100,7 +102,9 @@ typedef struct Report {
const char *message;
} Report;
-/* saved in the wm, don't remove */
+/**
+ * \note Saved in the wm, don't remove.
+ */
typedef struct ReportList {
ListBase list;
/** eReportType. */
@@ -133,7 +137,7 @@ typedef struct wmXrData {
/* reports need to be before wmWindowManager */
-/* windowmanager is saved, tag WMAN */
+/** Window-manager is saved, tag WMAN. */
typedef struct wmWindowManager {
ID id;
@@ -204,13 +208,13 @@ typedef struct wmWindowManager {
//#endif
} wmWindowManager;
-/* wmWindowManager.initialized */
+/** #wmWindowManager.initialized */
enum {
WM_WINDOW_IS_INIT = (1 << 0),
WM_KEYCONFIG_IS_INIT = (1 << 1),
};
-/* wmWindowManager.outliner_sync_select_dirty */
+/** #wmWindowManager.outliner_sync_select_dirty */
enum {
WM_OUTLINER_SYNC_SELECT_FROM_OBJECT = (1 << 0),
WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE = (1 << 1),
@@ -231,7 +235,9 @@ enum {
# endif
#endif
-/* the saveable part, rest of data is local in ghostwinlay */
+/**
+ * The saveable part, the rest of the data is local in GHOST.
+ */
typedef struct wmWindow {
struct wmWindow *next, *prev;
@@ -352,7 +358,9 @@ typedef struct wmOperatorTypeMacro {
struct PointerRNA *ptr;
} wmOperatorTypeMacro;
-/* Partial copy of the event, for matching by event handler. */
+/**
+ * Partial copy of the event, for matching by event handler.
+ */
typedef struct wmKeyMapItem {
struct wmKeyMapItem *next, *prev;
@@ -436,7 +444,9 @@ enum {
KMI_TYPE_NDOF = 5,
};
-/* stored in WM, the actively used keymaps */
+/**
+ * Stored in WM, the actively used key-maps.
+ */
typedef struct wmKeyMap {
struct wmKeyMap *next, *prev;
diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h
index a0856588a58..95530c7b0f7 100644
--- a/source/blender/makesdna/DNA_workspace_types.h
+++ b/source/blender/makesdna/DNA_workspace_types.h
@@ -60,7 +60,9 @@ typedef struct bToolRef_Runtime {
int flag;
} bToolRef_Runtime;
-/* Stored per mode. */
+/**
+ * \note Stored per mode.
+ */
typedef struct bToolRef {
struct bToolRef *next, *prev;
char idname[64];
diff --git a/source/blender/makesdna/intern/dna_utils.h b/source/blender/makesdna/intern/dna_utils.h
index b89c45a7a43..7ba71fb970b 100644
--- a/source/blender/makesdna/intern/dna_utils.h
+++ b/source/blender/makesdna/intern/dna_utils.h
@@ -60,7 +60,9 @@ char *DNA_elem_id_rename(struct MemArena *mem_arena,
const int elem_src_full_len,
const uint elem_src_full_offset_len);
-/* When requesting version info, support both directions. */
+/**
+ * When requesting version info, support both directions.
+ */
enum eDNA_RenameDir {
DNA_RENAME_STATIC_FROM_ALIAS = -1,
DNA_RENAME_ALIAS_FROM_STATIC = 1,
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
index 35af92592e9..19c678a4222 100644
--- a/source/blender/makesrna/intern/rna_access_compare_override.c
+++ b/source/blender/makesrna/intern/rna_access_compare_override.c
@@ -1095,8 +1095,8 @@ static void rna_property_override_check_resync(Main *bmain,
ID *id_src = rna_property_override_property_real_id_owner(bmain, ptr_item_src, NULL, NULL);
ID *id_dst = rna_property_override_property_real_id_owner(bmain, ptr_item_dst, NULL, NULL);
- BLI_assert(id_src == NULL || ID_IS_OVERRIDE_LIBRARY_REAL(id_src));
- /* Work around file corruption on writing, see T86853. */
+ /* If `id_src` is not a liboverride, we cannot perform any further 'need resync' checks from
+ * here. */
if (id_src != NULL && !ID_IS_OVERRIDE_LIBRARY_REAL(id_src)) {
return;
}
@@ -1117,8 +1117,8 @@ static void rna_property_override_check_resync(Main *bmain,
* override copy generated by `BKE_lib_override_library_update` will already have its
* self-references updated to itself, instead of still pointing to its linked source. */
(id_dst->lib == id_src->lib && id_dst != id_owner))) {
- ptr_dst->owner_id->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
- CLOG_INFO(&LOG, 3, "Local override %s detected as needing resync", ptr_dst->owner_id->name);
+ id_owner->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
+ CLOG_INFO(&LOG, 3, "Local override %s detected as needing resync", id_owner->name);
}
}
diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c
index 2bc00dd5af5..187e232b030 100644
--- a/source/blender/makesrna/intern/rna_cloth.c
+++ b/source/blender/makesrna/intern/rna_cloth.c
@@ -584,6 +584,8 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "ClothSimSettings");
RNA_def_struct_path_func(srna, "rna_ClothSettings_path");
+ RNA_define_lib_overridable(true);
+
/* goal */
prop = RNA_def_property(srna, "goal_min", PROP_FLOAT, PROP_FACTOR);
@@ -659,6 +661,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_mass_vgroup_get",
"rna_ClothSettings_mass_vgroup_length",
"rna_ClothSettings_mass_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Mass Vertex Group", "Vertex Group for pinning of vertices");
RNA_def_property_update(prop, 0, "rna_cloth_pinning_changed");
@@ -707,6 +710,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_shrink_vgroup_get",
"rna_ClothSettings_shrink_vgroup_length",
"rna_ClothSettings_shrink_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Shrink Vertex Group", "Vertex Group for shrinking cloth");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -810,6 +814,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_struct_vgroup_get",
"rna_ClothSettings_struct_vgroup_length",
"rna_ClothSettings_struct_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop,
"Structural Stiffness Vertex Group",
"Vertex group for fine control over structural stiffness");
@@ -820,6 +825,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_shear_vgroup_get",
"rna_ClothSettings_shear_vgroup_length",
"rna_ClothSettings_shear_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop, "Shear Stiffness Vertex Group", "Vertex group for fine control over shear stiffness");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -856,6 +862,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_bend_vgroup_get",
"rna_ClothSettings_bend_vgroup_length",
"rna_ClothSettings_bend_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop,
"Bending Stiffness Vertex Group",
"Vertex group for fine control over bending stiffness");
@@ -874,6 +881,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_rest_shape_key_set",
NULL,
NULL);
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop, "Rest Shape Key", "Shape key to use the rest spring lengths from");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -976,6 +984,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_internal_vgroup_get",
"rna_ClothSettings_internal_vgroup_length",
"rna_ClothSettings_internal_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop,
"Internal Springs Vertex Group",
"Vertex group for fine control over the internal spring stiffness");
@@ -1044,6 +1053,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
"rna_ClothSettings_pressure_vgroup_get",
"rna_ClothSettings_pressure_vgroup_length",
"rna_ClothSettings_pressure_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop,
"Pressure Vertex Group",
@@ -1082,6 +1092,8 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Maximum Spring Extension", "Maximum extension before spring gets cut");
# endif
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_cloth_collision_settings(BlenderRNA *brna)
@@ -1097,6 +1109,8 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "ClothCollSettings");
RNA_def_struct_path_func(srna, "rna_ClothCollisionSettings_path");
+ RNA_define_lib_overridable(true);
+
/* general collision */
prop = RNA_def_property(srna, "use_collision", PROP_BOOLEAN, PROP_NONE);
@@ -1169,7 +1183,6 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "collection", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "group");
RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Collision Collection", "Limit colliders to this Collection");
RNA_def_property_update(prop, 0, "rna_cloth_dependency_update");
@@ -1178,6 +1191,7 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
"rna_CollSettings_selfcol_vgroup_get",
"rna_CollSettings_selfcol_vgroup_length",
"rna_CollSettings_selfcol_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop,
"Selfcollision Vertex Group",
@@ -1189,6 +1203,7 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
"rna_CollSettings_objcol_vgroup_get",
"rna_CollSettings_objcol_vgroup_length",
"rna_CollSettings_objcol_vgroup_set");
+ RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(
prop,
"Collision Vertex Group",
@@ -1203,6 +1218,8 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
"Impulse Clamping",
"Clamp collision impulses to avoid instability (0.0 to disable clamping)");
RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ RNA_define_lib_overridable(false);
}
void RNA_def_cloth(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 5c12fc3a227..091b457cc83 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -321,7 +321,7 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
CMP_NODE_VALTORGB,
TEX_NODE_VALTORGB,
GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP)) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
}
break;
diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c
index a9d5ef089bb..b693d78a302 100644
--- a/source/blender/makesrna/intern/rna_dynamicpaint.c
+++ b/source/blender/makesrna/intern/rna_dynamicpaint.c
@@ -589,6 +589,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
prop = RNA_def_property(srna, "drip_velocity", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index a38bbd3d6d2..d3175c445a9 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -388,6 +388,7 @@ void rna_DriverVariable_name_set(PointerRNA *ptr, const char *value)
BLI_strncpy_utf8(data->name, value, 64);
driver_variable_name_validate(data);
+ driver_variable_unique_name(data);
}
/* ----------- */
diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c
index 90e77406f23..7aa96eb8430 100644
--- a/source/blender/makesrna/intern/rna_fluid.c
+++ b/source/blender/makesrna/intern/rna_fluid.c
@@ -1461,6 +1461,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
/* object collections */
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 2f42e521b52..0d86572357f 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -168,7 +168,7 @@ static void rna_ImageUser_update(Main *bmain, Scene *scene, PointerRNA *ptr)
if (id) {
if (GS(id->name) == ID_NT) {
/* Special update for nodetrees to find parent datablock. */
- ED_node_tag_update_nodetree(bmain, (bNodeTree *)id, NULL);
+ ED_node_tree_propagate_change(NULL, bmain, NULL);
}
else {
/* Update material or texture for render preview. */
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index df0271d81d5..98de40ead93 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -42,6 +42,7 @@
#include "BKE_geometry_set.h"
#include "BKE_image.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_texture.h"
#include "RNA_access.h"
@@ -1219,7 +1220,7 @@ static void rna_NodeTree_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *p
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
WM_main_add_notifier(NC_SCENE | ND_NODES, &ntree->id);
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static bNode *rna_NodeTree_node_new(bNodeTree *ntree,
@@ -1269,14 +1270,9 @@ static bNode *rna_NodeTree_node_new(bNodeTree *ntree,
}
Main *bmain = CTX_data_main(C);
- ntreeUpdateTree(bmain, ntree);
- nodeUpdate(ntree, node);
+ ED_node_tree_propagate_change(C, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
- if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
- DEG_relations_tag_update(bmain);
- }
-
return node;
}
@@ -1300,7 +1296,7 @@ static void rna_NodeTree_node_remove(bNodeTree *ntree,
RNA_POINTER_INVALIDATE(node_ptr);
- ntreeUpdateTree(bmain, ntree); /* update group node socket links */
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1320,8 +1316,7 @@ static void rna_NodeTree_node_clear(bNodeTree *ntree, Main *bmain, ReportList *r
node = next_node;
}
- ntreeUpdateTree(bmain, ntree);
-
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1400,13 +1395,7 @@ static bNodeLink *rna_NodeTree_link_new(bNodeTree *ntree,
fromsock->flag &= ~SOCK_HIDDEN;
tosock->flag &= ~SOCK_HIDDEN;
- if (tonode) {
- nodeUpdate(ntree, tonode);
- }
-
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, ret->tonode);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
return ret;
@@ -1431,7 +1420,7 @@ static void rna_NodeTree_link_remove(bNodeTree *ntree,
nodeRemLink(ntree, link);
RNA_POINTER_INVALIDATE(link_ptr);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1450,8 +1439,7 @@ static void rna_NodeTree_link_clear(bNodeTree *ntree, Main *bmain, ReportList *r
link = next_link;
}
- ntreeUpdateTree(bmain, ntree);
-
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1508,7 +1496,7 @@ static bNodeSocket *rna_NodeTree_inputs_new(
bNodeSocket *sock = ntreeAddSocketInterface(ntree, SOCK_IN, type, name);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
return sock;
@@ -1523,7 +1511,7 @@ static bNodeSocket *rna_NodeTree_outputs_new(
bNodeSocket *sock = ntreeAddSocketInterface(ntree, SOCK_OUT, type, name);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
return sock;
@@ -1544,8 +1532,7 @@ static void rna_NodeTree_socket_remove(bNodeTree *ntree,
else {
ntreeRemoveSocketInterface(ntree, sock);
- ntreeUpdateTree(bmain, ntree);
- DEG_id_tag_update(&ntree->id, 0);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
}
@@ -1560,7 +1547,7 @@ static void rna_NodeTree_inputs_clear(bNodeTree *ntree, Main *bmain, ReportList
ntreeRemoveSocketInterface(ntree, socket);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1574,7 +1561,7 @@ static void rna_NodeTree_outputs_clear(bNodeTree *ntree, Main *bmain, ReportList
ntreeRemoveSocketInterface(ntree, socket);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1603,9 +1590,9 @@ static void rna_NodeTree_inputs_move(bNodeTree *ntree, Main *bmain, int from_ind
}
}
- ntree->update |= NTREE_UPDATE_GROUP_IN;
+ BKE_ntree_update_tag_interface(ntree);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1634,9 +1621,9 @@ static void rna_NodeTree_outputs_move(bNodeTree *ntree, Main *bmain, int from_in
}
}
- ntree->update |= NTREE_UPDATE_GROUP_OUT;
+ BKE_ntree_update_tag_interface(ntree);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -1644,10 +1631,8 @@ static void rna_NodeTree_interface_update(bNodeTree *ntree, bContext *C)
{
Main *bmain = CTX_data_main(C);
- ntree->update |= NTREE_UPDATE_GROUP;
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ BKE_ntree_update_tag_interface(ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
/* ******** NodeLink ******** */
@@ -1968,7 +1953,7 @@ static bNodeType *rna_Node_register_base(Main *bmain,
/* setup dummy node & node type to store static properties in */
memset(&dummynt, 0, sizeof(bNodeType));
/* this does some additional initialization of default values */
- node_type_base_custom(&dummynt, identifier, "", 0, 0);
+ node_type_base_custom(&dummynt, identifier, "", 0);
memset(&dummynode, 0, sizeof(bNode));
dummynode.typeinfo = &dummynt;
@@ -2210,6 +2195,20 @@ static const EnumPropertyItem *rna_FunctionNodeRandomValue_type_itemf(bContext *
return itemf_function_check(rna_enum_attribute_type_items, random_value_type_supported);
}
+static bool accumulate_field_type_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_INT32);
+}
+
+static const EnumPropertyItem *rna_GeoNodeAccumulateField_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, accumulate_field_type_supported);
+}
+
static const EnumPropertyItem *rna_GeometryNodeAttributeRandomize_operation_itemf(
bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -2617,7 +2616,8 @@ static void rna_Node_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static void rna_Node_update_relations(Main *bmain, Scene *scene, PointerRNA *ptr)
@@ -2626,9 +2626,10 @@ static void rna_Node_update_relations(Main *bmain, Scene *scene, PointerRNA *ptr
DEG_relations_tag_update(bmain);
}
-static void rna_Node_socket_value_update(ID *id, bNode *node, bContext *C)
+static void rna_Node_socket_value_update(ID *id, bNode *UNUSED(node), bContext *C)
{
- ED_node_tag_update_nodetree(CTX_data_main(C), (bNodeTree *)id, node);
+ BKE_ntree_update_tag_all((bNodeTree *)id);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), (bNodeTree *)id);
}
static void rna_Node_select_set(PointerRNA *ptr, bool value)
@@ -2682,7 +2683,7 @@ static bNodeSocket *rna_Node_inputs_new(ID *id,
BKE_report(reports, RPT_ERROR, "Unable to create socket");
}
else {
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2716,7 +2717,7 @@ static bNodeSocket *rna_Node_outputs_new(ID *id,
BKE_report(reports, RPT_ERROR, "Unable to create socket");
}
else {
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2734,7 +2735,7 @@ static void rna_Node_socket_remove(
else {
nodeRemoveSocket(ntree, node, sock);
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
}
@@ -2749,7 +2750,7 @@ static void rna_Node_inputs_clear(ID *id, bNode *node, Main *bmain)
nodeRemoveSocket(ntree, node, sock);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2763,7 +2764,7 @@ static void rna_Node_outputs_clear(ID *id, bNode *node, Main *bmain)
nodeRemoveSocket(ntree, node, sock);
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2795,7 +2796,7 @@ static void rna_Node_inputs_move(ID *id, bNode *node, Main *bmain, int from_inde
}
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -2827,7 +2828,7 @@ static void rna_Node_outputs_move(ID *id, bNode *node, Main *bmain, int from_ind
}
}
- ntreeUpdateTree(bmain, ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
}
@@ -3055,10 +3056,9 @@ static void rna_NodeSocket_update(Main *bmain, Scene *UNUSED(scene), PointerRNA
{
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNodeSocket *sock = (bNodeSocket *)ptr->data;
- bNode *node;
- if (nodeFindNode(ntree, sock, &node, NULL)) {
- ED_node_tag_update_nodetree(bmain, ntree, node);
- }
+
+ BKE_ntree_update_tag_socket_property(ntree, sock);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static bool rna_NodeSocket_is_output_get(PointerRNA *ptr)
@@ -3351,10 +3351,8 @@ static void rna_NodeSocketInterface_update(Main *bmain, Scene *UNUSED(scene), Po
return;
}
- ntree->update |= NTREE_UPDATE_GROUP;
- ntreeUpdateTree(bmain, ntree);
-
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ BKE_ntree_update_tag_interface(ntree);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
/* ******** Standard Node Socket Base Types ******** */
@@ -3452,28 +3450,14 @@ static void rna_NodeSocketStandard_vector_range(
/* using a context update function here, to avoid searching the node if possible */
static void rna_NodeSocketStandard_value_update(struct bContext *C, PointerRNA *ptr)
{
- bNode *node;
-
/* default update */
rna_NodeSocket_update(CTX_data_main(C), CTX_data_scene(C), ptr);
-
- /* try to use node from context, faster */
- node = CTX_data_pointer_get(C, "node").data;
- if (!node) {
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNodeSocket *sock = ptr->data;
-
- /* fall back to searching node in the tree */
- nodeFindNode(ntree, sock, &node, NULL);
- }
}
static void rna_NodeSocketStandard_value_and_relation_update(struct bContext *C, PointerRNA *ptr)
{
rna_NodeSocketStandard_value_update(C, ptr);
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
Main *bmain = CTX_data_main(C);
- ntreeUpdateTree(bmain, ntree);
DEG_relations_tag_update(bmain);
}
@@ -3567,12 +3551,11 @@ static bool rna_NodeInternal_poll_instance(bNode *node, bNodeTree *ntree)
}
}
-static void rna_NodeInternal_update(ID *id, bNode *node)
+static void rna_NodeInternal_update(ID *id, bNode *node, Main *bmain)
{
bNodeTree *ntree = (bNodeTree *)id;
- if (node->typeinfo->updatefunc) {
- node->typeinfo->updatefunc(ntree, node);
- }
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static void rna_NodeInternal_draw_buttons(ID *id,
@@ -3721,7 +3704,8 @@ static void rna_Node_tex_image_update(Main *bmain, Scene *UNUSED(scene), Pointer
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
WM_main_add_notifier(NC_IMAGE, NULL);
}
@@ -3730,11 +3714,8 @@ static void rna_NodeGroup_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- if (node->id) {
- ntreeUpdateTree(bmain, (bNodeTree *)node->id);
- }
-
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
DEG_relations_tag_update(bmain);
}
@@ -4142,13 +4123,12 @@ static const EnumPropertyItem *rna_Node_channel_itemf(bContext *UNUSED(C),
return item;
}
-static void rna_Image_Node_update_id(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_Image_Node_update_id(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
node->update |= NODE_UPDATE_ID;
- nodeUpdate(ntree, node); /* to update image node sockets */
+ rna_Node_update(bmain, scene, ptr);
}
static void rna_NodeOutputFile_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -4395,7 +4375,7 @@ static bNodeSocket *rna_NodeOutputFile_slots_new(
sock = ntreeCompositOutputFileAddSocket(ntree, node, name, im_format);
- ntreeUpdateTree(CTX_data_main(C), ntree);
+ ED_node_tree_propagate_change(C, CTX_data_main(C), ntree);
WM_main_add_notifier(NC_NODE | NA_EDITED, ntree);
return sock;
@@ -4504,42 +4484,27 @@ static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *p
RE_engine_free(engine);
}
- ED_node_tag_update_nodetree(bmain, ntree, node);
+ BKE_ntree_update_tag_node_property(ntree, node);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
static void rna_ShaderNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
static void rna_Node_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
static void rna_GeometryNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
static void rna_CompositorNodeScale_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- bNode *node = (bNode *)ptr->data;
-
- nodeUpdate(ntree, node);
rna_Node_update(bmain, scene, ptr);
}
@@ -9491,6 +9456,28 @@ static void def_geo_subdivision_surface(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_geo_accumulate_field(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeAccumulateField", "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_GeoNodeAccumulateField_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_Node_socket_update");
+
+ prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "domain");
+ RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items);
+ RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT);
+ RNA_def_property_ui_text(prop, "Domain", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_fn_random_value(StructRNA *srna)
{
PropertyRNA *prop;
@@ -12386,7 +12373,7 @@ static void rna_def_internal_node(BlenderRNA *brna)
func = RNA_def_function(srna, "update", "rna_NodeInternal_update");
RNA_def_function_ui_description(
func, "Update on node graph topology changes (adding or removing nodes and links)");
- RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_ALLOW_WRITE);
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_ALLOW_WRITE);
/* draw buttons */
func = RNA_def_function(srna, "draw_buttons", "rna_NodeInternal_draw_buttons");
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 2fca9f0af7a..d697a48e04b 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -1128,6 +1128,8 @@ static void rna_def_collision(BlenderRNA *brna)
RNA_def_struct_ui_text(
srna, "Collision Settings", "Collision settings for object in physics simulation");
+ RNA_define_lib_overridable(true);
+
prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "deflect", 1);
RNA_def_property_ui_text(
@@ -1230,6 +1232,8 @@ static void rna_def_collision(BlenderRNA *brna)
"Cloth collision impulses act in the direction of the collider normals "
"(more reliable in some cases)");
RNA_def_property_update(prop, 0, "rna_CollisionSettings_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_effector_weight(BlenderRNA *brna)
@@ -1243,6 +1247,8 @@ static void rna_def_effector_weight(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Effector Weights", "Effector weights for physics simulation");
RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
+ RNA_define_lib_overridable(true);
+
/* Flags */
prop = RNA_def_property(srna, "apply_to_hair_growing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", EFF_WEIGHT_DO_HAIR);
@@ -1362,6 +1368,8 @@ static void rna_def_effector_weight(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3);
RNA_def_property_ui_text(prop, "Fluid Flow", "Fluid Flow effector weight");
RNA_def_property_update(prop, 0, "rna_EffectorWeight_update");
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_field(BlenderRNA *brna)
@@ -1471,6 +1479,8 @@ static void rna_def_field(BlenderRNA *brna)
srna, "Field Settings", "Field settings for an object in physics simulation");
RNA_def_struct_ui_icon(srna, ICON_PHYSICS);
+ RNA_define_lib_overridable(true);
+
/* Enums */
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
@@ -1514,34 +1524,34 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_strength");
- RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 10, 3);
RNA_def_property_ui_text(prop, "Strength", "Strength of force field");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
/* different ui range to above */
prop = RNA_def_property(srna, "linear_drag", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_strength");
- RNA_def_property_range(prop, -2.0f, 2.0f);
+ RNA_def_property_ui_range(prop, -2.0f, 2.0f, 10, 3);
RNA_def_property_ui_text(prop, "Linear Drag", "Drag component proportional to velocity");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
prop = RNA_def_property(srna, "harmonic_damping", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_damp");
- RNA_def_property_range(prop, 0.0f, 10.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 10, 3);
RNA_def_property_ui_text(prop, "Harmonic Damping", "Damping of the harmonic force");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
/* different ui range to above */
prop = RNA_def_property(srna, "quadratic_drag", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_damp");
- RNA_def_property_range(prop, -2.0f, 2.0f);
+ RNA_def_property_ui_range(prop, -2.0f, 2.0f, 10, 3);
RNA_def_property_ui_text(
prop, "Quadratic Drag", "Drag component proportional to the square of velocity");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
prop = RNA_def_property(srna, "flow", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_flow");
- RNA_def_property_range(prop, 0.0f, 10.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 10.0f, 10, 3);
RNA_def_property_ui_text(prop, "Flow", "Convert effector force into air flow velocity");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
@@ -1557,7 +1567,7 @@ static void rna_def_field(BlenderRNA *brna)
/* different ui range to above */
prop = RNA_def_property(srna, "inflow", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_flow");
- RNA_def_property_range(prop, -10.0f, 10.0f);
+ RNA_def_property_ui_range(prop, -10.0f, 10.0f, 10, 3);
RNA_def_property_ui_text(prop, "Inflow", "Inwards component of the vortex force");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
@@ -1570,7 +1580,8 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "rest_length", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_size");
- RNA_def_property_range(prop, 0.0f, 1000.0f);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 10, 3);
RNA_def_property_ui_text(prop, "Rest Length", "Rest length of the harmonic force");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
@@ -1728,7 +1739,7 @@ static void rna_def_field(BlenderRNA *brna)
prop = RNA_def_property(srna, "guide_minimum", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "f_strength");
- RNA_def_property_range(prop, 0.0f, 1000.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 10, 3);
RNA_def_property_ui_text(
prop, "Minimum Distance", "The distance from which particles are affected fully");
RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
@@ -1799,6 +1810,8 @@ static void rna_def_field(BlenderRNA *brna)
/* Variables used for Curve Guide, already wrapped, used for other fields too */
/* falloff_power, use_max_distance, maximum_distance */
+
+ RNA_define_lib_overridable(false);
}
static void rna_def_softbody(BlenderRNA *brna)
@@ -2134,6 +2147,7 @@ static void rna_def_softbody(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "effector_weights");
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
}
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index f732e14d905..fbc7625d815 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -3498,6 +3498,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
/* animation here? */
@@ -3507,12 +3508,14 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "pd");
RNA_def_property_struct_type(prop, "FieldSettings");
RNA_def_property_pointer_funcs(prop, "rna_Particle_field1_get", NULL, NULL, NULL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Force Field 1", "");
prop = RNA_def_property(srna, "force_field_2", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "pd2");
RNA_def_property_struct_type(prop, "FieldSettings");
RNA_def_property_pointer_funcs(prop, "rna_Particle_field2_get", NULL, NULL, NULL);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Force Field 2", "");
/* twist */
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index c0fb904101d..10e28ac3948 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -957,6 +957,7 @@ static void rna_def_rigidbody_world(BlenderRNA *brna)
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
RNA_def_property_ui_text(prop, "Effector Weights", "");
/* Sweep test */
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index d05f2a13c4b..c6c7341bcc6 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -86,8 +86,7 @@ const EnumPropertyItem rna_enum_exr_codec_items[] = {
{R_IMF_EXR_CODEC_B44, "B44", 0, "B44 (lossy)", ""},
{R_IMF_EXR_CODEC_B44A, "B44A", 0, "B44A (lossy)", ""},
{R_IMF_EXR_CODEC_DWAA, "DWAA", 0, "DWAA (lossy)", ""},
- /* NOTE: Commented out for until new OpenEXR is released, see T50673. */
- /* {R_IMF_EXR_CODEC_DWAB, "DWAB", 0, "DWAB (lossy)", ""}, */
+ {R_IMF_EXR_CODEC_DWAB, "DWAB", 0, "DWAB (lossy)", ""},
{0, NULL, 0, NULL, NULL},
};
#endif
@@ -3262,6 +3261,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"Automerge",
"Join by distance last drawn stroke with previous strokes in the active layer");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "gpencil_sculpt", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "gp_sculpt");
@@ -5583,7 +5583,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna)
{FFMPEG_MPEG2, "MPEG2", 0, "MPEG-2", ""},
{FFMPEG_MPEG4, "MPEG4", 0, "MPEG-4", ""},
{FFMPEG_AVI, "AVI", 0, "AVI", ""},
- {FFMPEG_MOV, "QUICKTIME", 0, "Quicktime", ""},
+ {FFMPEG_MOV, "QUICKTIME", 0, "QuickTime", ""},
{FFMPEG_DV, "DV", 0, "DV", ""},
{FFMPEG_OGG, "OGG", 0, "Ogg", ""},
{FFMPEG_MKV, "MKV", 0, "Matroska", ""},
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 5a74cfa9964..f66fb2653b5 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -199,7 +199,7 @@ static void rna_Texture_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *pt
}
else if (GS(id->name) == ID_NT) {
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
- ED_node_tag_update_nodetree(bmain, ntree, NULL);
+ ED_node_tree_propagate_change(NULL, bmain, ntree);
}
}
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index c81588aa8b5..03f4acdae79 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -24,6 +24,7 @@
#include "MEM_guardedalloc.h"
#include "BKE_movieclip.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
#include "RNA_access.h"
@@ -415,11 +416,12 @@ static void rna_tracking_stabRotTracks_active_index_range(
*max = max_ii(0, clip->tracking.stabilization.tot_rot_track - 1);
}
-static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_tracking_flushUpdate(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
MovieClip *clip = (MovieClip *)ptr->owner_id;
- nodeUpdateID(scene->nodetree, &clip->id);
+ BKE_ntree_update_tag_id_changed(bmain, &clip->id);
+ BKE_ntree_update_main(bmain, NULL);
WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
WM_main_add_notifier(NC_SCENE, NULL);
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index f96b3fc5eee..a406e867d6c 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -582,6 +582,43 @@ static void rna_uiTemplateCacheFile(uiLayout *layout,
uiTemplateCacheFile(layout, C, ptr, propname);
}
+static void rna_uiTemplateCacheFileVelocity(uiLayout *layout,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
+ return;
+ }
+
+ uiTemplateCacheFileVelocity(layout, &fileptr);
+}
+
+static void rna_uiTemplateCacheFileProcedural(uiLayout *layout,
+ bContext *C,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
+ return;
+ }
+
+ uiTemplateCacheFileProcedural(layout, C, &fileptr);
+}
+
+static void rna_uiTemplateCacheFileTimeSettings(uiLayout *layout,
+ PointerRNA *ptr,
+ const char *propname)
+{
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) {
+ return;
+ }
+
+ uiTemplateCacheFileTimeSettings(layout, &fileptr);
+}
+
static void rna_uiTemplatePathBuilder(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
@@ -1795,6 +1832,21 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
api_ui_item_rna_common(func);
+ func = RNA_def_function(srna, "template_cache_file_velocity", "rna_uiTemplateCacheFileVelocity");
+ RNA_def_function_ui_description(func, "Show cache files velocity properties");
+ api_ui_item_rna_common(func);
+
+ func = RNA_def_function(
+ srna, "template_cache_file_procedural", "rna_uiTemplateCacheFileProcedural");
+ RNA_def_function_ui_description(func, "Show cache files render procedural properties");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ api_ui_item_rna_common(func);
+
+ func = RNA_def_function(
+ srna, "template_cache_file_time_settings", "rna_uiTemplateCacheFileTimeSettings");
+ RNA_def_function_ui_description(func, "Show cache files time settings");
+ api_ui_item_rna_common(func);
+
func = RNA_def_function(srna, "template_recent_files", "uiTemplateRecentFiles");
RNA_def_function_ui_description(func, "Show list of recently saved .blend files");
RNA_def_int(func, "rows", 5, 1, INT_MAX, "", "Maximum number of items to show", 1, INT_MAX);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index dd1252ffebf..71c38311124 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -182,6 +182,7 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = {
# include "BKE_image.h"
# include "BKE_main.h"
# include "BKE_mesh_runtime.h"
+# include "BKE_object.h"
# include "BKE_paint.h"
# include "BKE_pbvh.h"
# include "BKE_preferences.h"
@@ -578,6 +579,20 @@ static PointerRNA rna_UserDef_apps_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_PreferencesApps, ptr->data);
}
+/* Reevaluate objects with a subsurf modifier as the last in their modifiers stacks. */
+static void rna_UserDef_subdivision_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Object *ob;
+
+ for (ob = bmain->objects.first; ob; ob = ob->id.next) {
+ if (BKE_object_get_last_subsurf_modifier(ob) != NULL) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ }
+
+ rna_userdef_update(bmain, scene, ptr);
+}
+
static void rna_UserDef_audio_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
BKE_sound_init(bmain);
@@ -2889,7 +2904,7 @@ static void rna_def_userdef_theme_space_node(BlenderRNA *brna)
prop = RNA_def_property(srna, "group_node", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "syntaxc");
- RNA_def_property_array(prop, 4);
+ RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Group Node", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
@@ -5651,6 +5666,16 @@ static void rna_def_userdef_system(BlenderRNA *brna)
"Use the depth buffer for picking 3D View selection "
"(without this the front most object may not be selected first)");
+ /* GPU subdivision evaluation. */
+
+ prop = RNA_def_property(srna, "use_gpu_subdivision", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "gpu_flag", USER_GPU_FLAG_SUBDIVISION_EVALUATION);
+ RNA_def_property_ui_text(prop,
+ "GPU Subdivision",
+ "Enable GPU acceleration for evaluating the last subdivision surface "
+ "modifiers in the stack");
+ RNA_def_property_update(prop, 0, "rna_UserDef_subdivision_update");
+
/* Audio */
prop = RNA_def_property(srna, "audio_mixing_buffer", PROP_ENUM, PROP_NONE);
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index c30beaf001a..e5c94c36a13 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -114,7 +114,7 @@ set(SRC
intern/MOD_weightvgedit.c
intern/MOD_weightvgmix.c
intern/MOD_weightvgproximity.c
- intern/MOD_weld.c
+ intern/MOD_weld.cc
intern/MOD_wireframe.c
MOD_modifiertypes.h
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 2f0f11ab56d..fa5149a45ba 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -285,7 +285,8 @@ static void mesh_merge_transform(Mesh *result,
int cap_nloops,
int cap_npolys,
int *remap,
- int remap_len)
+ int remap_len,
+ const bool recalc_normals_later)
{
int *index_orig;
int i;
@@ -305,6 +306,15 @@ static void mesh_merge_transform(Mesh *result,
mul_m4_v3(cap_offset, mv->co);
/* Reset MVert flags for caps */
mv->flag = mv->bweight = 0;
+
+ /* We have to correct normals too, if we do not tag them as dirty later! */
+ if (!recalc_normals_later) {
+ float no[3];
+ normal_short_to_float_v3(no, mv->no);
+ mul_mat3_m4_v3(cap_offset, no);
+ normalize_v3(no);
+ normal_float_to_short_v3(mv->no, no);
+ }
}
/* remap the vertex groups if necessary */
@@ -711,7 +721,8 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
start_cap_nloops,
start_cap_npolys,
vgroup_start_cap_remap,
- vgroup_start_cap_remap_len);
+ vgroup_start_cap_remap_len,
+ use_recalc_normals);
/* Identify doubles with first chunk */
if (use_merge) {
dm_mvert_map_doubles(full_doubles_map,
@@ -740,7 +751,8 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
end_cap_nloops,
end_cap_npolys,
vgroup_end_cap_remap,
- vgroup_end_cap_remap_len);
+ vgroup_end_cap_remap_len,
+ use_recalc_normals);
/* Identify doubles with last chunk */
if (use_merge) {
dm_mvert_map_doubles(full_doubles_map,
diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc
index f452b0c7091..090c4d5512e 100644
--- a/source/blender/modifiers/intern/MOD_mask.cc
+++ b/source/blender/modifiers/intern/MOD_mask.cc
@@ -702,7 +702,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx)
Object *armature_ob = mmd->ob_arm;
/* Return input mesh if there is no armature with bones. */
- if (ELEM(NULL, armature_ob, armature_ob->pose)) {
+ if (ELEM(nullptr, armature_ob, armature_ob->pose)) {
return mesh;
}
diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c
index bcaf294ec8b..00f39e58b4d 100644
--- a/source/blender/modifiers/intern/MOD_meshsequencecache.c
+++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c
@@ -328,14 +328,83 @@ static void panel_draw(const bContext *C, Panel *panel)
uiItemR(layout, ptr, "use_vertex_interpolation", 0, NULL, ICON_NONE);
}
+ modifier_panel_end(layout, ptr);
+}
+
+static void velocity_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
+ return;
+ }
+
+ if (RNA_pointer_is_null(&fileptr)) {
+ return;
+ }
+
+ uiLayoutSetPropSep(layout, true);
+ uiTemplateCacheFileVelocity(layout, &fileptr);
uiItemR(layout, ptr, "velocity_scale", 0, NULL, ICON_NONE);
+}
- modifier_panel_end(layout, ptr);
+static void time_panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
+ return;
+ }
+
+ if (RNA_pointer_is_null(&fileptr)) {
+ return;
+ }
+
+ uiLayoutSetPropSep(layout, true);
+ uiTemplateCacheFileTimeSettings(layout, &fileptr);
+}
+
+static void render_procedural_panel_draw(const bContext *C, Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ PointerRNA fileptr;
+ if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) {
+ return;
+ }
+
+ if (RNA_pointer_is_null(&fileptr)) {
+ return;
+ }
+
+ uiLayoutSetPropSep(layout, true);
+ uiTemplateCacheFileProcedural(layout, C, &fileptr);
}
static void panelRegister(ARegionType *region_type)
{
- modifier_panel_register(region_type, eModifierType_MeshSequenceCache, panel_draw);
+ 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,
+ "render_procedural",
+ "Render Procedural",
+ NULL,
+ render_procedural_panel_draw,
+ panel_type);
+ modifier_subpanel_register(
+ region_type, "velocity", "Velocity", NULL, velocity_panel_draw, panel_type);
}
static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md)
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
index ec6cbeb43bf..cee5d0be65d 100644
--- a/source/blender/modifiers/intern/MOD_nodes.cc
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -60,6 +60,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
+#include "BKE_node_tree_update.h"
#include "BKE_object.h"
#include "BKE_pointcloud.h"
#include "BKE_screen.h"
@@ -237,7 +238,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
DEG_add_modifier_to_transform_relation(ctx->node, "Nodes Modifier");
if (nmd->node_group != nullptr) {
- DEG_add_node_tree_relation(ctx->node, nmd->node_group, "Nodes Modifier");
+ DEG_add_node_tree_output_relation(ctx->node, nmd->node_group, "Nodes Modifier");
Set<ID *> used_ids;
find_used_ids_from_settings(nmd->settings, used_ids);
@@ -725,7 +726,7 @@ void MOD_nodes_init(Main *bmain, NodesModifierData *nmd)
group_input_node,
(bNodeSocket *)group_input_node->outputs.first);
- ntreeUpdateTree(bmain, ntree);
+ BKE_ntree_update_main_tree(bmain, ntree, nullptr);
}
static void initialize_group_input(NodesModifierData &nmd,
@@ -1294,7 +1295,7 @@ static void add_attribute_search_button(const bContext &C,
return;
}
- AttributeSearchData *data = OBJECT_GUARDED_NEW(AttributeSearchData);
+ AttributeSearchData *data = MEM_new<AttributeSearchData>(__func__);
data->object_session_uid = object->id.session_uuid;
STRNCPY(data->modifier_name, nmd.modifier.name);
STRNCPY(data->socket_identifier, socket.identifier);
diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
index 4e808120f4a..6b79c9e0f68 100644
--- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
+++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc
@@ -66,31 +66,55 @@ struct SingleInputValue {
void *value = nullptr;
};
-struct MultiInputValueItem {
+struct MultiInputValue {
/**
- * The socket where this value is coming from. This is required to sort the inputs correctly
- * based on the link order later on.
+ * Ordered sockets connected to this multi-input.
*/
- DSocket origin;
+ Vector<DSocket> origins;
/**
- * Should only be null directly after construction. After that it should always point to a value
- * of the correct type.
+ * A value for every origin socket. The order is determined by #origins.
+ * Note, the same origin can occur multiple times. However, it is guaranteed that values coming
+ * from the same origin have the same value (the pointer is different, but they point to values
+ * that would compare equal).
*/
- void *value = nullptr;
-};
-
-struct MultiInputValue {
+ Vector<void *> values;
/**
- * Collection of all the inputs that have been provided already. Note, the same origin can occur
- * multiple times. However, it is guaranteed that if two items have the same origin, they will
- * also have the same value (the pointer is different, but they point to values that would
- * compare equal).
+ * Number of non-null values.
*/
- Vector<MultiInputValueItem> items;
- /**
- * Number of items that need to be added until all inputs have been provided.
- */
- int expected_size = 0;
+ int provided_value_count = 0;
+
+ bool all_values_available() const
+ {
+ return this->missing_values() == 0;
+ }
+
+ int missing_values() const
+ {
+ return this->values.size() - this->provided_value_count;
+ }
+
+ void add_value(const DSocket origin, void *value)
+ {
+ const int index = this->find_available_index(origin);
+ this->values[index] = value;
+ this->provided_value_count++;
+ }
+
+ private:
+ int find_available_index(DSocket origin) const
+ {
+ for (const int i : origins.index_range()) {
+ if (values[i] != nullptr) {
+ continue;
+ }
+ if (origins[i] != origin) {
+ continue;
+ }
+ return i;
+ }
+ BLI_assert_unreachable();
+ return -1;
+ }
};
struct InputState {
@@ -211,9 +235,10 @@ struct NodeState {
MutableSpan<OutputState> outputs;
/**
- * Nodes that don't support laziness have some special handling the first time they are executed.
+ * Most nodes have inputs that are always required. Those have special handling to avoid an extra
+ * call to the node execution function.
*/
- bool non_lazy_node_is_initialized = false;
+ bool non_lazy_inputs_handled = false;
/**
* Used to check that nodes that don't support laziness do not run more than once.
@@ -556,13 +581,14 @@ class GeometryNodesEvaluator {
/* Construct the correct struct that can hold the input(s). */
if (socket->is_multi_input_socket()) {
input_state.value.multi = allocator.construct<MultiInputValue>().release();
+ MultiInputValue &multi_value = *input_state.value.multi;
/* Count how many values should be added until the socket is complete. */
- socket.foreach_origin_socket(
- [&](DSocket UNUSED(origin)) { input_state.value.multi->expected_size++; });
+ socket.foreach_origin_socket([&](DSocket origin) { multi_value.origins.append(origin); });
/* If no links are connected, we do read the value from socket itself. */
- if (input_state.value.multi->expected_size == 0) {
- input_state.value.multi->expected_size = 1;
+ if (multi_value.origins.is_empty()) {
+ multi_value.origins.append(socket);
}
+ multi_value.values.resize(multi_value.origins.size(), nullptr);
}
else {
input_state.value.single = allocator.construct<SingleInputValue>().release();
@@ -623,8 +649,10 @@ class GeometryNodesEvaluator {
const InputSocketRef &socket_ref = node->input(i);
if (socket_ref.is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- for (MultiInputValueItem &item : multi_value.items) {
- input_state.type->destruct(item.value);
+ for (void *value : multi_value.values) {
+ if (value != nullptr) {
+ input_state.type->destruct(value);
+ }
}
multi_value.~MultiInputValue();
}
@@ -774,12 +802,12 @@ class GeometryNodesEvaluator {
if (!this->prepare_node_outputs_for_execution(locked_node)) {
return;
}
- /* Initialize nodes that don't support laziness. This is done after at least one output is
+ /* Initialize inputs that don't support laziness. This is done after at least one output is
* required and before we check that all required inputs are provided. This reduces the
* number of "round-trips" through the task pool by one for most nodes. */
- if (!node_state.non_lazy_node_is_initialized && !node_supports_laziness(node)) {
- this->initialize_non_lazy_node(locked_node);
- node_state.non_lazy_node_is_initialized = true;
+ if (!node_state.non_lazy_inputs_handled) {
+ this->require_non_lazy_inputs(locked_node);
+ node_state.non_lazy_inputs_handled = true;
}
/* Prepare inputs and check if all required inputs are provided. */
if (!this->prepare_node_inputs_for_execution(locked_node)) {
@@ -853,17 +881,27 @@ class GeometryNodesEvaluator {
return execution_is_necessary;
}
- void initialize_non_lazy_node(LockedNode &locked_node)
+ void require_non_lazy_inputs(LockedNode &locked_node)
{
+ this->foreach_non_lazy_input(locked_node, [&](const DInputSocket socket) {
+ this->set_input_required(locked_node, socket);
+ });
+ }
+
+ void foreach_non_lazy_input(LockedNode &locked_node, FunctionRef<void(DInputSocket socket)> fn)
+ {
+ if (node_supports_laziness(locked_node.node)) {
+ /* In the future only some of the inputs may support lazyness. */
+ return;
+ }
+ /* Nodes that don't support laziness require all inputs. */
for (const int i : locked_node.node->inputs().index_range()) {
InputState &input_state = locked_node.node_state.inputs[i];
if (input_state.type == nullptr) {
/* Ignore unavailable/non-data sockets. */
continue;
}
- /* Nodes that don't support laziness require all inputs. */
- const DInputSocket input_socket = locked_node.node.input(i);
- this->set_input_required(locked_node, input_socket);
+ fn(locked_node.node.input(i));
}
}
@@ -892,7 +930,7 @@ class GeometryNodesEvaluator {
if (socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
/* Checks if all the linked sockets have been provided already. */
- if (multi_value.items.size() == multi_value.expected_size) {
+ if (multi_value.all_values_available()) {
input_state.was_ready_for_execution = true;
}
else if (is_required) {
@@ -1243,7 +1281,7 @@ class GeometryNodesEvaluator {
int missing_values = 0;
if (input_socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- missing_values = multi_value.expected_size - multi_value.items.size();
+ missing_values = multi_value.missing_values();
}
else {
SingleInputValue &single_value = *input_state.value.single;
@@ -1501,10 +1539,10 @@ class GeometryNodesEvaluator {
if (socket->is_multi_input_socket()) {
/* Add a new value to the multi-input. */
MultiInputValue &multi_value = *input_state.value.multi;
- multi_value.items.append({origin, value.get()});
+ multi_value.add_value(origin, value.get());
- if (multi_value.expected_size == multi_value.items.size()) {
- this->log_socket_value({socket}, input_state, multi_value.items);
+ if (multi_value.all_values_available()) {
+ this->log_socket_value({socket}, input_state, multi_value.values);
}
}
else {
@@ -1543,9 +1581,9 @@ class GeometryNodesEvaluator {
GMutablePointer value = this->get_value_from_socket(origin_socket, *input_state.type);
if (input_socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- multi_value.items.append({origin_socket, value.get()});
- if (multi_value.expected_size == multi_value.items.size()) {
- this->log_socket_value({input_socket}, input_state, multi_value.items);
+ multi_value.add_value(origin_socket, value.get());
+ if (multi_value.all_values_available()) {
+ this->log_socket_value({input_socket}, input_state, multi_value.values);
}
}
else {
@@ -1568,10 +1606,13 @@ class GeometryNodesEvaluator {
InputState &input_state = locked_node.node_state.inputs[socket->index()];
if (socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- for (MultiInputValueItem &item : multi_value.items) {
- input_state.type->destruct(item.value);
+ for (void *&value : multi_value.values) {
+ if (value != nullptr) {
+ input_state.type->destruct(value);
+ value = nullptr;
+ }
}
- multi_value.items.clear();
+ multi_value.provided_value_count = 0;
}
else {
SingleInputValue &single_value = *input_state.value.single;
@@ -1653,7 +1694,7 @@ class GeometryNodesEvaluator {
return *node_states_.lookup_key_as(node).state;
}
- void log_socket_value(DSocket socket, InputState &input_state, Span<MultiInputValueItem> values)
+ void log_socket_value(DSocket socket, InputState &input_state, Span<void *> values)
{
if (params_.geo_logger == nullptr) {
return;
@@ -1662,8 +1703,8 @@ class GeometryNodesEvaluator {
Vector<GPointer, 16> value_pointers;
value_pointers.reserve(values.size());
const CPPType &type = *input_state.type;
- for (const MultiInputValueItem &item : values) {
- value_pointers.append({type, item.value});
+ for (const void *value : values) {
+ value_pointers.append({type, value});
}
params_.geo_logger->local().log_multi_value_socket(socket, value_pointers);
}
@@ -1749,7 +1790,7 @@ bool NodeParamsProvider::can_get_input(StringRef identifier) const
if (socket->is_multi_input_socket()) {
MultiInputValue &multi_value = *input_state.value.multi;
- return multi_value.items.size() == multi_value.expected_size;
+ return multi_value.all_values_available();
}
SingleInputValue &single_value = *input_state.value.single;
return single_value.value != nullptr;
@@ -1789,25 +1830,11 @@ Vector<GMutablePointer> NodeParamsProvider::extract_multi_input(StringRef identi
MultiInputValue &multi_value = *input_state.value.multi;
Vector<GMutablePointer> ret_values;
- socket.foreach_origin_socket([&](DSocket origin) {
- for (MultiInputValueItem &item : multi_value.items) {
- if (item.origin == origin && item.value != nullptr) {
- ret_values.append({*input_state.type, item.value});
- /* Make sure we do not use the same value again if two values have the same origin. */
- item.value = nullptr;
- return;
- }
- }
- BLI_assert_unreachable();
- });
- if (ret_values.is_empty()) {
- /* If the socket is not linked, we just use the value from the socket itself. */
- BLI_assert(multi_value.items.size() == 1);
- MultiInputValueItem &item = multi_value.items[0];
- BLI_assert(item.origin == socket);
- ret_values.append({*input_state.type, item.value});
- }
- multi_value.items.clear();
+ for (void *&value : multi_value.values) {
+ BLI_assert(value != nullptr);
+ ret_values.append({*input_state.type, value});
+ value = nullptr;
+ }
return ret_values;
}
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 7470f2abb15..00870d076ef 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -39,6 +39,7 @@
#include "DNA_screen_types.h"
#include "BKE_context.h"
+#include "BKE_editmesh.h"
#include "BKE_mesh.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
@@ -46,6 +47,7 @@
#include "BKE_subdiv_ccg.h"
#include "BKE_subdiv_deform.h"
#include "BKE_subdiv_mesh.h"
+#include "BKE_subdiv_modifier.h"
#include "BKE_subsurf.h"
#include "UI_interface.h"
@@ -65,11 +67,6 @@
#include "intern/CCGSubSurf.h"
-typedef struct SubsurfRuntimeData {
- /* Cached subdivision surface descriptor, with topology and settings. */
- struct Subdiv *subdiv;
-} SubsurfRuntimeData;
-
static void initData(ModifierData *md)
{
SubsurfModifierData *smd = (SubsurfModifierData *)md;
@@ -155,37 +152,6 @@ static int subdiv_levels_for_modifier_get(const SubsurfModifierData *smd,
return get_render_subsurf_level(&scene->r, requested_levels, use_render_params);
}
-static void subdiv_settings_init(SubdivSettings *settings,
- const SubsurfModifierData *smd,
- const ModifierEvalContext *ctx)
-{
- const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER);
- const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels;
-
- settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
- settings->is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision);
- settings->level = settings->is_simple ?
- 1 :
- (settings->is_adaptive ? smd->quality : requested_levels);
- settings->use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease);
- settings->vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
- smd->boundary_smooth);
- settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
- smd->uv_smooth);
-}
-
-/* Main goal of this function is to give usable subdivision surface descriptor
- * which matches settings and topology. */
-static Subdiv *subdiv_descriptor_ensure(SubsurfModifierData *smd,
- const SubdivSettings *subdiv_settings,
- const Mesh *mesh)
-{
- SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
- Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_settings, mesh);
- runtime_data->subdiv = subdiv;
- return subdiv;
-}
-
/* Subdivide into fully qualified mesh. */
static void subdiv_mesh_settings_init(SubdivToMeshSettings *settings,
@@ -240,14 +206,17 @@ static Mesh *subdiv_as_ccg(SubsurfModifierData *smd,
return result;
}
-static SubsurfRuntimeData *subsurf_ensure_runtime(SubsurfModifierData *smd)
+/* Cache settings for lazy CPU evaluation. */
+
+static void subdiv_cache_cpu_evaluation_settings(const ModifierEvalContext *ctx,
+ Mesh *me,
+ SubsurfModifierData *smd)
{
- SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
- if (runtime_data == NULL) {
- runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
- smd->modifier.runtime = runtime_data;
- }
- return runtime_data;
+ SubdivToMeshSettings mesh_settings;
+ subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
+ me->runtime.subsurf_apply_render = (ctx->flag & MOD_APPLY_RENDER) != 0;
+ me->runtime.subsurf_resolution = mesh_settings.resolution;
+ me->runtime.subsurf_use_optimal_display = mesh_settings.use_optimal_display;
}
/* Modifier itself. */
@@ -261,12 +230,30 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
#endif
SubsurfModifierData *smd = (SubsurfModifierData *)md;
SubdivSettings subdiv_settings;
- subdiv_settings_init(&subdiv_settings, smd, ctx);
+ BKE_subsurf_modifier_subdiv_settings_init(
+ &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
if (subdiv_settings.level == 0) {
return result;
}
- SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd);
- Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh);
+ SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
+
+ /* Delay evaluation to the draw code if possible, provided we do not have to apply the modifier.
+ */
+ if ((ctx->flag & MOD_APPLY_TO_BASE_MESH) == 0) {
+ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ const bool is_render_mode = (ctx->flag & MOD_APPLY_RENDER) != 0;
+ /* Same check as in `DRW_mesh_batch_cache_create_requested` to keep both code coherent. */
+ const bool is_editmode = (mesh->edit_mesh != NULL) &&
+ (mesh->edit_mesh->mesh_eval_final != NULL);
+ const int required_mode = BKE_subsurf_modifier_eval_required_mode(is_render_mode, is_editmode);
+ if (BKE_subsurf_modifier_can_do_gpu_subdiv_ex(scene, ctx->object, smd, required_mode, false)) {
+ subdiv_cache_cpu_evaluation_settings(ctx, mesh, smd);
+ return result;
+ }
+ }
+
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
+ smd, &subdiv_settings, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return result;
@@ -320,12 +307,14 @@ static void deformMatrices(ModifierData *md,
SubsurfModifierData *smd = (SubsurfModifierData *)md;
SubdivSettings subdiv_settings;
- subdiv_settings_init(&subdiv_settings, smd, ctx);
+ BKE_subsurf_modifier_subdiv_settings_init(
+ &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0);
if (subdiv_settings.level == 0) {
return;
}
- SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd);
- Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh);
+ SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd);
+ Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
+ smd, &subdiv_settings, mesh, false);
if (subdiv == NULL) {
/* Happens on bad topology, but also on empty input mesh. */
return;
diff --git a/source/blender/modifiers/intern/MOD_volume_displace.cc b/source/blender/modifiers/intern/MOD_volume_displace.cc
index fcf75040a9a..a1ca29f454c 100644
--- a/source/blender/modifiers/intern/MOD_volume_displace.cc
+++ b/source/blender/modifiers/intern/MOD_volume_displace.cc
@@ -203,9 +203,10 @@ struct DisplaceGridOp {
template<typename GridType> void operator()()
{
- if constexpr (std::is_same_v<GridType, openvdb::points::PointDataGrid> ||
- std::is_same_v<GridType, openvdb::StringGrid> ||
- std::is_same_v<GridType, openvdb::MaskGrid>) {
+ if constexpr (blender::is_same_any_v<GridType,
+ openvdb::points::PointDataGrid,
+ openvdb::StringGrid,
+ openvdb::MaskGrid>) {
/* We don't support displacing these grid types yet. */
return;
}
diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.cc
index f842bef3298..92207e1fbe6 100644
--- a/source/blender/modifiers/intern/MOD_weld.c
+++ b/source/blender/modifiers/intern/MOD_weld.cc
@@ -31,14 +31,19 @@
//#define USE_WELD_NORMALS
//#define USE_BVHTREEKDOP
+#include <algorithm>
+
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
-#include "BLI_alloca.h"
+#include "BLI_array.hh"
#include "BLI_bitmap.h"
+#include "BLI_index_range.hh"
#include "BLI_kdtree.h"
#include "BLI_math.h"
+#include "BLI_span.hh"
+#include "BLI_vector.hh"
#include "BLT_translation.h"
@@ -69,127 +74,133 @@
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
+using blender::Array;
+using blender::IndexRange;
+using blender::MutableSpan;
+using blender::Span;
+using blender::Vector;
+
/* Indicates when the element was not computed. */
-#define OUT_OF_CONTEXT (uint)(-1)
+#define OUT_OF_CONTEXT (int)(-1)
/* Indicates if the edge or face will be collapsed. */
-#define ELEM_COLLAPSED (uint)(-2)
+#define ELEM_COLLAPSED (int)(-2)
/* indicates whether an edge or vertex in groups_map will be merged. */
-#define ELEM_MERGED (uint)(-2)
+#define ELEM_MERGED (int)(-2)
/* Used to indicate a range in an array specifying a group. */
struct WeldGroup {
- uint len;
- uint ofs;
+ int len;
+ int ofs;
};
/* Edge groups that will be merged. Final vertices are also indicated. */
struct WeldGroupEdge {
struct WeldGroup group;
- uint v1;
- uint v2;
+ int v1;
+ int v2;
};
-typedef struct WeldVert {
+struct WeldVert {
/* Indexes relative to the original Mesh. */
- uint vert_dest;
- uint vert_orig;
-} WeldVert;
+ int vert_dest;
+ int vert_orig;
+};
-typedef struct WeldEdge {
+struct WeldEdge {
union {
- uint flag;
+ int flag;
struct {
/* Indexes relative to the original Mesh. */
- uint edge_dest;
- uint edge_orig;
- uint vert_a;
- uint vert_b;
+ int edge_dest;
+ int edge_orig;
+ int vert_a;
+ int vert_b;
};
};
-} WeldEdge;
+};
-typedef struct WeldLoop {
+struct WeldLoop {
union {
- uint flag;
+ int flag;
struct {
/* Indexes relative to the original Mesh. */
- uint vert;
- uint edge;
- uint loop_orig;
- uint loop_skip_to;
+ int vert;
+ int edge;
+ int loop_orig;
+ int loop_skip_to;
};
};
-} WeldLoop;
+};
-typedef struct WeldPoly {
+struct WeldPoly {
union {
- uint flag;
+ int flag;
struct {
/* Indexes relative to the original Mesh. */
- uint poly_dst;
- uint poly_orig;
- uint loop_start;
- uint loop_end;
+ int poly_dst;
+ int poly_orig;
+ int loop_start;
+ int loop_end;
/* Final Polygon Size. */
- uint len;
+ int len;
/* Group of loops that will be affected. */
struct WeldGroup loops;
};
};
-} WeldPoly;
+};
-typedef struct WeldMesh {
+struct WeldMesh {
/* Group of vertices to be merged. */
- struct WeldGroup *vert_groups;
- uint *vert_groups_buffer;
+ Array<WeldGroup> vert_groups;
+ Array<int> vert_groups_buffer;
/* Group of edges to be merged. */
- struct WeldGroupEdge *edge_groups;
- uint *edge_groups_buffer;
+ Array<WeldGroupEdge> edge_groups;
+ Array<int> edge_groups_buffer;
/* From the original index of the vertex, this indicates which group it is or is going to be
* merged. */
- uint *edge_groups_map;
+ Array<int> edge_groups_map;
/* References all polygons and loops that will be affected. */
- WeldLoop *wloop;
- WeldPoly *wpoly;
+ Vector<WeldLoop> wloop;
+ Vector<WeldPoly> wpoly;
WeldPoly *wpoly_new;
- uint wloop_len;
- uint wpoly_len;
- uint wpoly_new_len;
+ int wloop_len;
+ int wpoly_len;
+ int wpoly_new_len;
/* From the actual index of the element in the mesh, it indicates what is the index of the Weld
* element above. */
- uint *loop_map;
- uint *poly_map;
+ Array<int> loop_map;
+ Array<int> poly_map;
- uint vert_kill_len;
- uint edge_kill_len;
- uint loop_kill_len;
- uint poly_kill_len; /* Including the new polygons. */
+ int vert_kill_len;
+ int edge_kill_len;
+ int loop_kill_len;
+ int poly_kill_len; /* Including the new polygons. */
/* Size of the affected polygon with more sides. */
- uint max_poly_len;
-} WeldMesh;
-
-typedef struct WeldLoopOfPolyIter {
- uint loop_start;
- uint loop_end;
- const WeldLoop *wloop;
- const MLoop *mloop;
- const uint *loop_map;
+ int max_poly_len;
+};
+
+struct WeldLoopOfPolyIter {
+ int loop_start;
+ int loop_end;
+ Span<WeldLoop> wloop;
+ Span<MLoop> mloop;
+ Span<int> loop_map;
/* Weld group. */
- uint *group;
+ int *group;
- uint l_curr;
- uint l_next;
+ int l_curr;
+ int l_next;
/* Return */
- uint group_len;
- uint v;
- uint e;
+ int group_len;
+ int v;
+ int e;
char type;
-} WeldLoopOfPolyIter;
+};
/* -------------------------------------------------------------------- */
/** \name Debug Utils
@@ -197,22 +208,20 @@ typedef struct WeldLoopOfPolyIter {
#ifdef USE_WELD_DEBUG
static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
- const WeldPoly *wp,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map,
- uint *group_buffer);
+ const WeldPoly &wp,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map,
+ int *group_buffer);
static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter);
-static void weld_assert_edge_kill_len(const WeldEdge *wedge,
- const uint wedge_len,
- const uint supposed_kill_len)
+static void weld_assert_edge_kill_len(Span<WeldEdge> wedge, const int supposed_kill_len)
{
- uint kills = 0;
+ int kills = 0;
const WeldEdge *we = &wedge[0];
- for (uint i = wedge_len; i--; we++) {
- uint edge_dest = we->edge_dest;
+ for (int i = wedge.size(); i--; we++) {
+ int edge_dest = we->edge_dest;
/* Magically includes collapsed edges. */
if (edge_dest != OUT_OF_CONTEXT) {
kills++;
@@ -221,28 +230,25 @@ static void weld_assert_edge_kill_len(const WeldEdge *wedge,
BLI_assert(kills == supposed_kill_len);
}
-static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly,
- const WeldPoly *wpoly_new,
- const uint wpoly_new_len,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map,
- const uint *poly_map,
- const MPoly *mpoly,
- const uint mpoly_len,
- const uint mloop_len,
- const uint supposed_poly_kill_len,
- const uint supposed_loop_kill_len)
+static void weld_assert_poly_and_loop_kill_len(Span<WeldPoly> wpoly,
+ Span<WeldPoly> wpoly_new,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map,
+ Span<int> poly_map,
+ Span<MPoly> mpoly,
+ const int supposed_poly_kill_len,
+ const int supposed_loop_kill_len)
{
- uint poly_kills = 0;
- uint loop_kills = mloop_len;
+ int poly_kills = 0;
+ int loop_kills = mloop.size();
const MPoly *mp = &mpoly[0];
- for (uint i = 0; i < mpoly_len; i++, mp++) {
- uint poly_ctx = poly_map[i];
+ for (int i = 0; i < mpoly.size(); i++, mp++) {
+ int poly_ctx = poly_map[i];
if (poly_ctx != OUT_OF_CONTEXT) {
const WeldPoly *wp = &wpoly[poly_ctx];
WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ if (!weld_iter_loop_of_poly_begin(&iter, *wp, wloop, mloop, loop_map, nullptr)) {
poly_kills++;
continue;
}
@@ -251,11 +257,11 @@ static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly,
poly_kills++;
continue;
}
- uint remain = wp->len;
- uint l = wp->loop_start;
+ int remain = wp->len;
+ int l = wp->loop_start;
while (remain) {
- uint l_next = l + 1;
- uint loop_ctx = loop_map[l];
+ int l_next = l + 1;
+ int loop_ctx = loop_map[l];
if (loop_ctx != OUT_OF_CONTEXT) {
const WeldLoop *wl = &wloop[loop_ctx];
if (wl->loop_skip_to != OUT_OF_CONTEXT) {
@@ -279,17 +285,17 @@ static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly,
}
}
- const WeldPoly *wp = &wpoly_new[0];
- for (uint i = wpoly_new_len; i--; wp++) {
+ const WeldPoly *wp = wpoly_new.data();
+ for (int i = wpoly_new.size(); i--; wp++) {
if (wp->poly_dst != OUT_OF_CONTEXT) {
poly_kills++;
continue;
}
- uint remain = wp->len;
- uint l = wp->loop_start;
+ int remain = wp->len;
+ int l = wp->loop_start;
while (remain) {
- uint l_next = l + 1;
- uint loop_ctx = loop_map[l];
+ int l_next = l + 1;
+ int loop_ctx = loop_map[l];
if (loop_ctx != OUT_OF_CONTEXT) {
const WeldLoop *wl = &wloop[loop_ctx];
if (wl->loop_skip_to != OUT_OF_CONTEXT) {
@@ -312,46 +318,46 @@ static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly,
BLI_assert(loop_kills == supposed_loop_kill_len);
}
-static void weld_assert_poly_no_vert_repetition(const WeldPoly *wp,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map)
+static void weld_assert_poly_no_vert_repetition(const WeldPoly &wp,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map)
{
- const uint len = wp->len;
- uint *verts = BLI_array_alloca(verts, len);
+ const int len = wp.len;
+ Array<int, 64> verts(len);
WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) {
return;
}
else {
- uint i = 0;
+ int i = 0;
while (weld_iter_loop_of_poly_next(&iter)) {
verts[i++] = iter.v;
}
}
- for (uint i = 0; i < len; i++) {
- uint va = verts[i];
- for (uint j = i + 1; j < len; j++) {
- uint vb = verts[j];
+ for (int i = 0; i < len; i++) {
+ int va = verts[i];
+ for (int j = i + 1; j < len; j++) {
+ int vb = verts[j];
BLI_assert(va != vb);
}
}
}
-static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop)
+static void weld_assert_poly_len(const WeldPoly *wp, const Span<WeldLoop> wloop)
{
if (wp->flag == ELEM_COLLAPSED) {
return;
}
- uint len = wp->len;
+ int len = wp->len;
const WeldLoop *wl = &wloop[wp->loops.ofs];
BLI_assert(wp->loop_start <= wl->loop_orig);
- uint end_wloop = wp->loops.ofs + wp->loops.len;
+ int end_wloop = wp->loops.ofs + wp->loops.len;
const WeldLoop *wl_end = &wloop[end_wloop - 1];
- uint min_len = 0;
+ int min_len = 0;
for (; wl <= wl_end; wl++) {
BLI_assert(wl->loop_skip_to == OUT_OF_CONTEXT); /* Not for this case. */
if (wl->flag != ELEM_COLLAPSED) {
@@ -360,7 +366,7 @@ static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop)
}
BLI_assert(len >= min_len);
- uint max_len = wp->loop_end - wp->loop_start + 1;
+ int max_len = wp->loop_end - wp->loop_start + 1;
BLI_assert(len <= max_len);
}
@@ -372,92 +378,71 @@ static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop)
/** \name Weld Vert API
* \{ */
-static void weld_vert_ctx_alloc_and_setup(const uint mvert_len,
- uint *r_vert_dest_map,
- WeldVert **r_wvert,
- uint *r_wvert_len)
+static Vector<WeldVert> weld_vert_ctx_alloc_and_setup(Span<int> vert_dest_map,
+ const int vert_kill_len)
{
- /* Vert Context. */
- uint wvert_len = 0;
-
- WeldVert *wvert, *wv;
- wvert = MEM_mallocN(sizeof(*wvert) * mvert_len, __func__);
- wv = &wvert[0];
-
- uint *v_dest_iter = &r_vert_dest_map[0];
- for (uint i = 0; i < mvert_len; i++, v_dest_iter++) {
- if (*v_dest_iter != OUT_OF_CONTEXT) {
- wv->vert_dest = *v_dest_iter;
- wv->vert_orig = i;
- wv++;
- wvert_len++;
+ Vector<WeldVert> wvert;
+ wvert.reserve(std::min<int>(2 * vert_kill_len, vert_dest_map.size()));
+
+ for (const int i : vert_dest_map.index_range()) {
+ if (vert_dest_map[i] != OUT_OF_CONTEXT) {
+ wvert.append({vert_dest_map[i], i});
}
}
-
- *r_wvert = MEM_reallocN(wvert, sizeof(*wvert) * wvert_len);
- *r_wvert_len = wvert_len;
+ return wvert;
}
-static void weld_vert_groups_setup(const uint mvert_len,
- const uint wvert_len,
- const WeldVert *wvert,
- const uint *vert_dest_map,
- uint *r_vert_groups_map,
- uint **r_vert_groups_buffer,
- struct WeldGroup **r_vert_groups)
+static void weld_vert_groups_setup(Span<WeldVert> wvert,
+ Span<int> vert_dest_map,
+ MutableSpan<int> r_vert_groups_map,
+ Array<int> &r_vert_groups_buffer,
+ Array<WeldGroup> &r_vert_groups)
{
/* Get weld vert groups. */
- uint wgroups_len = 0;
- const uint *vert_dest_iter = &vert_dest_map[0];
- uint *group_map_iter = &r_vert_groups_map[0];
- for (uint i = 0; i < mvert_len; i++, group_map_iter++, vert_dest_iter++) {
- uint vert_dest = *vert_dest_iter;
+ int wgroups_len = 0;
+ for (const int i : vert_dest_map.index_range()) {
+ const int vert_dest = vert_dest_map[i];
if (vert_dest != OUT_OF_CONTEXT) {
if (vert_dest != i) {
- *group_map_iter = ELEM_MERGED;
+ r_vert_groups_map[i] = ELEM_MERGED;
}
else {
- *group_map_iter = wgroups_len;
+ r_vert_groups_map[i] = wgroups_len;
wgroups_len++;
}
}
else {
- *group_map_iter = OUT_OF_CONTEXT;
+ r_vert_groups_map[i] = OUT_OF_CONTEXT;
}
}
- struct WeldGroup *wgroups = MEM_callocN(sizeof(*wgroups) * wgroups_len, __func__);
+ r_vert_groups.reinitialize(wgroups_len);
+ r_vert_groups.fill({0, 0});
+ MutableSpan<WeldGroup> wgroups = r_vert_groups;
- const WeldVert *wv = &wvert[0];
- for (uint i = wvert_len; i--; wv++) {
- uint group_index = r_vert_groups_map[wv->vert_dest];
+ for (const WeldVert &wv : wvert) {
+ int group_index = r_vert_groups_map[wv.vert_dest];
wgroups[group_index].len++;
}
- uint ofs = 0;
- struct WeldGroup *wg_iter = &wgroups[0];
- for (uint i = wgroups_len; i--; wg_iter++) {
- wg_iter->ofs = ofs;
- ofs += wg_iter->len;
+ int ofs = 0;
+ for (WeldGroup &wg : wgroups) {
+ wg.ofs = ofs;
+ ofs += wg.len;
}
- BLI_assert(ofs == wvert_len);
+ BLI_assert(ofs == wvert.size());
- uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
- wv = &wvert[0];
- for (uint i = wvert_len; i--; wv++) {
- uint group_index = r_vert_groups_map[wv->vert_dest];
- groups_buffer[wgroups[group_index].ofs++] = wv->vert_orig;
+ r_vert_groups_buffer.reinitialize(ofs);
+ for (const WeldVert &wv : wvert) {
+ int group_index = r_vert_groups_map[wv.vert_dest];
+ r_vert_groups_buffer[wgroups[group_index].ofs++] = wv.vert_orig;
}
- wg_iter = &wgroups[0];
- for (uint i = wgroups_len; i--; wg_iter++) {
- wg_iter->ofs -= wg_iter->len;
+ for (WeldGroup &wg : wgroups) {
+ wg.ofs -= wg.len;
}
-
- *r_vert_groups = wgroups;
- *r_vert_groups_buffer = groups_buffer;
}
/** \} */
@@ -466,31 +451,24 @@ static void weld_vert_groups_setup(const uint mvert_len,
/** \name Weld Edge API
* \{ */
-static void weld_edge_ctx_setup(const uint mvert_len,
- const uint wedge_len,
- struct WeldGroup *r_vlinks,
- uint *r_edge_dest_map,
- WeldEdge *r_wedge,
- uint *r_edge_kiil_len)
+static void weld_edge_ctx_setup(MutableSpan<WeldGroup> r_vlinks,
+ MutableSpan<int> r_edge_dest_map,
+ MutableSpan<WeldEdge> r_wedge,
+ int *r_edge_kiil_len)
{
- WeldEdge *we;
-
/* Setup Edge Overlap. */
- uint edge_kill_len = 0;
+ int edge_kill_len = 0;
- struct WeldGroup *vl_iter, *v_links;
- v_links = r_vlinks;
- vl_iter = &v_links[0];
+ MutableSpan<WeldGroup> v_links = r_vlinks;
- we = &r_wedge[0];
- for (uint i = wedge_len; i--; we++) {
- uint dst_vert_a = we->vert_a;
- uint dst_vert_b = we->vert_b;
+ for (WeldEdge &we : r_wedge) {
+ int dst_vert_a = we.vert_a;
+ int dst_vert_b = we.vert_b;
if (dst_vert_a == dst_vert_b) {
- BLI_assert(we->edge_dest == OUT_OF_CONTEXT);
- r_edge_dest_map[we->edge_orig] = ELEM_COLLAPSED;
- we->flag = ELEM_COLLAPSED;
+ BLI_assert(we.edge_dest == OUT_OF_CONTEXT);
+ r_edge_dest_map[we.edge_orig] = ELEM_COLLAPSED;
+ we.flag = ELEM_COLLAPSED;
edge_kill_len++;
continue;
}
@@ -499,62 +477,60 @@ static void weld_edge_ctx_setup(const uint mvert_len,
v_links[dst_vert_b].len++;
}
- uint link_len = 0;
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
- vl_iter->ofs = link_len;
- link_len += vl_iter->len;
+ int link_len = 0;
+ for (WeldGroup &vl : r_vlinks) {
+ vl.ofs = link_len;
+ link_len += vl.len;
}
- if (link_len) {
- uint *link_edge_buffer = MEM_mallocN(sizeof(*link_edge_buffer) * link_len, __func__);
+ if (link_len > 0) {
+ Array<int> link_edge_buffer(link_len);
- we = &r_wedge[0];
- for (uint i = 0; i < wedge_len; i++, we++) {
- if (we->flag == ELEM_COLLAPSED) {
+ for (const int i : r_wedge.index_range()) {
+ const WeldEdge &we = r_wedge[i];
+ if (we.flag == ELEM_COLLAPSED) {
continue;
}
- uint dst_vert_a = we->vert_a;
- uint dst_vert_b = we->vert_b;
+ int dst_vert_a = we.vert_a;
+ int dst_vert_b = we.vert_b;
link_edge_buffer[v_links[dst_vert_a].ofs++] = i;
link_edge_buffer[v_links[dst_vert_b].ofs++] = i;
}
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
+ for (WeldGroup &vl : r_vlinks) {
/* Fix offset */
- vl_iter->ofs -= vl_iter->len;
+ vl.ofs -= vl.len;
}
- we = &r_wedge[0];
- for (uint i = 0; i < wedge_len; i++, we++) {
- if (we->edge_dest != OUT_OF_CONTEXT) {
+ for (const int i : r_wedge.index_range()) {
+ const WeldEdge &we = r_wedge[i];
+ if (we.edge_dest != OUT_OF_CONTEXT) {
/* No need to retest edges.
* (Already includes collapsed edges). */
continue;
}
- uint dst_vert_a = we->vert_a;
- uint dst_vert_b = we->vert_b;
+ int dst_vert_a = we.vert_a;
+ int dst_vert_b = we.vert_b;
struct WeldGroup *link_a = &v_links[dst_vert_a];
struct WeldGroup *link_b = &v_links[dst_vert_b];
- uint edges_len_a = link_a->len;
- uint edges_len_b = link_b->len;
+ int edges_len_a = link_a->len;
+ int edges_len_b = link_b->len;
if (edges_len_a <= 1 || edges_len_b <= 1) {
continue;
}
- uint *edges_ctx_a = &link_edge_buffer[link_a->ofs];
- uint *edges_ctx_b = &link_edge_buffer[link_b->ofs];
- uint edge_orig = we->edge_orig;
+ int *edges_ctx_a = &link_edge_buffer[link_a->ofs];
+ int *edges_ctx_b = &link_edge_buffer[link_b->ofs];
+ int edge_orig = we.edge_orig;
for (; edges_len_a--; edges_ctx_a++) {
- uint e_ctx_a = *edges_ctx_a;
+ int e_ctx_a = *edges_ctx_a;
if (e_ctx_a == i) {
continue;
}
@@ -565,7 +541,7 @@ static void weld_edge_ctx_setup(const uint mvert_len,
if (edges_len_b == 0) {
break;
}
- uint e_ctx_b = *edges_ctx_b;
+ int e_ctx_b = *edges_ctx_b;
if (e_ctx_a == e_ctx_b) {
WeldEdge *we_b = &r_wedge[e_ctx_b];
BLI_assert(ELEM(we_b->vert_a, dst_vert_a, dst_vert_b));
@@ -580,138 +556,118 @@ static void weld_edge_ctx_setup(const uint mvert_len,
}
#ifdef USE_WELD_DEBUG
- weld_assert_edge_kill_len(r_wedge, wedge_len, edge_kill_len);
+ weld_assert_edge_kill_len(r_wedge, edge_kill_len);
#endif
-
- MEM_freeN(link_edge_buffer);
}
*r_edge_kiil_len = edge_kill_len;
}
-static void weld_edge_ctx_alloc(const MEdge *medge,
- const uint medge_len,
- const uint *vert_dest_map,
- uint *r_edge_dest_map,
- uint **r_edge_ctx_map,
- WeldEdge **r_wedge,
- uint *r_wedge_len)
+static Vector<WeldEdge> weld_edge_ctx_alloc(Span<MEdge> medge,
+ Span<int> vert_dest_map,
+ MutableSpan<int> r_edge_dest_map,
+ MutableSpan<int> r_edge_ctx_map)
{
/* Edge Context. */
- uint *edge_map = MEM_mallocN(sizeof(*edge_map) * medge_len, __func__);
- uint wedge_len = 0;
-
- WeldEdge *wedge, *we;
- wedge = MEM_mallocN(sizeof(*wedge) * medge_len, __func__);
- we = &wedge[0];
-
- const MEdge *me = &medge[0];
- uint *e_dest_iter = &r_edge_dest_map[0];
- uint *iter = &edge_map[0];
- for (uint i = 0; i < medge_len; i++, me++, iter++, e_dest_iter++) {
- uint v1 = me->v1;
- uint v2 = me->v2;
- uint v_dest_1 = vert_dest_map[v1];
- uint v_dest_2 = vert_dest_map[v2];
+ int wedge_len = 0;
+
+ Vector<WeldEdge> wedge;
+ wedge.reserve(medge.size());
+
+ for (const int i : medge.index_range()) {
+ int v1 = medge[i].v1;
+ int v2 = medge[i].v2;
+ int v_dest_1 = vert_dest_map[v1];
+ int v_dest_2 = vert_dest_map[v2];
if ((v_dest_1 != OUT_OF_CONTEXT) || (v_dest_2 != OUT_OF_CONTEXT)) {
- we->vert_a = (v_dest_1 != OUT_OF_CONTEXT) ? v_dest_1 : v1;
- we->vert_b = (v_dest_2 != OUT_OF_CONTEXT) ? v_dest_2 : v2;
- we->edge_dest = OUT_OF_CONTEXT;
- we->edge_orig = i;
- we++;
- *e_dest_iter = i;
- *iter = wedge_len++;
+ WeldEdge we{};
+ we.vert_a = (v_dest_1 != OUT_OF_CONTEXT) ? v_dest_1 : v1;
+ we.vert_b = (v_dest_2 != OUT_OF_CONTEXT) ? v_dest_2 : v2;
+ we.edge_dest = OUT_OF_CONTEXT;
+ we.edge_orig = i;
+ wedge.append(we);
+ r_edge_dest_map[i] = i;
+ r_edge_ctx_map[i] = wedge_len++;
}
else {
- *e_dest_iter = OUT_OF_CONTEXT;
- *iter = OUT_OF_CONTEXT;
+ r_edge_dest_map[i] = OUT_OF_CONTEXT;
+ r_edge_ctx_map[i] = OUT_OF_CONTEXT;
}
}
- *r_wedge = MEM_reallocN(wedge, sizeof(*wedge) * wedge_len);
- *r_wedge_len = wedge_len;
- *r_edge_ctx_map = edge_map;
+ return wedge;
}
-static void weld_edge_groups_setup(const uint medge_len,
- const uint edge_kill_len,
- const uint wedge_len,
- WeldEdge *wedge,
- const uint *wedge_map,
- uint *r_edge_groups_map,
- uint **r_edge_groups_buffer,
- struct WeldGroupEdge **r_edge_groups)
+static void weld_edge_groups_setup(const int medge_len,
+ const int edge_kill_len,
+ MutableSpan<WeldEdge> wedge,
+ Span<int> wedge_map,
+ MutableSpan<int> r_edge_groups_map,
+ Array<int> &r_edge_groups_buffer,
+ Array<WeldGroupEdge> &r_edge_groups)
{
-
/* Get weld edge groups. */
- struct WeldGroupEdge *wegroups, *wegrp_iter;
+ struct WeldGroupEdge *wegrp_iter;
- uint wgroups_len = wedge_len - edge_kill_len;
- wegroups = MEM_callocN(sizeof(*wegroups) * wgroups_len, __func__);
- wegrp_iter = &wegroups[0];
+ int wgroups_len = wedge.size() - edge_kill_len;
+ r_edge_groups.reinitialize(wgroups_len);
+ r_edge_groups.fill({0});
+ MutableSpan<WeldGroupEdge> wegroups = r_edge_groups;
+ wegrp_iter = &r_edge_groups[0];
wgroups_len = 0;
- const uint *edge_ctx_iter = &wedge_map[0];
- uint *group_map_iter = &r_edge_groups_map[0];
- for (uint i = medge_len; i--; edge_ctx_iter++, group_map_iter++) {
- uint edge_ctx = *edge_ctx_iter;
+ for (const int i : IndexRange(medge_len)) {
+ int edge_ctx = wedge_map[i];
if (edge_ctx != OUT_OF_CONTEXT) {
WeldEdge *we = &wedge[edge_ctx];
- uint edge_dest = we->edge_dest;
+ int edge_dest = we->edge_dest;
if (edge_dest != OUT_OF_CONTEXT) {
BLI_assert(edge_dest != we->edge_orig);
- *group_map_iter = ELEM_MERGED;
+ r_edge_groups_map[i] = ELEM_MERGED;
}
else {
we->edge_dest = we->edge_orig;
wegrp_iter->v1 = we->vert_a;
wegrp_iter->v2 = we->vert_b;
- *group_map_iter = wgroups_len;
+ r_edge_groups_map[i] = wgroups_len;
wgroups_len++;
wegrp_iter++;
}
}
else {
- *group_map_iter = OUT_OF_CONTEXT;
+ r_edge_groups_map[i] = OUT_OF_CONTEXT;
}
}
- BLI_assert(wgroups_len == wedge_len - edge_kill_len);
+ BLI_assert(wgroups_len == wedge.size() - edge_kill_len);
- WeldEdge *we = &wedge[0];
- for (uint i = wedge_len; i--; we++) {
- if (we->flag == ELEM_COLLAPSED) {
+ for (const WeldEdge &we : wedge) {
+ if (we.flag == ELEM_COLLAPSED) {
continue;
}
- uint group_index = r_edge_groups_map[we->edge_dest];
+ int group_index = r_edge_groups_map[we.edge_dest];
wegroups[group_index].group.len++;
}
- uint ofs = 0;
- wegrp_iter = &wegroups[0];
- for (uint i = wgroups_len; i--; wegrp_iter++) {
- wegrp_iter->group.ofs = ofs;
- ofs += wegrp_iter->group.len;
+ int ofs = 0;
+ for (WeldGroupEdge &wegrp : wegroups) {
+ wegrp.group.ofs = ofs;
+ ofs += wegrp.group.len;
}
- uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__);
- we = &wedge[0];
- for (uint i = wedge_len; i--; we++) {
- if (we->flag == ELEM_COLLAPSED) {
+ r_edge_groups_buffer.reinitialize(ofs);
+ for (const WeldEdge &we : wedge) {
+ if (we.flag == ELEM_COLLAPSED) {
continue;
}
- uint group_index = r_edge_groups_map[we->edge_dest];
- groups_buffer[wegroups[group_index].group.ofs++] = we->edge_orig;
+ int group_index = r_edge_groups_map[we.edge_dest];
+ r_edge_groups_buffer[wegroups[group_index].group.ofs++] = we.edge_orig;
}
- wegrp_iter = &wegroups[0];
- for (uint i = wgroups_len; i--; wegrp_iter++) {
- wegrp_iter->group.ofs -= wegrp_iter->group.len;
+ for (WeldGroupEdge &wegrp : wegroups) {
+ wegrp.group.ofs -= wegrp.group.len;
}
-
- *r_edge_groups_buffer = groups_buffer;
- *r_edge_groups = wegroups;
}
/** \} */
@@ -721,31 +677,31 @@ static void weld_edge_groups_setup(const uint medge_len,
* \{ */
static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
- const WeldPoly *wp,
- const WeldLoop *wloop,
- const MLoop *mloop,
- const uint *loop_map,
- uint *group_buffer)
+ const WeldPoly &wp,
+ Span<WeldLoop> wloop,
+ Span<MLoop> mloop,
+ Span<int> loop_map,
+ int *group_buffer)
{
- if (wp->flag == ELEM_COLLAPSED) {
+ if (wp.flag == ELEM_COLLAPSED) {
return false;
}
- iter->loop_start = wp->loop_start;
- iter->loop_end = wp->loop_end;
+ iter->loop_start = wp.loop_start;
+ iter->loop_end = wp.loop_end;
iter->wloop = wloop;
iter->mloop = mloop;
iter->loop_map = loop_map;
iter->group = group_buffer;
- uint group_len = 0;
+ int group_len = 0;
if (group_buffer) {
/* First loop group needs more attention. */
- uint loop_start, loop_end, l;
+ int loop_start, loop_end, l;
loop_start = iter->loop_start;
loop_end = l = iter->loop_end;
while (l >= loop_start) {
- const uint loop_ctx = loop_map[l];
+ const int loop_ctx = loop_map[l];
if (loop_ctx != OUT_OF_CONTEXT) {
const WeldLoop *wl = &wloop[loop_ctx];
if (wl->flag == ELEM_COLLAPSED) {
@@ -774,10 +730,10 @@ static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter,
static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
{
- uint loop_end = iter->loop_end;
- const WeldLoop *wloop = iter->wloop;
- const uint *loop_map = iter->loop_map;
- uint l = iter->l_curr = iter->l_next;
+ int loop_end = iter->loop_end;
+ Span<WeldLoop> wloop = iter->wloop;
+ Span<int> loop_map = iter->loop_map;
+ int l = iter->l_curr = iter->l_next;
if (l == iter->loop_start) {
/* `grupo_len` is already calculated in the first loop */
}
@@ -785,8 +741,8 @@ static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
iter->group_len = 0;
}
while (l <= loop_end) {
- uint l_next = l + 1;
- const uint loop_ctx = loop_map[l];
+ int l_next = l + 1;
+ const int loop_ctx = loop_map[l];
if (loop_ctx != OUT_OF_CONTEXT) {
const WeldLoop *wl = &wloop[loop_ctx];
if (wl->loop_skip_to != OUT_OF_CONTEXT) {
@@ -809,7 +765,7 @@ static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
else {
const MLoop *ml = &iter->mloop[l];
#ifdef USE_WELD_DEBUG
- BLI_assert(iter->v != ml->v);
+ BLI_assert((uint)iter->v != ml->v);
#endif
iter->v = ml->v;
iter->e = ml->e;
@@ -825,129 +781,119 @@ static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter)
return false;
}
-static void weld_poly_loop_ctx_alloc(const MPoly *mpoly,
- const uint mpoly_len,
- const MLoop *mloop,
- const uint mloop_len,
- const uint *vert_dest_map,
- const uint *edge_dest_map,
+static void weld_poly_loop_ctx_alloc(Span<MPoly> mpoly,
+ Span<MLoop> mloop,
+ Span<int> vert_dest_map,
+ Span<int> edge_dest_map,
WeldMesh *r_weld_mesh)
{
/* Loop/Poly Context. */
- uint *loop_map = MEM_mallocN(sizeof(*loop_map) * mloop_len, __func__);
- uint *poly_map = MEM_mallocN(sizeof(*poly_map) * mpoly_len, __func__);
- uint wloop_len = 0;
- uint wpoly_len = 0;
- uint max_ctx_poly_len = 4;
+ Array<int> loop_map(mloop.size());
+ Array<int> poly_map(mpoly.size());
+ int wloop_len = 0;
+ int wpoly_len = 0;
+ int max_ctx_poly_len = 4;
- WeldLoop *wloop, *wl;
- wloop = MEM_mallocN(sizeof(*wloop) * mloop_len, __func__);
- wl = &wloop[0];
+ Vector<WeldLoop> wloop;
+ wloop.reserve(mloop.size());
- WeldPoly *wpoly, *wp;
- wpoly = MEM_mallocN(sizeof(*wpoly) * mpoly_len, __func__);
- wp = &wpoly[0];
+ Vector<WeldPoly> wpoly;
+ wpoly.reserve(mpoly.size());
- uint maybe_new_poly = 0;
+ int maybe_new_poly = 0;
- const MPoly *mp = &mpoly[0];
- uint *iter = &poly_map[0];
- uint *loop_map_iter = &loop_map[0];
- for (uint i = 0; i < mpoly_len; i++, mp++, iter++) {
- const uint loopstart = mp->loopstart;
- const uint totloop = mp->totloop;
-
- uint vert_ctx_len = 0;
-
- uint l = loopstart;
- uint prev_wloop_len = wloop_len;
- const MLoop *ml = &mloop[l];
- for (uint j = totloop; j--; l++, ml++, loop_map_iter++) {
- uint v = ml->v;
- uint e = ml->e;
- uint v_dest = vert_dest_map[v];
- uint e_dest = edge_dest_map[e];
+ for (const int i : mpoly.index_range()) {
+ const MPoly &mp = mpoly[i];
+ const int loopstart = mp.loopstart;
+ const int totloop = mp.totloop;
+
+ int vert_ctx_len = 0;
+
+ int prev_wloop_len = wloop_len;
+ for (const int i_loop : mloop.index_range().slice(loopstart, totloop)) {
+ int v = mloop[i_loop].v;
+ int e = mloop[i_loop].e;
+ int v_dest = vert_dest_map[v];
+ int e_dest = edge_dest_map[e];
bool is_vert_ctx = v_dest != OUT_OF_CONTEXT;
bool is_edge_ctx = e_dest != OUT_OF_CONTEXT;
if (is_vert_ctx) {
vert_ctx_len++;
}
if (is_vert_ctx || is_edge_ctx) {
- wl->vert = is_vert_ctx ? v_dest : v;
- wl->edge = is_edge_ctx ? e_dest : e;
- wl->loop_orig = l;
- wl->loop_skip_to = OUT_OF_CONTEXT;
- wl++;
-
- *loop_map_iter = wloop_len++;
+ WeldLoop wl{};
+ wl.vert = is_vert_ctx ? v_dest : v;
+ wl.edge = is_edge_ctx ? e_dest : e;
+ wl.loop_orig = i_loop;
+ wl.loop_skip_to = OUT_OF_CONTEXT;
+ wloop.append(wl);
+
+ loop_map[i_loop] = wloop_len++;
}
else {
- *loop_map_iter = OUT_OF_CONTEXT;
+ loop_map[i_loop] = OUT_OF_CONTEXT;
}
}
if (wloop_len != prev_wloop_len) {
- uint loops_len = wloop_len - prev_wloop_len;
-
- wp->poly_dst = OUT_OF_CONTEXT;
- wp->poly_orig = i;
- wp->loops.len = loops_len;
- wp->loops.ofs = prev_wloop_len;
- wp->loop_start = loopstart;
- wp->loop_end = loopstart + totloop - 1;
- wp->len = totloop;
- wp++;
-
- *iter = wpoly_len++;
+ int loops_len = wloop_len - prev_wloop_len;
+ WeldPoly wp{};
+ wp.poly_dst = OUT_OF_CONTEXT;
+ wp.poly_orig = i;
+ wp.loops.len = loops_len;
+ wp.loops.ofs = prev_wloop_len;
+ wp.loop_start = loopstart;
+ wp.loop_end = loopstart + totloop - 1;
+ wp.len = totloop;
+ wpoly.append(wp);
+
+ poly_map[i] = wpoly_len++;
if (totloop > 5 && vert_ctx_len > 1) {
- uint max_new = (totloop / 3) - 1;
+ int max_new = (totloop / 3) - 1;
vert_ctx_len /= 2;
maybe_new_poly += MIN2(max_new, vert_ctx_len);
CLAMP_MIN(max_ctx_poly_len, totloop);
}
}
else {
- *iter = OUT_OF_CONTEXT;
+ poly_map[i] = OUT_OF_CONTEXT;
}
}
- if (mpoly_len < (wpoly_len + maybe_new_poly)) {
- WeldPoly *wpoly_tmp = wpoly;
- wpoly = MEM_mallocN(sizeof(*wpoly) * ((size_t)wpoly_len + maybe_new_poly), __func__);
- memcpy(wpoly, wpoly_tmp, sizeof(*wpoly) * wpoly_len);
- MEM_freeN(wpoly_tmp);
+ if (mpoly.size() < (wpoly_len + maybe_new_poly)) {
+ wpoly.resize(wpoly_len + maybe_new_poly);
}
- WeldPoly *poly_new = &wpoly[wpoly_len];
+ WeldPoly *poly_new = wpoly.data() + wpoly_len;
- r_weld_mesh->wloop = MEM_reallocN(wloop, sizeof(*wloop) * wloop_len);
- r_weld_mesh->wpoly = wpoly;
+ r_weld_mesh->wloop = std::move(wloop);
+ r_weld_mesh->wpoly = std::move(wpoly);
r_weld_mesh->wpoly_new = poly_new;
r_weld_mesh->wloop_len = wloop_len;
r_weld_mesh->wpoly_len = wpoly_len;
r_weld_mesh->wpoly_new_len = 0;
- r_weld_mesh->loop_map = loop_map;
- r_weld_mesh->poly_map = poly_map;
+ r_weld_mesh->loop_map = std::move(loop_map);
+ r_weld_mesh->poly_map = std::move(poly_map);
r_weld_mesh->max_poly_len = max_ctx_poly_len;
}
-static void weld_poly_split_recursive(const uint *vert_dest_map,
+static void weld_poly_split_recursive(Span<int> vert_dest_map,
#ifdef USE_WELD_DEBUG
- const MLoop *mloop,
+ const Span<MLoop> mloop,
#endif
- uint ctx_verts_len,
+ int ctx_verts_len,
WeldPoly *r_wp,
WeldMesh *r_weld_mesh,
- uint *r_poly_kill,
- uint *r_loop_kill)
+ int *r_poly_kill,
+ int *r_loop_kill)
{
- uint poly_len = r_wp->len;
+ int poly_len = r_wp->len;
if (poly_len > 3 && ctx_verts_len > 1) {
- const uint ctx_loops_len = r_wp->loops.len;
- const uint ctx_loops_ofs = r_wp->loops.ofs;
- WeldLoop *wloop = r_weld_mesh->wloop;
+ const int ctx_loops_len = r_wp->loops.len;
+ const int ctx_loops_ofs = r_wp->loops.ofs;
+ MutableSpan<WeldLoop> wloop = r_weld_mesh->wloop;
WeldPoly *wpoly_new = r_weld_mesh->wpoly_new;
- uint loop_kill = 0;
+ int loop_kill = 0;
WeldLoop *poly_loops = &wloop[ctx_loops_ofs];
WeldLoop *wla = &poly_loops[0];
@@ -955,19 +901,19 @@ static void weld_poly_split_recursive(const uint *vert_dest_map,
while (wla_prev->flag == ELEM_COLLAPSED) {
wla_prev--;
}
- const uint la_len = ctx_loops_len - 1;
- for (uint la = 0; la < la_len; la++, wla++) {
+ const int la_len = ctx_loops_len - 1;
+ for (int la = 0; la < la_len; la++, wla++) {
wa_continue:
if (wla->flag == ELEM_COLLAPSED) {
continue;
}
- uint vert_a = wla->vert;
+ int vert_a = wla->vert;
/* Only test vertices that will be merged. */
if (vert_dest_map[vert_a] != OUT_OF_CONTEXT) {
- uint lb = la + 1;
+ int lb = la + 1;
WeldLoop *wlb = wla + 1;
WeldLoop *wlb_prev = wla;
- uint killed_ab = 0;
+ int killed_ab = 0;
ctx_verts_len = 1;
for (; lb < ctx_loops_len; lb++, wlb++) {
BLI_assert(wlb->loop_skip_to == OUT_OF_CONTEXT);
@@ -975,13 +921,13 @@ static void weld_poly_split_recursive(const uint *vert_dest_map,
killed_ab++;
continue;
}
- uint vert_b = wlb->vert;
+ int vert_b = wlb->vert;
if (vert_dest_map[vert_b] != OUT_OF_CONTEXT) {
ctx_verts_len++;
}
if (vert_a == vert_b) {
- const uint dist_a = wlb->loop_orig - wla->loop_orig - killed_ab;
- const uint dist_b = poly_len - dist_a;
+ const int dist_a = wlb->loop_orig - wla->loop_orig - killed_ab;
+ const int dist_b = poly_len - dist_a;
BLI_assert(dist_a != 0 && dist_b != 0);
if (dist_a == 1 || dist_b == 1) {
@@ -989,7 +935,7 @@ static void weld_poly_split_recursive(const uint *vert_dest_map,
BLI_assert((wla->flag == ELEM_COLLAPSED) || (wlb->flag == ELEM_COLLAPSED));
}
else {
- WeldLoop *wl_tmp = NULL;
+ WeldLoop *wl_tmp = nullptr;
if (dist_a == 2) {
wl_tmp = wlb_prev;
BLI_assert(wla->flag != ELEM_COLLAPSED);
@@ -1000,7 +946,7 @@ static void weld_poly_split_recursive(const uint *vert_dest_map,
poly_len -= 2;
}
if (dist_b == 2) {
- if (wl_tmp != NULL) {
+ if (wl_tmp != nullptr) {
r_wp->flag = ELEM_COLLAPSED;
*r_poly_kill += 1;
}
@@ -1014,9 +960,9 @@ static void weld_poly_split_recursive(const uint *vert_dest_map,
loop_kill += 2;
poly_len -= 2;
}
- if (wl_tmp == NULL) {
- const uint new_loops_len = lb - la;
- const uint new_loops_ofs = ctx_loops_ofs + la;
+ if (wl_tmp == nullptr) {
+ const int new_loops_len = lb - la;
+ const int new_loops_ofs = ctx_loops_ofs + la;
WeldPoly *new_wp = &wpoly_new[r_weld_mesh->wpoly_new_len++];
new_wp->poly_dst = OUT_OF_CONTEXT;
@@ -1065,56 +1011,53 @@ static void weld_poly_split_recursive(const uint *vert_dest_map,
*r_loop_kill += loop_kill;
#ifdef USE_WELD_DEBUG
- weld_assert_poly_no_vert_repetition(r_wp, wloop, mloop, r_weld_mesh->loop_map);
+ weld_assert_poly_no_vert_repetition(*r_wp, wloop, mloop, r_weld_mesh->loop_map);
#endif
}
}
-static void weld_poly_loop_ctx_setup(const MLoop *mloop,
+static void weld_poly_loop_ctx_setup(Span<MLoop> mloop,
#ifdef USE_WELD_DEBUG
- const MPoly *mpoly,
- const uint mpoly_len,
- const uint mloop_len,
+ Span<MPoly> mpoly,
#endif
- const uint mvert_len,
- const uint *vert_dest_map,
- const uint remain_edge_ctx_len,
- struct WeldGroup *r_vlinks,
+ const int mvert_len,
+ Span<int> vert_dest_map,
+ const int remain_edge_ctx_len,
+ MutableSpan<WeldGroup> r_vlinks,
WeldMesh *r_weld_mesh)
{
- uint poly_kill_len, loop_kill_len, wpoly_len, wpoly_new_len;
+ int poly_kill_len, loop_kill_len, wpoly_len, wpoly_new_len;
- WeldPoly *wpoly_new, *wpoly, *wp;
- WeldLoop *wloop, *wl;
+ WeldPoly *wpoly_new;
+ WeldLoop *wl;
- wpoly = r_weld_mesh->wpoly;
- wloop = r_weld_mesh->wloop;
+ MutableSpan<WeldPoly> wpoly = r_weld_mesh->wpoly;
+ MutableSpan<WeldLoop> wloop = r_weld_mesh->wloop;
wpoly_new = r_weld_mesh->wpoly_new;
wpoly_len = r_weld_mesh->wpoly_len;
wpoly_new_len = 0;
poly_kill_len = 0;
loop_kill_len = 0;
- const uint *loop_map = r_weld_mesh->loop_map;
+ Span<int> loop_map = r_weld_mesh->loop_map;
if (remain_edge_ctx_len) {
- /* Setup Poly/Loop. */
+ /* Setup Poly/Loop. Note that `wpoly_len` may be different than `wpoly.size()` here. */
+ for (const int i : IndexRange(wpoly_len)) {
+ WeldPoly &wp = wpoly[i];
+ const int ctx_loops_len = wp.loops.len;
+ const int ctx_loops_ofs = wp.loops.ofs;
- wp = &wpoly[0];
- for (uint i = wpoly_len; i--; wp++) {
- const uint ctx_loops_len = wp->loops.len;
- const uint ctx_loops_ofs = wp->loops.ofs;
-
- uint poly_len = wp->len;
- uint ctx_verts_len = 0;
+ int poly_len = wp.len;
+ int ctx_verts_len = 0;
wl = &wloop[ctx_loops_ofs];
- for (uint l = ctx_loops_len; l--; wl++) {
- const uint edge_dest = wl->edge;
+ for (int l = ctx_loops_len; l--; wl++) {
+ const int edge_dest = wl->edge;
if (edge_dest == ELEM_COLLAPSED) {
wl->flag = ELEM_COLLAPSED;
if (poly_len == 3) {
- wp->flag = ELEM_COLLAPSED;
+ wp.flag = ELEM_COLLAPSED;
poly_kill_len++;
loop_kill_len += 3;
poly_len = 0;
@@ -1124,7 +1067,7 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
poly_len--;
}
else {
- const uint vert_dst = wl->vert;
+ const int vert_dst = wl->vert;
if (vert_dest_map[vert_dst] != OUT_OF_CONTEXT) {
ctx_verts_len++;
}
@@ -1132,7 +1075,7 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
}
if (poly_len) {
- wp->len = poly_len;
+ wp.len = poly_len;
#ifdef USE_WELD_DEBUG
weld_assert_poly_len(wp, wloop);
#endif
@@ -1142,7 +1085,7 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
mloop,
#endif
ctx_verts_len,
- wp,
+ &wp,
r_weld_mesh,
&poly_kill_len,
&loop_kill_len);
@@ -1153,75 +1096,70 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
#ifdef USE_WELD_DEBUG
weld_assert_poly_and_loop_kill_len(wpoly,
- wpoly_new,
- wpoly_new_len,
+ {wpoly_new, wpoly_new_len},
wloop,
mloop,
loop_map,
r_weld_mesh->poly_map,
mpoly,
- mpoly_len,
- mloop_len,
poly_kill_len,
loop_kill_len);
#endif
/* Setup Polygon Overlap. */
- uint wpoly_and_new_len = wpoly_len + wpoly_new_len;
+ int wpoly_and_new_len = wpoly_len + wpoly_new_len;
- struct WeldGroup *vl_iter, *v_links = r_vlinks;
- memset(v_links, 0, sizeof(*v_links) * mvert_len);
+ r_vlinks.fill({0, 0});
+ MutableSpan<WeldGroup> v_links = r_vlinks;
- wp = &wpoly[0];
- for (uint i = wpoly_and_new_len; i--; wp++) {
+ for (const int i : IndexRange(wpoly_and_new_len)) {
+ const WeldPoly &wp = wpoly[i];
WeldLoopOfPolyIter iter;
- if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) {
while (weld_iter_loop_of_poly_next(&iter)) {
v_links[iter.v].len++;
}
}
}
- uint link_len = 0;
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
- vl_iter->ofs = link_len;
- link_len += vl_iter->len;
+ int link_len = 0;
+ for (const int i : IndexRange(mvert_len)) {
+ v_links[i].ofs = link_len;
+ link_len += v_links[i].len;
}
if (link_len) {
- uint *link_poly_buffer = MEM_mallocN(sizeof(*link_poly_buffer) * link_len, __func__);
+ Array<int> link_poly_buffer(link_len);
- wp = &wpoly[0];
- for (uint i = 0; i < wpoly_and_new_len; i++, wp++) {
+ for (const int i : IndexRange(wpoly_and_new_len)) {
+ const WeldPoly &wp = wpoly[i];
WeldLoopOfPolyIter iter;
- if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) {
+ if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) {
while (weld_iter_loop_of_poly_next(&iter)) {
link_poly_buffer[v_links[iter.v].ofs++] = i;
}
}
}
- vl_iter = &v_links[0];
- for (uint i = mvert_len; i--; vl_iter++) {
+ for (WeldGroup &vl : r_vlinks) {
/* Fix offset */
- vl_iter->ofs -= vl_iter->len;
+ vl.ofs -= vl.len;
}
- uint polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b;
+ int polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b;
polys_len_b = p_ctx_b = 0; /* silence warnings */
- wp = &wpoly[0];
- for (uint i = 0; i < wpoly_and_new_len; i++, wp++) {
- if (wp->poly_dst != OUT_OF_CONTEXT) {
+ for (const int i : IndexRange(wpoly_and_new_len)) {
+ const WeldPoly &wp = wpoly[i];
+ if (wp.poly_dst != OUT_OF_CONTEXT) {
/* No need to retest poly.
* (Already includes collapsed polygons). */
continue;
}
WeldLoopOfPolyIter iter;
- weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL);
+ weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr);
weld_iter_loop_of_poly_next(&iter);
struct WeldGroup *link_a = &v_links[iter.v];
polys_len_a = link_a->len;
@@ -1229,7 +1167,7 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
BLI_assert(link_poly_buffer[link_a->ofs] == i);
continue;
}
- uint wp_len = wp->len;
+ int wp_len = wp.len;
polys_ctx_a = &link_poly_buffer[link_a->ofs];
for (; polys_len_a--; polys_ctx_a++) {
p_ctx_a = *polys_ctx_a;
@@ -1275,36 +1213,31 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
BLI_assert(p_ctx_a > i);
BLI_assert(p_ctx_a == p_ctx_b);
BLI_assert(wp_tmp->poly_dst == OUT_OF_CONTEXT);
- BLI_assert(wp_tmp != wp);
- wp_tmp->poly_dst = wp->poly_orig;
+ BLI_assert(wp_tmp != &wp);
+ wp_tmp->poly_dst = wp.poly_orig;
loop_kill_len += wp_tmp->len;
poly_kill_len++;
}
}
- MEM_freeN(link_poly_buffer);
}
}
else {
poly_kill_len = r_weld_mesh->wpoly_len;
loop_kill_len = r_weld_mesh->wloop_len;
- wp = &wpoly[0];
- for (uint i = wpoly_len; i--; wp++) {
- wp->flag = ELEM_COLLAPSED;
+ for (WeldPoly &wp : wpoly) {
+ wp.flag = ELEM_COLLAPSED;
}
}
#ifdef USE_WELD_DEBUG
weld_assert_poly_and_loop_kill_len(wpoly,
- wpoly_new,
- wpoly_new_len,
+ {wpoly_new, wpoly_new_len},
wloop,
mloop,
loop_map,
r_weld_mesh->poly_map,
mpoly,
- mpoly_len,
- mloop_len,
poly_kill_len,
loop_kill_len);
#endif
@@ -1321,87 +1254,53 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop,
* \{ */
static void weld_mesh_context_create(const Mesh *mesh,
- uint *vert_dest_map,
- const uint vert_kill_len,
+ MutableSpan<int> vert_dest_map,
+ const int vert_kill_len,
WeldMesh *r_weld_mesh)
{
- const MEdge *medge = mesh->medge;
- const MLoop *mloop = mesh->mloop;
- const MPoly *mpoly = mesh->mpoly;
- const uint mvert_len = mesh->totvert;
- const uint medge_len = mesh->totedge;
- const uint mloop_len = mesh->totloop;
- const uint mpoly_len = mesh->totpoly;
-
- uint *edge_dest_map = MEM_mallocN(sizeof(*edge_dest_map) * medge_len, __func__);
- struct WeldGroup *v_links = MEM_callocN(sizeof(*v_links) * mvert_len, __func__);
-
- WeldVert *wvert;
- uint wvert_len;
+ Span<MEdge> medge{mesh->medge, mesh->totedge};
+ Span<MPoly> mpoly{mesh->mpoly, mesh->totpoly};
+ Span<MLoop> mloop{mesh->mloop, mesh->totloop};
+ const int mvert_len = mesh->totvert;
+
+ Vector<WeldVert> wvert = weld_vert_ctx_alloc_and_setup(vert_dest_map, vert_kill_len);
r_weld_mesh->vert_kill_len = vert_kill_len;
- weld_vert_ctx_alloc_and_setup(mvert_len, vert_dest_map, &wvert, &wvert_len);
- uint *edge_ctx_map;
- WeldEdge *wedge;
- uint wedge_len;
- weld_edge_ctx_alloc(
- medge, medge_len, vert_dest_map, edge_dest_map, &edge_ctx_map, &wedge, &wedge_len);
+ Array<int> edge_dest_map(medge.size());
+ Array<int> edge_ctx_map(medge.size());
+ Vector<WeldEdge> wedge = weld_edge_ctx_alloc(medge, vert_dest_map, edge_dest_map, edge_ctx_map);
- weld_edge_ctx_setup(
- mvert_len, wedge_len, v_links, edge_dest_map, wedge, &r_weld_mesh->edge_kill_len);
+ Array<WeldGroup> v_links(mvert_len, {0, 0});
+ weld_edge_ctx_setup(v_links, edge_dest_map, wedge, &r_weld_mesh->edge_kill_len);
- weld_poly_loop_ctx_alloc(
- mpoly, mpoly_len, mloop, mloop_len, vert_dest_map, edge_dest_map, r_weld_mesh);
+ weld_poly_loop_ctx_alloc(mpoly, mloop, vert_dest_map, edge_dest_map, r_weld_mesh);
weld_poly_loop_ctx_setup(mloop,
#ifdef USE_WELD_DEBUG
mpoly,
- mpoly_len,
- mloop_len,
+
#endif
mvert_len,
vert_dest_map,
- wedge_len - r_weld_mesh->edge_kill_len,
+ wedge.size() - r_weld_mesh->edge_kill_len,
v_links,
r_weld_mesh);
- weld_vert_groups_setup(mvert_len,
- wvert_len,
- wvert,
+ weld_vert_groups_setup(wvert,
vert_dest_map,
vert_dest_map,
- &r_weld_mesh->vert_groups_buffer,
- &r_weld_mesh->vert_groups);
+ r_weld_mesh->vert_groups_buffer,
+ r_weld_mesh->vert_groups);
- weld_edge_groups_setup(medge_len,
+ weld_edge_groups_setup(medge.size(),
r_weld_mesh->edge_kill_len,
- wedge_len,
wedge,
edge_ctx_map,
edge_dest_map,
- &r_weld_mesh->edge_groups_buffer,
- &r_weld_mesh->edge_groups);
-
- r_weld_mesh->edge_groups_map = edge_dest_map;
- MEM_freeN(v_links);
- MEM_freeN(wvert);
- MEM_freeN(edge_ctx_map);
- MEM_freeN(wedge);
-}
-
-static void weld_mesh_context_free(WeldMesh *weld_mesh)
-{
- MEM_freeN(weld_mesh->vert_groups);
- MEM_freeN(weld_mesh->vert_groups_buffer);
-
- MEM_freeN(weld_mesh->edge_groups);
- MEM_freeN(weld_mesh->edge_groups_buffer);
- MEM_freeN(weld_mesh->edge_groups_map);
+ r_weld_mesh->edge_groups_buffer,
+ r_weld_mesh->edge_groups);
- MEM_freeN(weld_mesh->wloop);
- MEM_freeN(weld_mesh->wpoly);
- MEM_freeN(weld_mesh->loop_map);
- MEM_freeN(weld_mesh->poly_map);
+ r_weld_mesh->edge_groups_map = std::move(edge_dest_map);
}
/** \} */
@@ -1411,14 +1310,14 @@ static void weld_mesh_context_free(WeldMesh *weld_mesh)
* \{ */
static void customdata_weld(
- const CustomData *source, CustomData *dest, const uint *src_indices, int count, int dest_index)
+ const CustomData *source, CustomData *dest, const int *src_indices, int count, int dest_index)
{
if (count == 1) {
CustomData_copy_data(source, dest, src_indices[0], dest_index, 1);
return;
}
- CustomData_interp(source, dest, (const int *)src_indices, NULL, NULL, count, dest_index);
+ CustomData_interp(source, dest, (const int *)src_indices, nullptr, nullptr, count, dest_index);
int src_i, dest_i;
int j;
@@ -1427,8 +1326,8 @@ static void customdata_weld(
#ifdef USE_WELD_NORMALS
float no[3] = {0.0f, 0.0f, 0.0f};
#endif
- uint crease = 0;
- uint bweight = 0;
+ int crease = 0;
+ int bweight = 0;
short flag = 0;
/* interpolates a layer at a time */
@@ -1572,37 +1471,35 @@ static bool bvhtree_weld_overlap_cb(void *userdata, int index_a, int index_b, in
/** Use for #MOD_WELD_MODE_CONNECTED calculation. */
struct WeldVertexCluster {
float co[3];
- uint merged_verts;
+ int merged_verts;
};
static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
const ModifierEvalContext *UNUSED(ctx),
Mesh *mesh)
{
- Mesh *result = mesh;
-
- BLI_bitmap *v_mask = NULL;
+ BLI_bitmap *v_mask = nullptr;
int v_mask_act = 0;
- const MVert *mvert;
- const MLoop *mloop;
- const MPoly *mpoly, *mp;
- uint totvert, totedge, totloop, totpoly;
-
- mvert = mesh->mvert;
- totvert = mesh->totvert;
+ Span<MVert> mvert{mesh->mvert, mesh->totvert};
+ Span<MEdge> medge{mesh->medge, mesh->totedge};
+ Span<MPoly> mpoly{mesh->mpoly, mesh->totpoly};
+ Span<MLoop> mloop{mesh->mloop, mesh->totloop};
+ const int totvert = mesh->totvert;
+ const int totedge = mesh->totedge;
+ const int totloop = mesh->totloop;
+ const int totpoly = mesh->totpoly;
/* Vertex Group. */
const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name);
if (defgrp_index != -1) {
- MDeformVert *dvert, *dv;
- dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT);
+ MDeformVert *dvert;
+ dvert = static_cast<MDeformVert *>(CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT));
if (dvert) {
const bool invert_vgroup = (wmd->flag & MOD_WELD_INVERT_VGROUP) != 0;
- dv = &dvert[0];
v_mask = BLI_BITMAP_NEW(totvert, __func__);
- for (uint i = 0; i < totvert; i++, dv++) {
- const bool found = BKE_defvert_find_weight(dv, defgrp_index) > 0.0f;
+ for (const int i : IndexRange(totvert)) {
+ const bool found = BKE_defvert_find_weight(&dvert[i], defgrp_index) > 0.0f;
if (found != invert_vgroup) {
BLI_BITMAP_ENABLE(v_mask, i);
v_mask_act++;
@@ -1613,15 +1510,15 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
/* From the original index of the vertex.
* This indicates which vert it is or is going to be merged. */
- uint *vert_dest_map = MEM_malloc_arrayN(totvert, sizeof(*vert_dest_map), __func__);
- uint vert_kill_len = 0;
+ Array<int> vert_dest_map(totvert);
+ int vert_kill_len = 0;
if (wmd->mode == MOD_WELD_MODE_ALL)
#ifdef USE_BVHTREEKDOP
{
/* Get overlap map. */
struct BVHTreeFromMesh treedata;
BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(&treedata,
- mvert,
+ mvert.data(),
totvert,
false,
v_mask,
@@ -1630,8 +1527,8 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
2,
6,
0,
- NULL,
- NULL);
+ nullptr,
+ nullptr);
if (bvhtree) {
struct WeldOverlapData data;
@@ -1649,20 +1546,20 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
free_bvhtree_from_mesh(&treedata);
if (overlap) {
- range_vn_u(vert_dest_map, totvert, 0);
+ range_vn_i(vert_dest_map.data(), totvert, 0);
const BVHTreeOverlap *overlap_iter = &overlap[0];
- for (uint i = 0; i < overlap_len; i++, overlap_iter++) {
- uint indexA = overlap_iter->indexA;
- uint indexB = overlap_iter->indexB;
+ for (int i = 0; i < overlap_len; i++, overlap_iter++) {
+ int indexA = overlap_iter->indexA;
+ int indexB = overlap_iter->indexB;
BLI_assert(indexA < indexB);
- uint va_dst = vert_dest_map[indexA];
+ int va_dst = vert_dest_map[indexA];
while (va_dst != vert_dest_map[va_dst]) {
va_dst = vert_dest_map[va_dst];
}
- uint vb_dst = vert_dest_map[indexB];
+ int vb_dst = vert_dest_map[indexB];
while (vb_dst != vert_dest_map[vb_dst]) {
vb_dst = vert_dest_map[vb_dst];
}
@@ -1670,19 +1567,19 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
continue;
}
if (va_dst > vb_dst) {
- SWAP(uint, va_dst, vb_dst);
+ SWAP(int, va_dst, vb_dst);
}
vert_kill_len++;
vert_dest_map[vb_dst] = va_dst;
}
/* Fix #r_vert_dest_map for next step. */
- for (uint i = 0; i < totvert; i++) {
+ for (int i = 0; i < totvert; i++) {
if (i == vert_dest_map[i]) {
vert_dest_map[i] = OUT_OF_CONTEXT;
}
else {
- uint v = i;
+ int v = i;
while (v != vert_dest_map[v] && vert_dest_map[v] != OUT_OF_CONTEXT) {
v = vert_dest_map[v];
}
@@ -1698,7 +1595,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
#else
{
KDTree_3d *tree = BLI_kdtree_3d_new(v_mask ? v_mask_act : totvert);
- for (uint i = 0; i < totvert; i++) {
+ for (const int i : IndexRange(totvert)) {
if (!v_mask || BLI_BITMAP_TEST(v_mask, i)) {
BLI_kdtree_3d_insert(tree, i, mvert[i].co);
}
@@ -1707,37 +1604,30 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
BLI_kdtree_3d_balance(tree);
vert_kill_len = BLI_kdtree_3d_calc_duplicates_fast(
- tree, wmd->merge_dist, false, (int *)vert_dest_map);
+ tree, wmd->merge_dist, false, vert_dest_map.data());
BLI_kdtree_3d_free(tree);
}
#endif
else {
BLI_assert(wmd->mode == MOD_WELD_MODE_CONNECTED);
- MEdge *medge, *me;
-
- medge = mesh->medge;
- totvert = mesh->totvert;
- totedge = mesh->totedge;
+ Array<WeldVertexCluster> vert_clusters(totvert);
- struct WeldVertexCluster *vert_clusters = MEM_malloc_arrayN(
- totvert, sizeof(*vert_clusters), __func__);
- struct WeldVertexCluster *vc = &vert_clusters[0];
- for (uint i = 0; i < totvert; i++, vc++) {
- copy_v3_v3(vc->co, mvert[i].co);
- vc->merged_verts = 0;
+ for (const int i : mvert.index_range()) {
+ WeldVertexCluster &vc = vert_clusters[i];
+ copy_v3_v3(vc.co, mvert[i].co);
+ vc.merged_verts = 0;
}
const float merge_dist_sq = square_f(wmd->merge_dist);
- range_vn_u(vert_dest_map, totvert, 0);
+ range_vn_i(vert_dest_map.data(), totvert, 0);
/* Collapse Edges that are shorter than the threshold. */
- me = &medge[0];
- for (uint i = 0; i < totedge; i++, me++) {
- uint v1 = me->v1;
- uint v2 = me->v2;
+ for (const int i : medge.index_range()) {
+ int v1 = medge[i].v1;
+ int v2 = medge[i].v2;
- if (wmd->flag & MOD_WELD_LOOSE_EDGES && (me->flag & ME_LOOSEEDGE) == 0) {
+ if (wmd->flag & MOD_WELD_LOOSE_EDGES && (medge[i].flag & ME_LOOSEEDGE) == 0) {
continue;
}
while (v1 != vert_dest_map[v1]) {
@@ -1753,10 +1643,10 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
continue;
}
if (v1 > v2) {
- SWAP(uint, v1, v2);
+ SWAP(int, v1, v2);
}
- struct WeldVertexCluster *v1_cluster = &vert_clusters[v1];
- struct WeldVertexCluster *v2_cluster = &vert_clusters[v2];
+ WeldVertexCluster *v1_cluster = &vert_clusters[v1];
+ WeldVertexCluster *v2_cluster = &vert_clusters[v2];
float edgedir[3];
sub_v3_v3v3(edgedir, v2_cluster->co, v1_cluster->co);
@@ -1772,14 +1662,12 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
}
}
- MEM_freeN(vert_clusters);
-
- for (uint i = 0; i < totvert; i++) {
+ for (const int i : IndexRange(totvert)) {
if (i == vert_dest_map[i]) {
vert_dest_map[i] = OUT_OF_CONTEXT;
}
else {
- uint v = i;
+ int v = i;
while ((v != vert_dest_map[v]) && (vert_dest_map[v] != OUT_OF_CONTEXT)) {
v = vert_dest_map[v];
}
@@ -1793,174 +1681,139 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
MEM_freeN(v_mask);
}
- if (vert_kill_len) {
- WeldMesh weld_mesh;
- weld_mesh_context_create(mesh, vert_dest_map, vert_kill_len, &weld_mesh);
-
- mloop = mesh->mloop;
- mpoly = mesh->mpoly;
-
- totedge = mesh->totedge;
- totloop = mesh->totloop;
- totpoly = mesh->totpoly;
-
- const int result_nverts = totvert - weld_mesh.vert_kill_len;
- const int result_nedges = totedge - weld_mesh.edge_kill_len;
- const int result_nloops = totloop - weld_mesh.loop_kill_len;
- const int result_npolys = totpoly - weld_mesh.poly_kill_len + weld_mesh.wpoly_new_len;
-
- result = BKE_mesh_new_nomain_from_template(
- mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys);
-
- /* Vertices */
-
- uint *vert_final = vert_dest_map;
- uint *index_iter = &vert_final[0];
- int dest_index = 0;
- for (uint i = 0; i < totvert; i++, index_iter++) {
- int source_index = i;
- int count = 0;
- while (i < totvert && *index_iter == OUT_OF_CONTEXT) {
- *index_iter = dest_index + count;
- index_iter++;
- count++;
- i++;
- }
- if (count) {
- CustomData_copy_data(&mesh->vdata, &result->vdata, source_index, dest_index, count);
- dest_index += count;
- }
- if (i == totvert) {
- break;
- }
- if (*index_iter != ELEM_MERGED) {
- struct WeldGroup *wgroup = &weld_mesh.vert_groups[*index_iter];
- customdata_weld(&mesh->vdata,
- &result->vdata,
- &weld_mesh.vert_groups_buffer[wgroup->ofs],
- wgroup->len,
- dest_index);
- *index_iter = dest_index;
- dest_index++;
- }
- }
+ if (vert_kill_len == 0) {
+ return mesh;
+ }
- BLI_assert(dest_index == result_nverts);
-
- /* Edges */
-
- uint *edge_final = weld_mesh.edge_groups_map;
- index_iter = &edge_final[0];
- dest_index = 0;
- for (uint i = 0; i < totedge; i++, index_iter++) {
- int source_index = i;
- int count = 0;
- while (i < totedge && *index_iter == OUT_OF_CONTEXT) {
- *index_iter = dest_index + count;
- index_iter++;
- count++;
- i++;
- }
- if (count) {
- CustomData_copy_data(&mesh->edata, &result->edata, source_index, dest_index, count);
- MEdge *me = &result->medge[dest_index];
- dest_index += count;
- for (; count--; me++) {
- me->v1 = vert_final[me->v1];
- me->v2 = vert_final[me->v2];
- }
- }
- if (i == totedge) {
- break;
- }
- if (*index_iter != ELEM_MERGED) {
- struct WeldGroupEdge *wegrp = &weld_mesh.edge_groups[*index_iter];
- customdata_weld(&mesh->edata,
- &result->edata,
- &weld_mesh.edge_groups_buffer[wegrp->group.ofs],
- wegrp->group.len,
- dest_index);
- MEdge *me = &result->medge[dest_index];
- me->v1 = vert_final[wegrp->v1];
- me->v2 = vert_final[wegrp->v2];
- me->flag |= ME_LOOSEEDGE;
-
- *index_iter = dest_index;
- dest_index++;
- }
+ WeldMesh weld_mesh;
+ weld_mesh_context_create(mesh, vert_dest_map, vert_kill_len, &weld_mesh);
+
+ const int result_nverts = totvert - weld_mesh.vert_kill_len;
+ const int result_nedges = totedge - weld_mesh.edge_kill_len;
+ const int result_nloops = totloop - weld_mesh.loop_kill_len;
+ const int result_npolys = totpoly - weld_mesh.poly_kill_len + weld_mesh.wpoly_new_len;
+
+ Mesh *result = BKE_mesh_new_nomain_from_template(
+ mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys);
+
+ /* Vertices. */
+
+ /* Be careful when editing this array, to avoid new allocations it uses the same buffer as
+ * #vert_dest_map. This map will be used to adjust the edges, polys and loops. */
+ MutableSpan<int> vert_final = vert_dest_map;
+
+ int dest_index = 0;
+ for (int i = 0; i < totvert; i++) {
+ int source_index = i;
+ int count = 0;
+ while (i < totvert && vert_dest_map[i] == OUT_OF_CONTEXT) {
+ vert_final[i] = dest_index + count;
+ count++;
+ i++;
}
+ if (count) {
+ CustomData_copy_data(&mesh->vdata, &result->vdata, source_index, dest_index, count);
+ dest_index += count;
+ }
+ if (i == totvert) {
+ break;
+ }
+ if (vert_dest_map[i] != ELEM_MERGED) {
+ struct WeldGroup *wgroup = &weld_mesh.vert_groups[vert_dest_map[i]];
+ customdata_weld(&mesh->vdata,
+ &result->vdata,
+ &weld_mesh.vert_groups_buffer[wgroup->ofs],
+ wgroup->len,
+ dest_index);
+ vert_final[i] = dest_index;
+ dest_index++;
+ }
+ }
- BLI_assert(dest_index == result_nedges);
-
- /* Polys/Loops */
-
- mp = &mpoly[0];
- MPoly *r_mp = &result->mpoly[0];
- MLoop *r_ml = &result->mloop[0];
- uint r_i = 0;
- int loop_cur = 0;
- uint *group_buffer = BLI_array_alloca(group_buffer, weld_mesh.max_poly_len);
- for (uint i = 0; i < totpoly; i++, mp++) {
- int loop_start = loop_cur;
- uint poly_ctx = weld_mesh.poly_map[i];
- if (poly_ctx == OUT_OF_CONTEXT) {
- uint mp_loop_len = mp->totloop;
- CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart, loop_cur, mp_loop_len);
- loop_cur += mp_loop_len;
- for (; mp_loop_len--; r_ml++) {
- r_ml->v = vert_final[r_ml->v];
- r_ml->e = edge_final[r_ml->e];
- }
- }
- else {
- WeldPoly *wp = &weld_mesh.wpoly[poly_ctx];
- WeldLoopOfPolyIter iter;
- if (!weld_iter_loop_of_poly_begin(
- &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) {
- continue;
- }
+ BLI_assert(dest_index == result_nverts);
- if (wp->poly_dst != OUT_OF_CONTEXT) {
- continue;
- }
- while (weld_iter_loop_of_poly_next(&iter)) {
- customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur);
- uint v = vert_final[iter.v];
- uint e = edge_final[iter.e];
- r_ml->v = v;
- r_ml->e = e;
- r_ml++;
- loop_cur++;
- if (iter.type) {
- result->medge[e].flag &= ~ME_LOOSEEDGE;
- }
- BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
- }
- }
+ /* Edges. */
+
+ /* Be careful when editing this array, to avoid new allocations it uses the same buffer as
+ * #edge_groups_map. This map will be used to adjust the polys and loops. */
+ MutableSpan<int> edge_final = weld_mesh.edge_groups_map;
- CustomData_copy_data(&mesh->pdata, &result->pdata, i, r_i, 1);
- r_mp->loopstart = loop_start;
- r_mp->totloop = loop_cur - loop_start;
- r_mp++;
- r_i++;
+ dest_index = 0;
+ for (int i = 0; i < totedge; i++) {
+ int source_index = i;
+ int count = 0;
+ while (i < totedge && weld_mesh.edge_groups_map[i] == OUT_OF_CONTEXT) {
+ edge_final[i] = dest_index + count;
+ count++;
+ i++;
+ }
+ if (count) {
+ CustomData_copy_data(&mesh->edata, &result->edata, source_index, dest_index, count);
+ MEdge *me = &result->medge[dest_index];
+ dest_index += count;
+ for (; count--; me++) {
+ me->v1 = vert_final[me->v1];
+ me->v2 = vert_final[me->v2];
+ }
+ }
+ if (i == totedge) {
+ break;
}
+ if (weld_mesh.edge_groups_map[i] != ELEM_MERGED) {
+ struct WeldGroupEdge *wegrp = &weld_mesh.edge_groups[weld_mesh.edge_groups_map[i]];
+ customdata_weld(&mesh->edata,
+ &result->edata,
+ &weld_mesh.edge_groups_buffer[wegrp->group.ofs],
+ wegrp->group.len,
+ dest_index);
+ MEdge *me = &result->medge[dest_index];
+ me->v1 = vert_final[wegrp->v1];
+ me->v2 = vert_final[wegrp->v2];
+ me->flag |= ME_LOOSEEDGE;
+
+ edge_final[i] = dest_index;
+ dest_index++;
+ }
+ }
- WeldPoly *wp = &weld_mesh.wpoly_new[0];
- for (uint i = 0; i < weld_mesh.wpoly_new_len; i++, wp++) {
- int loop_start = loop_cur;
+ BLI_assert(dest_index == result_nedges);
+
+ /* Polys/Loops. */
+
+ MPoly *r_mp = &result->mpoly[0];
+ MLoop *r_ml = &result->mloop[0];
+ int r_i = 0;
+ int loop_cur = 0;
+ Array<int, 64> group_buffer(weld_mesh.max_poly_len);
+ for (const int i : mpoly.index_range()) {
+ const MPoly &mp = mpoly[i];
+ int loop_start = loop_cur;
+ int poly_ctx = weld_mesh.poly_map[i];
+ if (poly_ctx == OUT_OF_CONTEXT) {
+ int mp_loop_len = mp.totloop;
+ CustomData_copy_data(&mesh->ldata, &result->ldata, mp.loopstart, loop_cur, mp_loop_len);
+ loop_cur += mp_loop_len;
+ for (; mp_loop_len--; r_ml++) {
+ r_ml->v = vert_final[r_ml->v];
+ r_ml->e = edge_final[r_ml->e];
+ }
+ }
+ else {
+ const WeldPoly &wp = weld_mesh.wpoly[poly_ctx];
WeldLoopOfPolyIter iter;
if (!weld_iter_loop_of_poly_begin(
- &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) {
+ &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) {
continue;
}
- if (wp->poly_dst != OUT_OF_CONTEXT) {
+ if (wp.poly_dst != OUT_OF_CONTEXT) {
continue;
}
while (weld_iter_loop_of_poly_next(&iter)) {
- customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur);
- uint v = vert_final[iter.v];
- uint e = edge_final[iter.e];
+ customdata_weld(
+ &mesh->ldata, &result->ldata, group_buffer.data(), iter.group_len, loop_cur);
+ int v = vert_final[iter.v];
+ int e = edge_final[iter.e];
r_ml->v = v;
r_ml->e = e;
r_ml++;
@@ -1970,23 +1823,54 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd,
}
BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
}
-
- r_mp->loopstart = loop_start;
- r_mp->totloop = loop_cur - loop_start;
- r_mp++;
- r_i++;
}
- BLI_assert((int)r_i == result_npolys);
- BLI_assert(loop_cur == result_nloops);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, i, r_i, 1);
+ r_mp->loopstart = loop_start;
+ r_mp->totloop = loop_cur - loop_start;
+ r_mp++;
+ r_i++;
+ }
- /* is this needed? */
- BKE_mesh_normals_tag_dirty(result);
+ for (const int i : IndexRange(weld_mesh.wpoly_new_len)) {
+ const WeldPoly &wp = weld_mesh.wpoly_new[i];
+ int loop_start = loop_cur;
+ WeldLoopOfPolyIter iter;
+ if (!weld_iter_loop_of_poly_begin(
+ &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) {
+ continue;
+ }
- weld_mesh_context_free(&weld_mesh);
+ if (wp.poly_dst != OUT_OF_CONTEXT) {
+ continue;
+ }
+ while (weld_iter_loop_of_poly_next(&iter)) {
+ customdata_weld(&mesh->ldata, &result->ldata, group_buffer.data(), iter.group_len, loop_cur);
+ int v = vert_final[iter.v];
+ int e = edge_final[iter.e];
+ r_ml->v = v;
+ r_ml->e = e;
+ r_ml++;
+ loop_cur++;
+ if (iter.type) {
+ result->medge[e].flag &= ~ME_LOOSEEDGE;
+ }
+ BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0);
+ }
+
+ r_mp->loopstart = loop_start;
+ r_mp->totloop = loop_cur - loop_start;
+ r_mp++;
+ r_i++;
}
- MEM_freeN(vert_dest_map);
+ BLI_assert((int)r_i == result_npolys);
+ BLI_assert(loop_cur == result_nloops);
+
+ /* We could only update the normals of the elements in context, but the next modifier can make it
+ * dirty anyway which would make the work useless. */
+ BKE_mesh_normals_tag_dirty(result);
+
return result;
}
@@ -2027,12 +1911,12 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiLayoutSetPropSep(layout, true);
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mode", 0, nullptr, ICON_NONE);
uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE);
if (weld_mode == MOD_WELD_MODE_CONNECTED) {
- uiItemR(layout, ptr, "loose_edges", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "loose_edges", 0, nullptr, ICON_NONE);
}
- modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL);
+ modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr);
modifier_panel_end(layout, ptr);
}
@@ -2048,34 +1932,35 @@ ModifierTypeInfo modifierType_Weld = {
/* structSize */ sizeof(WeldModifierData),
/* srna */ &RNA_WeldModifier,
/* type */ eModifierTypeType_Constructive,
- /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
- eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
- eModifierTypeFlag_AcceptsCVs,
+ /* flags */
+ (ModifierTypeFlag)(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping |
+ eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode |
+ eModifierTypeFlag_AcceptsCVs),
/* icon */ ICON_AUTOMERGE_OFF, /* TODO: Use correct icon. */
/* copyData */ BKE_modifier_copydata_generic,
- /* deformVerts */ NULL,
- /* deformMatrices */ NULL,
- /* deformVertsEM */ NULL,
- /* deformMatricesEM */ NULL,
+ /* deformVerts */ nullptr,
+ /* deformMatrices */ nullptr,
+ /* deformVertsEM */ nullptr,
+ /* deformMatricesEM */ nullptr,
/* modifyMesh */ modifyMesh,
- /* modifyHair */ NULL,
- /* modifyGeometrySet */ NULL,
+ /* modifyHair */ nullptr,
+ /* modifyGeometrySet */ nullptr,
/* initData */ initData,
/* requiredDataMask */ requiredDataMask,
- /* freeData */ NULL,
- /* isDisabled */ NULL,
- /* updateDepsgraph */ NULL,
- /* dependsOnTime */ NULL,
- /* dependsOnNormals */ NULL,
- /* foreachIDLink */ NULL,
- /* foreachTexLink */ NULL,
- /* freeRuntimeData */ NULL,
+ /* freeData */ nullptr,
+ /* isDisabled */ nullptr,
+ /* updateDepsgraph */ nullptr,
+ /* dependsOnTime */ nullptr,
+ /* dependsOnNormals */ nullptr,
+ /* foreachIDLink */ nullptr,
+ /* foreachTexLink */ nullptr,
+ /* freeRuntimeData */ nullptr,
/* panelRegister */ panelRegister,
- /* blendWrite */ NULL,
- /* blendRead */ NULL,
+ /* blendWrite */ nullptr,
+ /* blendRead */ nullptr,
};
/** \} */
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 5f61d13a3af..4d31cd3e4f5 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -18,6 +18,8 @@
# All rights reserved.
# ***** END GPL LICENSE BLOCK *****
+add_subdirectory(composite)
+add_subdirectory(function)
add_subdirectory(geometry)
add_subdirectory(shader)
@@ -49,114 +51,6 @@ set(INC
set(SRC
- composite/nodes/node_composite_alphaOver.cc
- composite/nodes/node_composite_antialiasing.cc
- composite/nodes/node_composite_bilateralblur.cc
- composite/nodes/node_composite_blur.cc
- composite/nodes/node_composite_bokehblur.cc
- composite/nodes/node_composite_bokehimage.cc
- composite/nodes/node_composite_boxmask.cc
- composite/nodes/node_composite_brightness.cc
- composite/nodes/node_composite_channelMatte.cc
- composite/nodes/node_composite_chromaMatte.cc
- composite/nodes/node_composite_colorMatte.cc
- composite/nodes/node_composite_colorSpill.cc
- composite/nodes/node_composite_colorbalance.cc
- composite/nodes/node_composite_colorcorrection.cc
- composite/nodes/node_composite_common.cc
- composite/nodes/node_composite_composite.cc
- composite/nodes/node_composite_cornerpin.cc
- composite/nodes/node_composite_crop.cc
- composite/nodes/node_composite_cryptomatte.cc
- composite/nodes/node_composite_curves.cc
- composite/nodes/node_composite_defocus.cc
- composite/nodes/node_composite_denoise.cc
- composite/nodes/node_composite_despeckle.cc
- composite/nodes/node_composite_diffMatte.cc
- composite/nodes/node_composite_dilate.cc
- composite/nodes/node_composite_directionalblur.cc
- composite/nodes/node_composite_displace.cc
- composite/nodes/node_composite_distanceMatte.cc
- composite/nodes/node_composite_doubleEdgeMask.cc
- composite/nodes/node_composite_ellipsemask.cc
- composite/nodes/node_composite_exposure.cc
- composite/nodes/node_composite_filter.cc
- composite/nodes/node_composite_flip.cc
- composite/nodes/node_composite_gamma.cc
- composite/nodes/node_composite_glare.cc
- composite/nodes/node_composite_hueSatVal.cc
- composite/nodes/node_composite_huecorrect.cc
- composite/nodes/node_composite_idMask.cc
- composite/nodes/node_composite_image.cc
- composite/nodes/node_composite_inpaint.cc
- composite/nodes/node_composite_invert.cc
- composite/nodes/node_composite_keying.cc
- composite/nodes/node_composite_keyingscreen.cc
- composite/nodes/node_composite_lensdist.cc
- composite/nodes/node_composite_levels.cc
- composite/nodes/node_composite_lummaMatte.cc
- composite/nodes/node_composite_mapRange.cc
- composite/nodes/node_composite_mapUV.cc
- composite/nodes/node_composite_mapValue.cc
- composite/nodes/node_composite_mask.cc
- composite/nodes/node_composite_math.cc
- composite/nodes/node_composite_mixrgb.cc
- composite/nodes/node_composite_movieclip.cc
- composite/nodes/node_composite_moviedistortion.cc
- composite/nodes/node_composite_normal.cc
- composite/nodes/node_composite_normalize.cc
- composite/nodes/node_composite_outputFile.cc
- composite/nodes/node_composite_pixelate.cc
- composite/nodes/node_composite_planetrackdeform.cc
- composite/nodes/node_composite_posterize.cc
- composite/nodes/node_composite_premulkey.cc
- composite/nodes/node_composite_rgb.cc
- composite/nodes/node_composite_rotate.cc
- composite/nodes/node_composite_scale.cc
- composite/nodes/node_composite_sepcombHSVA.cc
- composite/nodes/node_composite_sepcombRGBA.cc
- composite/nodes/node_composite_sepcombYCCA.cc
- composite/nodes/node_composite_sepcombYUVA.cc
- composite/nodes/node_composite_setalpha.cc
- composite/nodes/node_composite_splitViewer.cc
- composite/nodes/node_composite_stabilize2d.cc
- composite/nodes/node_composite_sunbeams.cc
- composite/nodes/node_composite_switch.cc
- composite/nodes/node_composite_switchview.cc
- composite/nodes/node_composite_texture.cc
- composite/nodes/node_composite_tonemap.cc
- composite/nodes/node_composite_trackpos.cc
- composite/nodes/node_composite_transform.cc
- composite/nodes/node_composite_translate.cc
- composite/nodes/node_composite_valToRgb.cc
- composite/nodes/node_composite_value.cc
- composite/nodes/node_composite_vecBlur.cc
- composite/nodes/node_composite_viewer.cc
- composite/nodes/node_composite_zcombine.cc
-
- composite/node_composite_tree.cc
- composite/node_composite_util.cc
-
- function/nodes/legacy/node_fn_random_float.cc
-
- function/nodes/node_fn_align_euler_to_vector.cc
- function/nodes/node_fn_boolean_math.cc
- function/nodes/node_fn_compare.cc
- function/nodes/node_fn_float_to_int.cc
- function/nodes/node_fn_input_bool.cc
- function/nodes/node_fn_input_color.cc
- function/nodes/node_fn_input_int.cc
- function/nodes/node_fn_input_special_characters.cc
- function/nodes/node_fn_input_string.cc
- function/nodes/node_fn_input_vector.cc
- function/nodes/node_fn_random_value.cc
- function/nodes/node_fn_replace_string.cc
- function/nodes/node_fn_rotate_euler.cc
- function/nodes/node_fn_slice_string.cc
- function/nodes/node_fn_string_length.cc
- function/nodes/node_fn_value_to_string.cc
- function/node_function_util.cc
-
texture/nodes/node_texture_at.c
texture/nodes/node_texture_bricks.c
texture/nodes/node_texture_checker.c
@@ -197,8 +91,6 @@ set(SRC
intern/node_tree_ref.cc
intern/node_util.c
- composite/node_composite_util.hh
- function/node_function_util.hh
texture/node_texture_util.h
NOD_common.h
@@ -227,6 +119,8 @@ set(SRC
set(LIB
bf_bmesh
bf_functions
+ bf_nodes_composite
+ bf_nodes_function
bf_nodes_geometry
bf_nodes_shader
)
@@ -282,13 +176,6 @@ if(WITH_IMAGE_OPENEXR)
add_definitions(-DWITH_OPENEXR)
endif()
-if(WITH_COMPOSITOR)
- list(APPEND INC
- ../compositor
- )
- add_definitions(-DWITH_COMPOSITOR)
-endif()
-
if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index a0b8e237f19..96a5e1d87a6 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -49,6 +49,7 @@ 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);
@@ -87,8 +88,8 @@ void register_node_type_geo_curve_resample(void);
void register_node_type_geo_curve_reverse(void);
void register_node_type_geo_curve_sample(void);
void register_node_type_geo_curve_set_handles(void);
-void register_node_type_geo_curve_spline_type(void);
void register_node_type_geo_curve_spline_parameter(void);
+void register_node_type_geo_curve_spline_type(void);
void register_node_type_geo_curve_subdivide(void);
void register_node_type_geo_curve_to_mesh(void);
void register_node_type_geo_curve_to_points(void);
@@ -105,6 +106,7 @@ void register_node_type_geo_input_id(void);
void register_node_type_geo_input_index(void);
void register_node_type_geo_input_material_index(void);
void register_node_type_geo_input_material(void);
+void register_node_type_geo_input_mesh_edge_angle(void);
void register_node_type_geo_input_mesh_edge_neighbors(void);
void register_node_type_geo_input_mesh_edge_vertices(void);
void register_node_type_geo_input_mesh_face_area(void);
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index f225b3b94b2..2246cc29dc4 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -134,12 +134,8 @@ class GeoNodeExecParams {
}
template<typename T>
- static inline constexpr bool is_field_base_type_v = std::is_same_v<T, float> ||
- std::is_same_v<T, int> ||
- std::is_same_v<T, bool> ||
- std::is_same_v<T, ColorGeometry4f> ||
- std::is_same_v<T, float3> ||
- std::is_same_v<T, std::string>;
+ static inline constexpr bool is_field_base_type_v =
+ is_same_any_v<T, float, int, bool, ColorGeometry4f, float3, std::string>;
/**
* Get the input value for the input socket with the given identifier.
diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh
index af2130ec452..113e8ffc93d 100644
--- a/source/blender/nodes/NOD_node_declaration.hh
+++ b/source/blender/nodes/NOD_node_declaration.hh
@@ -95,6 +95,7 @@ class SocketDeclaration {
bool compact_ = false;
bool is_multi_input_ = false;
bool no_mute_links_ = false;
+ bool is_unavailable_ = false;
bool is_attribute_name_ = false;
bool is_default_link_socket_ = false;
@@ -185,12 +186,23 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder {
decl_->description_ = std::move(value);
return *(Self *)this;
}
+
Self &no_muted_links(bool value = true)
{
decl_->no_mute_links_ = value;
return *(Self *)this;
}
+ /**
+ * Used for sockets that are always unavailable and should not be seen by the user.
+ * Ideally, no new calls to this method should be added over time.
+ */
+ Self &unavailable(bool value = true)
+ {
+ decl_->is_unavailable_ = value;
+ return *(Self *)this;
+ }
+
Self &is_attribute_name(bool value = true)
{
decl_->is_attribute_name_ = value;
@@ -288,10 +300,13 @@ class NodeDeclarationBuilder {
/**
* All inputs support fields, and all outputs are fields if any of the inputs is a field.
- * Calling field status definitions on each socket is unnecessary.
+ * Calling field status definitions on each socket is unnecessary. Must be called before adding
+ * any sockets.
*/
void is_function_node(bool value = true)
{
+ BLI_assert_msg(declaration_.inputs().is_empty() && declaration_.outputs().is_empty(),
+ "is_function_node() must be called before any socket is created");
declaration_.is_function_node_ = value;
}
@@ -476,6 +491,10 @@ inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(StringRef
socket_decl->name_ = name;
socket_decl->identifier_ = identifier.is_empty() ? name : identifier;
socket_decl->in_out_ = in_out;
+ if (declaration_.is_function_node()) {
+ socket_decl->input_field_type_ = InputSocketFieldType::IsSupported;
+ socket_decl->output_field_dependency_ = OutputFieldDependency::ForDependentField();
+ }
declarations.append(std::move(socket_decl));
Builder &socket_decl_builder_ref = *socket_decl_builder;
builders_.append(std::move(socket_decl_builder));
diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh
index 65789069231..ebbec20a139 100644
--- a/source/blender/nodes/NOD_node_tree_ref.hh
+++ b/source/blender/nodes/NOD_node_tree_ref.hh
@@ -262,6 +262,7 @@ class NodeTreeRef : NonCopyable, NonMovable {
Vector<LinkRef *> links_;
MultiValueMap<const bNodeType *, NodeRef *> nodes_by_type_;
Vector<std::unique_ptr<SocketIndexByIdentifierMap>> owned_identifier_maps_;
+ const NodeRef *group_output_node_ = nullptr;
public:
NodeTreeRef(bNodeTree *btree);
@@ -280,6 +281,11 @@ class NodeTreeRef : NonCopyable, NonMovable {
const NodeRef *find_node(const bNode &bnode) const;
/**
+ * This is the active group output node if there are multiple.
+ */
+ const NodeRef *group_output_node() const;
+
+ /**
* \return True when there is a link cycle. Unavailable sockets are ignored.
*/
bool has_link_cycles() const;
@@ -759,6 +765,11 @@ inline Span<const LinkRef *> NodeTreeRef::links() const
return links_;
}
+inline const NodeRef *NodeTreeRef::group_output_node() const
+{
+ return group_output_node_;
+}
+
inline bNodeTree *NodeTreeRef::btree() const
{
return btree_;
diff --git a/source/blender/nodes/NOD_socket_declarations.hh b/source/blender/nodes/NOD_socket_declarations.hh
index 3fb21a4263d..c0ba949e337 100644
--- a/source/blender/nodes/NOD_socket_declarations.hh
+++ b/source/blender/nodes/NOD_socket_declarations.hh
@@ -231,7 +231,7 @@ class Shader : public SocketDeclaration {
bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
bool matches(const bNodeSocket &socket) const override;
- bool can_connect(const bNodeSocket &socket) const;
+ bool can_connect(const bNodeSocket &socket) const override;
};
class ShaderBuilder : public SocketDeclarationBuilder<Shader> {
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 84bc7bf0ceb..74f1531bd90 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -323,9 +323,9 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, 0, "LEGACY_SELECT_BY_M
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_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC", AttributeStatistic, "Attribute Statistic", "")
-DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "")
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "")
DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture, "CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "")
DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "")
@@ -333,7 +333,6 @@ DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Conve
DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINT_SELECTION, 0, "CURVE_ENDPOINT_SELECTION", CurveEndpointSelection, "Endpoint Selection", "")
DefNode(GeometryNode, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, def_geo_curve_handle_type_selection, "CURVE_HANDLE_TYPE_SELECTION", CurveHandleTypeSelection, "Handle Type Selection", "")
DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Curve Length", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_PARAMETER, 0, "SPLINE_PARAMETER", SplineParameter, "Spline Parameter", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Curve Circle", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_LINE, def_geo_curve_primitive_line, "CURVE_PRIMITIVE_LINE", CurvePrimitiveLine, "Curve Line", "")
@@ -342,11 +341,13 @@ DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, def_geo_curve_prim
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, 0, "CURVE_PRIMITIVE_SPIRAL", CurveSpiral, "Curve Spiral", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_STAR, 0, "CURVE_PRIMITIVE_STAR", CurveStar, "Star", "")
DefNode(GeometryNode, GEO_NODE_CURVE_SET_HANDLES, def_geo_curve_set_handles, "CURVE_SET_HANDLES", CurveSetHandles, "Set Handle Type", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_PARAMETER, 0, "SPLINE_PARAMETER", SplineParameter, "Spline Parameter", "")
DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_TYPE, def_geo_curve_spline_type, "CURVE_SPLINE_TYPE", CurveSplineType, "Set Spline Type", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "")
DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, def_geo_delete_geometry, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "")
DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, def_geo_distribute_points_on_faces, "DISTRIBUTE_POINTS_ON_FACES", DistributePointsOnFaces, "Distribute Points on Faces", "")
+DefNode(GeometryNode, GEO_NODE_ACCUMULATE_FIELD, def_geo_accumulate_field, "ACCUMULATE_FIELD", AccumulateField, "Accumulate Field", "")
DefNode(GeometryNode, GEO_NODE_DUAL_MESH, 0, "DUAL_MESH", DualMesh, "Dual Mesh", "")
DefNode(GeometryNode, GEO_NODE_FILL_CURVE, def_geo_curve_fill, "FILL_CURVE", FillCurve, "Fill Curve", "")
DefNode(GeometryNode, GEO_NODE_FILLET_CURVE, def_geo_curve_fillet, "FILLET_CURVE", FilletCurve, "Fillet Curve", "")
@@ -358,6 +359,7 @@ DefNode(GeometryNode, GEO_NODE_INPUT_ID, 0, "INPUT_ID", InputID, "ID", "")
DefNode(GeometryNode, GEO_NODE_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL_INDEX, 0, "INPUT_MATERIAL_INDEX", InputMaterialIndex, "Material Index", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "")
+DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_ANGLE, 0, "MESH_EDGE_ANGLE", InputMeshEdgeAngle, "Edge Angle", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, 0, "MESH_EDGE_NEIGHBORS", InputMeshEdgeNeighbors, "Edge Neighbors", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_VERTICES, 0, "MESH_EDGE_VERTICES", InputMeshEdgeVertices, "Edge Vertices", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_AREA, 0, "MESH_FACE_AREA", InputMeshFaceArea, "Face Area", "")
diff --git a/source/blender/nodes/composite/CMakeLists.txt b/source/blender/nodes/composite/CMakeLists.txt
new file mode 100644
index 00000000000..e9fc24bbbee
--- /dev/null
+++ b/source/blender/nodes/composite/CMakeLists.txt
@@ -0,0 +1,150 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2021, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ../
+ ../intern
+ ../../editors/include
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../depsgraph
+ ../../imbuf
+ ../../makesdna
+ ../../makesrna
+ ../../render
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+)
+
+
+set(SRC
+ nodes/node_composite_alphaOver.cc
+ nodes/node_composite_antialiasing.cc
+ nodes/node_composite_bilateralblur.cc
+ nodes/node_composite_blur.cc
+ nodes/node_composite_bokehblur.cc
+ nodes/node_composite_bokehimage.cc
+ nodes/node_composite_boxmask.cc
+ nodes/node_composite_brightness.cc
+ nodes/node_composite_channelMatte.cc
+ nodes/node_composite_chromaMatte.cc
+ nodes/node_composite_colorMatte.cc
+ nodes/node_composite_colorSpill.cc
+ nodes/node_composite_colorbalance.cc
+ nodes/node_composite_colorcorrection.cc
+ nodes/node_composite_common.cc
+ nodes/node_composite_composite.cc
+ nodes/node_composite_cornerpin.cc
+ nodes/node_composite_crop.cc
+ nodes/node_composite_cryptomatte.cc
+ nodes/node_composite_curves.cc
+ nodes/node_composite_defocus.cc
+ nodes/node_composite_denoise.cc
+ nodes/node_composite_despeckle.cc
+ nodes/node_composite_diffMatte.cc
+ nodes/node_composite_dilate.cc
+ nodes/node_composite_directionalblur.cc
+ nodes/node_composite_displace.cc
+ nodes/node_composite_distanceMatte.cc
+ nodes/node_composite_doubleEdgeMask.cc
+ nodes/node_composite_ellipsemask.cc
+ nodes/node_composite_exposure.cc
+ nodes/node_composite_filter.cc
+ nodes/node_composite_flip.cc
+ nodes/node_composite_gamma.cc
+ nodes/node_composite_glare.cc
+ nodes/node_composite_hueSatVal.cc
+ nodes/node_composite_huecorrect.cc
+ nodes/node_composite_idMask.cc
+ nodes/node_composite_image.cc
+ nodes/node_composite_inpaint.cc
+ nodes/node_composite_invert.cc
+ nodes/node_composite_keying.cc
+ nodes/node_composite_keyingscreen.cc
+ nodes/node_composite_lensdist.cc
+ nodes/node_composite_levels.cc
+ nodes/node_composite_lummaMatte.cc
+ nodes/node_composite_mapRange.cc
+ nodes/node_composite_mapUV.cc
+ nodes/node_composite_mapValue.cc
+ nodes/node_composite_mask.cc
+ nodes/node_composite_math.cc
+ nodes/node_composite_mixrgb.cc
+ nodes/node_composite_movieclip.cc
+ nodes/node_composite_moviedistortion.cc
+ nodes/node_composite_normal.cc
+ nodes/node_composite_normalize.cc
+ nodes/node_composite_outputFile.cc
+ nodes/node_composite_pixelate.cc
+ nodes/node_composite_planetrackdeform.cc
+ nodes/node_composite_posterize.cc
+ nodes/node_composite_premulkey.cc
+ nodes/node_composite_rgb.cc
+ nodes/node_composite_rotate.cc
+ nodes/node_composite_scale.cc
+ nodes/node_composite_sepcombHSVA.cc
+ nodes/node_composite_sepcombRGBA.cc
+ nodes/node_composite_sepcombYCCA.cc
+ nodes/node_composite_sepcombYUVA.cc
+ nodes/node_composite_setalpha.cc
+ nodes/node_composite_splitViewer.cc
+ nodes/node_composite_stabilize2d.cc
+ nodes/node_composite_sunbeams.cc
+ nodes/node_composite_switch.cc
+ nodes/node_composite_switchview.cc
+ nodes/node_composite_texture.cc
+ nodes/node_composite_tonemap.cc
+ nodes/node_composite_trackpos.cc
+ nodes/node_composite_transform.cc
+ nodes/node_composite_translate.cc
+ nodes/node_composite_valToRgb.cc
+ nodes/node_composite_value.cc
+ nodes/node_composite_vecBlur.cc
+ nodes/node_composite_viewer.cc
+ nodes/node_composite_zcombine.cc
+
+ node_composite_tree.cc
+ node_composite_util.cc
+
+ node_composite_util.hh
+)
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+if(WITH_IMAGE_OPENEXR)
+ add_definitions(-DWITH_OPENEXR)
+endif()
+
+if(WITH_COMPOSITOR)
+ list(APPEND INC
+ ../../compositor
+ )
+ add_definitions(-DWITH_COMPOSITOR)
+endif()
+
+if(WITH_OPENIMAGEDENOISE)
+ add_definitions(-DWITH_OPENIMAGEDENOISE)
+endif()
+
+blender_add_lib(bf_nodes_composite "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc
index 1326c9edab1..08dbd4ad6f0 100644
--- a/source/blender/nodes/composite/node_composite_tree.cc
+++ b/source/blender/nodes/composite/node_composite_tree.cc
@@ -33,8 +33,11 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_tracking.h"
+#include "UI_resources.h"
+
#include "node_common.h"
#include "node_util.h"
@@ -117,29 +120,11 @@ static void localize(bNodeTree *localtree, bNodeTree *ntree)
}
}
- bNodeSocket *output_sock = (bNodeSocket *)node->outputs.first;
- bNodeSocket *local_output_sock = (bNodeSocket *)local_node->outputs.first;
- while (output_sock != nullptr) {
- local_output_sock->cache = output_sock->cache;
- output_sock->cache = nullptr;
- /* This is actually link to original: someone was just lazy enough and tried to save few
- * bytes in the cost of readability. */
- local_output_sock->new_sock = output_sock;
-
- output_sock = output_sock->next;
- local_output_sock = local_output_sock->next;
- }
-
node = node->next;
local_node = local_node->next;
}
}
-static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_sync_tree(ntree, localtree);
-}
-
static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
{
bNode *lnode;
@@ -149,11 +134,11 @@ static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
BKE_node_preview_merge_tree(ntree, localtree, true);
for (lnode = (bNode *)localtree->nodes.first; lnode; lnode = lnode->next) {
- if (ntreeNodeExists(ntree, lnode->new_node)) {
+ if (bNode *orig_node = nodeFindNodebyName(ntree, lnode->name)) {
if (ELEM(lnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
if (lnode->id && (lnode->flag & NODE_DO_OUTPUT)) {
/* image_merge does sanity check for pointers */
- BKE_image_merge(bmain, (Image *)lnode->new_node->id, (Image *)lnode->id);
+ BKE_image_merge(bmain, (Image *)orig_node->id, (Image *)lnode->id);
}
}
else if (lnode->type == CMP_NODE_MOVIEDISTORTION) {
@@ -161,20 +146,19 @@ static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree)
* and to achieve much better performance on further calls this context should be
* copied back to original node */
if (lnode->storage) {
- if (lnode->new_node->storage) {
- BKE_tracking_distortion_free((MovieDistortion *)lnode->new_node->storage);
+ if (orig_node->storage) {
+ BKE_tracking_distortion_free((MovieDistortion *)orig_node->storage);
}
- lnode->new_node->storage = BKE_tracking_distortion_copy(
- (MovieDistortion *)lnode->storage);
+ orig_node->storage = BKE_tracking_distortion_copy((MovieDistortion *)lnode->storage);
}
}
for (lsock = (bNodeSocket *)lnode->outputs.first; lsock; lsock = lsock->next) {
- if (ntreeOutputExists(lnode->new_node, lsock->new_sock)) {
- lsock->new_sock->cache = lsock->cache;
+ if (bNodeSocket *orig_socket = nodeFindSocket(orig_node, SOCK_OUT, lsock->identifier)) {
+ orig_socket->cache = lsock->cache;
lsock->cache = nullptr;
- lsock->new_sock = nullptr;
+ orig_socket = nullptr;
}
}
}
@@ -186,11 +170,6 @@ static void update(bNodeTree *ntree)
ntreeSetOutput(ntree);
ntree_update_reroute_nodes(ntree);
-
- if (ntree->update & NTREE_UPDATE_NODES) {
- /* clean up preview cache, in case nodes have been removed */
- BKE_node_preview_remove_unused(ntree);
- }
}
static void composite_node_add_init(bNodeTree *UNUSED(bnodetree), bNode *bnode)
@@ -214,20 +193,18 @@ bNodeTreeType *ntreeType_Composite;
void register_node_tree_type_cmp()
{
- bNodeTreeType *tt = ntreeType_Composite = (bNodeTreeType *)MEM_callocN(
- sizeof(bNodeTreeType), "compositor node tree type");
+ bNodeTreeType *tt = ntreeType_Composite = MEM_cnew<bNodeTreeType>(__func__);
tt->type = NTREE_COMPOSIT;
strcpy(tt->idname, "CompositorNodeTree");
strcpy(tt->ui_name, N_("Compositor"));
- tt->ui_icon = 0; /* Defined in `drawnode.c`. */
+ tt->ui_icon = ICON_NODE_COMPOSITING;
strcpy(tt->ui_description, N_("Compositing nodes"));
tt->free_cache = free_cache;
tt->free_node_cache = free_node_cache;
tt->foreach_nodeclass = foreach_nodeclass;
tt->localize = localize;
- tt->local_sync = local_sync;
tt->local_merge = local_merge;
tt->update = update;
tt->get_from_context = composite_get_from_context;
@@ -301,14 +278,15 @@ void ntreeCompositTagRender(Scene *scene)
if (sce_iter->nodetree) {
LISTBASE_FOREACH (bNode *, node, &sce_iter->nodetree->nodes) {
if (node->id == (ID *)scene || node->type == CMP_NODE_COMPOSITE) {
- nodeUpdate(sce_iter->nodetree, node);
+ BKE_ntree_update_tag_node_property(sce_iter->nodetree, node);
}
else if (node->type == CMP_NODE_TEXTURE) /* uses scene size_x/size_y */ {
- nodeUpdate(sce_iter->nodetree, node);
+ BKE_ntree_update_tag_node_property(sce_iter->nodetree, node);
}
}
}
}
+ BKE_ntree_update_main(G_MAIN, nullptr);
}
/* XXX after render animation system gets a refresh, this call allows composite to end clean */
diff --git a/source/blender/nodes/composite/node_composite_util.cc b/source/blender/nodes/composite/node_composite_util.cc
index 1262dfad11f..1f892c1c9e2 100644
--- a/source/blender/nodes/composite/node_composite_util.cc
+++ b/source/blender/nodes/composite/node_composite_util.cc
@@ -47,9 +47,9 @@ void cmp_node_update_default(bNodeTree *UNUSED(ntree), bNode *node)
node->need_exec = 1;
}
-void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = cmp_node_poll_default;
ntype->updatefunc = cmp_node_update_default;
diff --git a/source/blender/nodes/composite/node_composite_util.hh b/source/blender/nodes/composite/node_composite_util.hh
index 04708d0d854..65dbc2065ef 100644
--- a/source/blender/nodes/composite/node_composite_util.hh
+++ b/source/blender/nodes/composite/node_composite_util.hh
@@ -52,5 +52,4 @@ bool cmp_node_poll_default(struct bNodeType *ntype,
struct bNodeTree *ntree,
const char **r_disabled_hint);
void cmp_node_update_default(struct bNodeTree *ntree, struct bNode *node);
-void cmp_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void cmp_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
diff --git a/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc b/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc
index 5e6d59edfd5..82ef5df8403 100644
--- a/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc
@@ -42,7 +42,7 @@ static void cmp_node_alphaover_declare(NodeDeclarationBuilder &b)
static void node_alphaover_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- node->storage = MEM_callocN(sizeof(NodeTwoFloats), "NodeTwoFloats");
+ node->storage = MEM_cnew<NodeTwoFloats>(__func__);
}
static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -58,7 +58,7 @@ void register_node_type_cmp_alphaover()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_ALPHAOVER, "Alpha Over", NODE_CLASS_OP_COLOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_ALPHAOVER, "Alpha Over", NODE_CLASS_OP_COLOR);
ntype.declare = blender::nodes::cmp_node_alphaover_declare;
ntype.draw_buttons = node_composit_buts_alphaover;
node_type_init(&ntype, node_alphaover_init);
diff --git a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
index 02b2652ed6a..b42b219ced9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc
@@ -42,8 +42,7 @@ static void cmp_node_antialiasing_declare(NodeDeclarationBuilder &b)
static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAntiAliasingData *data = (NodeAntiAliasingData *)MEM_callocN(sizeof(NodeAntiAliasingData),
- "node antialiasing data");
+ NodeAntiAliasingData *data = MEM_cnew<NodeAntiAliasingData>(__func__);
data->threshold = CMP_DEFAULT_SMAA_THRESHOLD;
data->contrast_limit = CMP_DEFAULT_SMAA_CONTRAST_LIMIT;
@@ -67,10 +66,10 @@ void register_node_type_cmp_antialiasing()
{
static bNodeType ntype;
- cmp_node_type_base(
- &ntype, CMP_NODE_ANTIALIASING, "Anti-Aliasing", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_ANTIALIASING, "Anti-Aliasing", NODE_CLASS_OP_FILTER);
ntype.declare = blender::nodes::cmp_node_antialiasing_declare;
ntype.draw_buttons = node_composit_buts_antialiasing;
+ ntype.flag |= NODE_PREVIEW;
node_type_size(&ntype, 170, 140, 200);
node_type_init(&ntype, node_composit_init_antialiasing);
node_type_storage(
diff --git a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
index 3f107a13a44..2b4030935a0 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc
@@ -41,8 +41,7 @@ static void cmp_node_bilateralblur_declare(NodeDeclarationBuilder &b)
static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBilateralBlurData *nbbd = (NodeBilateralBlurData *)MEM_callocN(sizeof(NodeBilateralBlurData),
- "node bilateral blur data");
+ NodeBilateralBlurData *nbbd = MEM_cnew<NodeBilateralBlurData>(__func__);
node->storage = nbbd;
nbbd->iter = 1;
nbbd->sigma_color = 0.3;
@@ -65,7 +64,7 @@ void register_node_type_cmp_bilateralblur()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_BILATERALBLUR, "Bilateral Blur", NODE_CLASS_OP_FILTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_BILATERALBLUR, "Bilateral Blur", NODE_CLASS_OP_FILTER);
ntype.declare = blender::nodes::cmp_node_bilateralblur_declare;
ntype.draw_buttons = node_composit_buts_bilateralblur;
node_type_init(&ntype, node_composit_init_bilateralblur);
diff --git a/source/blender/nodes/composite/nodes/node_composite_blur.cc b/source/blender/nodes/composite/nodes/node_composite_blur.cc
index bcc8c786ae5..b7904ffdafe 100644
--- a/source/blender/nodes/composite/nodes/node_composite_blur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_blur.cc
@@ -44,7 +44,7 @@ static void cmp_node_blur_declare(NodeDeclarationBuilder &b)
static void node_composit_init_blur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBlurData *data = (NodeBlurData *)MEM_callocN(sizeof(NodeBlurData), "node blur data");
+ NodeBlurData *data = MEM_cnew<NodeBlurData>(__func__);
data->filtertype = R_FILTER_GAUSS;
node->storage = data;
}
@@ -94,9 +94,10 @@ void register_node_type_cmp_blur()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_BLUR, "Blur", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_BLUR, "Blur", NODE_CLASS_OP_FILTER);
ntype.declare = blender::nodes::cmp_node_blur_declare;
ntype.draw_buttons = node_composit_buts_blur;
+ ntype.flag |= NODE_PREVIEW;
node_type_init(&ntype, node_composit_init_blur);
node_type_storage(
&ntype, "NodeBlurData", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
index d0659f6a51e..bffaceee067 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
@@ -25,7 +25,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
-#include "../node_composite_util.hh"
+#include "node_composite_util.hh"
/* **************** BLUR ******************** */
@@ -60,7 +60,7 @@ void register_node_type_cmp_bokehblur()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER);
ntype.declare = blender::nodes::cmp_node_bokehblur_declare;
ntype.draw_buttons = node_composit_buts_bokehblur;
node_type_init(&ntype, node_composit_init_bokehblur);
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
index 8817a07a422..93a00cb210d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
@@ -24,7 +24,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
-#include "../node_composite_util.hh"
+#include "node_composite_util.hh"
/* **************** Bokeh image Tools ******************** */
@@ -39,7 +39,7 @@ static void cmp_node_bokehimage_declare(NodeDeclarationBuilder &b)
static void node_composit_init_bokehimage(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBokehImage *data = (NodeBokehImage *)MEM_callocN(sizeof(NodeBokehImage), "NodeBokehImage");
+ NodeBokehImage *data = MEM_cnew<NodeBokehImage>(__func__);
data->angle = 0.0f;
data->flaps = 5;
data->rounding = 0.0f;
@@ -67,9 +67,10 @@ void register_node_type_cmp_bokehimage()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_BOKEHIMAGE, "Bokeh Image", NODE_CLASS_INPUT, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_BOKEHIMAGE, "Bokeh Image", NODE_CLASS_INPUT);
ntype.declare = blender::nodes::cmp_node_bokehimage_declare;
ntype.draw_buttons = node_composit_buts_bokehimage;
+ ntype.flag |= NODE_PREVIEW;
node_type_init(&ntype, node_composit_init_bokehimage);
node_type_storage(
&ntype, "NodeBokehImage", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
index 40859922154..68c79d89435 100644
--- a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc
@@ -24,7 +24,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
-#include "../node_composite_util.hh"
+#include "node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
@@ -41,7 +41,7 @@ static void cmp_node_boxmask_declare(NodeDeclarationBuilder &b)
static void node_composit_init_boxmask(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBoxMask *data = (NodeBoxMask *)MEM_callocN(sizeof(NodeBoxMask), "NodeBoxMask");
+ NodeBoxMask *data = MEM_cnew<NodeBoxMask>(__func__);
data->x = 0.5;
data->y = 0.5;
data->width = 0.2;
@@ -70,7 +70,7 @@ void register_node_type_cmp_boxmask()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MASK_BOX, "Box Mask", NODE_CLASS_MATTE, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_MASK_BOX, "Box Mask", NODE_CLASS_MATTE);
ntype.declare = blender::nodes::cmp_node_boxmask_declare;
ntype.draw_buttons = node_composit_buts_boxmask;
node_type_init(&ntype, node_composit_init_boxmask);
diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.cc b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
index ca03a9b4fbf..ea1684a6ca7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_brightness.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_brightness.cc
@@ -56,7 +56,7 @@ void register_node_type_cmp_brightcontrast()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR);
ntype.declare = blender::nodes::cmp_node_brightcontrast_declare;
ntype.draw_buttons = node_composit_buts_brightcontrast;
node_type_init(&ntype, node_composit_init_brightcontrast);
diff --git a/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc b/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc
index 1b4be78c71b..9d3bc97f2dc 100644
--- a/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc
@@ -43,7 +43,7 @@ static void cmp_node_channel_matte_declare(NodeDeclarationBuilder &b)
static void node_composit_init_channel_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
node->storage = c;
c->t1 = 1.0f;
c->t2 = 0.0f;
@@ -101,10 +101,10 @@ void register_node_type_cmp_channel_matte()
{
static bNodeType ntype;
- cmp_node_type_base(
- &ntype, CMP_NODE_CHANNEL_MATTE, "Channel Key", NODE_CLASS_MATTE, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_CHANNEL_MATTE, "Channel Key", NODE_CLASS_MATTE);
ntype.declare = blender::nodes::cmp_node_channel_matte_declare;
ntype.draw_buttons = node_composit_buts_channel_matte;
+ ntype.flag |= NODE_PREVIEW;
node_type_init(&ntype, node_composit_init_channel_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc
index a7e3a1c148f..be27f747af0 100644
--- a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc
@@ -42,7 +42,7 @@ static void cmp_node_chroma_matte_declare(NodeDeclarationBuilder &b)
static void node_composit_init_chroma_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
node->storage = c;
c->t1 = DEG2RADF(30.0f);
c->t2 = DEG2RADF(10.0f);
@@ -71,9 +71,10 @@ void register_node_type_cmp_chroma_matte()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CHROMA_MATTE, "Chroma Key", NODE_CLASS_MATTE, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_CHROMA_MATTE, "Chroma Key", NODE_CLASS_MATTE);
ntype.declare = blender::nodes::cmp_node_chroma_matte_declare;
ntype.draw_buttons = node_composit_buts_chroma_matte;
+ ntype.flag |= NODE_PREVIEW;
node_type_init(&ntype, node_composit_init_chroma_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc b/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc
index 367b046f3f6..58040c2076b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc
@@ -42,7 +42,7 @@ static void cmp_node_color_matte_declare(NodeDeclarationBuilder &b)
static void node_composit_init_color_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node color");
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
node->storage = c;
c->t1 = 0.01f;
c->t2 = 0.1f;
@@ -72,9 +72,10 @@ void register_node_type_cmp_color_matte()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COLOR_MATTE, "Color Key", NODE_CLASS_MATTE, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_COLOR_MATTE, "Color Key", NODE_CLASS_MATTE);
ntype.declare = blender::nodes::cmp_node_color_matte_declare;
ntype.draw_buttons = node_composit_buts_color_matte;
+ ntype.flag |= NODE_PREVIEW;
node_type_init(&ntype, node_composit_init_color_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc b/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
index e136041cf6e..187b1dfdfc5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc
@@ -43,7 +43,7 @@ static void cmp_node_color_spill_declare(NodeDeclarationBuilder &b)
static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeColorspill *ncs = (NodeColorspill *)MEM_callocN(sizeof(NodeColorspill), "node colorspill");
+ NodeColorspill *ncs = MEM_cnew<NodeColorspill>(__func__);
node->storage = ncs;
node->custom1 = 2; /* green channel */
node->custom2 = 0; /* simple limit algorithm */
@@ -102,7 +102,7 @@ void register_node_type_cmp_color_spill()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COLOR_SPILL, "Color Spill", NODE_CLASS_MATTE, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_COLOR_SPILL, "Color Spill", NODE_CLASS_MATTE);
ntype.declare = blender::nodes::cmp_node_color_spill_declare;
ntype.draw_buttons = node_composit_buts_color_spill;
node_type_init(&ntype, node_composit_init_color_spill);
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
index a35b3d813e6..bddd702bcca 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc
@@ -71,8 +71,7 @@ void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *UNUSED(ntree), bNode *node)
static void node_composit_init_colorbalance(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeColorBalance *n = (NodeColorBalance *)MEM_callocN(sizeof(NodeColorBalance),
- "node colorbalance");
+ NodeColorBalance *n = MEM_cnew<NodeColorBalance>(__func__);
n->lift[0] = n->lift[1] = n->lift[2] = 1.0f;
n->gamma[0] = n->gamma[1] = n->gamma[2] = 1.0f;
@@ -162,7 +161,7 @@ void register_node_type_cmp_colorbalance()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR);
ntype.declare = blender::nodes::cmp_node_colorbalance_declare;
ntype.draw_buttons = node_composit_buts_colorbalance;
ntype.draw_buttons_ex = node_composit_buts_colorbalance_ex;
diff --git a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
index e3bba3b6c4f..16d1ad90757 100644
--- a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc
@@ -41,8 +41,7 @@ static void cmp_node_colorcorrection_declare(NodeDeclarationBuilder &b)
static void node_composit_init_colorcorrection(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeColorCorrection *n = (NodeColorCorrection *)MEM_callocN(sizeof(NodeColorCorrection),
- "node colorcorrection");
+ NodeColorCorrection *n = MEM_cnew<NodeColorCorrection>(__func__);
n->startmidtones = 0.2f;
n->endmidtones = 0.7f;
n->master.contrast = 1.0f;
@@ -289,7 +288,7 @@ void register_node_type_cmp_colorcorrection()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COLORCORRECTION, "Color Correction", NODE_CLASS_OP_COLOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_COLORCORRECTION, "Color Correction", NODE_CLASS_OP_COLOR);
ntype.declare = blender::nodes::cmp_node_colorcorrection_declare;
ntype.draw_buttons = node_composit_buts_colorcorrection;
ntype.draw_buttons_ex = node_composit_buts_colorcorrection_ex;
diff --git a/source/blender/nodes/composite/nodes/node_composite_common.cc b/source/blender/nodes/composite/nodes/node_composite_common.cc
index aa81cecc3e2..36678baafa5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_common.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_common.cc
@@ -38,7 +38,7 @@ void register_node_type_cmp_group()
/* NOTE: Cannot use sh_node_type_base for node group, because it would map the node type
* to the shared NODE_GROUP integer type id. */
- node_type_base_custom(&ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP, 0);
+ node_type_base_custom(&ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP);
ntype.type = NODE_GROUP;
ntype.poll = cmp_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.cc b/source/blender/nodes/composite/nodes/node_composite_composite.cc
index 547e5123579..5f694d0738e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_composite.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_composite.cc
@@ -48,9 +48,10 @@ void register_node_type_cmp_composite()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT);
ntype.declare = blender::nodes::cmp_node_composite_declare;
ntype.draw_buttons = node_composit_buts_composite;
+ ntype.flag |= NODE_PREVIEW;
ntype.no_muting = true;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
index 2e7a87a576d..2bd188e4182 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc
@@ -54,7 +54,7 @@ void register_node_type_cmp_cornerpin()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT);
ntype.declare = blender::nodes::cmp_node_cornerpin_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_crop.cc b/source/blender/nodes/composite/nodes/node_composite_crop.cc
index fa33caa4c0e..2969e0564b1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_crop.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_crop.cc
@@ -42,7 +42,7 @@ static void cmp_node_crop_declare(NodeDeclarationBuilder &b)
static void node_composit_init_crop(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTwoXYs *nxy = (NodeTwoXYs *)MEM_callocN(sizeof(NodeTwoXYs), "node xy data");
+ NodeTwoXYs *nxy = MEM_cnew<NodeTwoXYs>(__func__);
node->storage = nxy;
nxy->x1 = 0;
nxy->x2 = 0;
@@ -76,7 +76,7 @@ void register_node_type_cmp_crop()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CROP, "Crop", NODE_CLASS_DISTORT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_CROP, "Crop", NODE_CLASS_DISTORT);
ntype.declare = blender::nodes::cmp_node_crop_declare;
ntype.draw_buttons = node_composit_buts_crop;
node_type_init(&ntype, node_composit_init_crop);
diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
index 65b1f6799d7..c059a2883f6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc
@@ -136,8 +136,7 @@ static void cryptomatte_add(const Scene &scene,
return;
}
- CryptomatteEntry *entry = static_cast<CryptomatteEntry *>(
- MEM_callocN(sizeof(CryptomatteEntry), __func__));
+ CryptomatteEntry *entry = MEM_cnew<CryptomatteEntry>(__func__);
entry->encoded_hash = encoded_hash;
blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node(
scene, node, true);
@@ -199,8 +198,7 @@ void ntreeCompositCryptomatteUpdateLayerNames(const Scene *scene, bNode *node)
if (session) {
for (blender::StringRef layer_name :
blender::bke::cryptomatte::BKE_cryptomatte_layer_names_get(*session)) {
- CryptomatteLayer *layer = static_cast<CryptomatteLayer *>(
- MEM_callocN(sizeof(CryptomatteLayer), __func__));
+ CryptomatteLayer *layer = MEM_cnew<CryptomatteLayer>(__func__);
layer_name.copy(layer->name);
BLI_addtail(&n->runtime.layers, layer);
}
@@ -245,8 +243,7 @@ CryptomatteSession *ntreeCompositCryptomatteSession(const Scene *scene, bNode *n
static void node_init_cryptomatte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeCryptomatte *user = static_cast<NodeCryptomatte *>(
- MEM_callocN(sizeof(NodeCryptomatte), __func__));
+ NodeCryptomatte *user = MEM_cnew<NodeCryptomatte>(__func__);
node->storage = user;
}
@@ -312,7 +309,7 @@ void register_node_type_cmp_cryptomatte()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_MATTE, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_MATTE);
node_type_socket_templates(&ntype, cmp_node_cryptomatte_in, cmp_node_cryptomatte_out);
node_type_size(&ntype, 240, 100, 700);
node_type_init(&ntype, node_init_cryptomatte);
@@ -369,7 +366,7 @@ void register_node_type_cmp_cryptomatte_legacy()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte", NODE_CLASS_MATTE, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte", NODE_CLASS_MATTE);
node_type_socket_templates(&ntype, nullptr, cmp_node_cryptomatte_out);
node_type_init(&ntype, node_init_cryptomatte_legacy);
node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte);
diff --git a/source/blender/nodes/composite/nodes/node_composite_curves.cc b/source/blender/nodes/composite/nodes/node_composite_curves.cc
index 518b57dc405..6be8a04a6e1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_curves.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_curves.cc
@@ -49,9 +49,9 @@ void register_node_type_cmp_curve_time()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TIME, "Time", NODE_CLASS_INPUT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_TIME, "Time", NODE_CLASS_INPUT);
ntype.declare = blender::nodes::cmp_node_time_declare;
- node_type_size(&ntype, 140, 100, 320);
+ node_type_size(&ntype, 200, 140, 320);
node_type_init(&ntype, node_composit_init_curves_time);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
@@ -84,7 +84,7 @@ void register_node_type_cmp_curve_vec()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR);
ntype.declare = blender::nodes::cmp_node_curve_vec_declare;
ntype.draw_buttons = node_buts_curvevec;
node_type_size(&ntype, 200, 140, 320);
@@ -119,7 +119,7 @@ void register_node_type_cmp_curve_rgb()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR);
ntype.declare = blender::nodes::cmp_node_rgbcurves_declare;
node_type_size(&ntype, 200, 140, 320);
node_type_init(&ntype, node_composit_init_curve_rgb);
diff --git a/source/blender/nodes/composite/nodes/node_composite_defocus.cc b/source/blender/nodes/composite/nodes/node_composite_defocus.cc
index 0ee8a8da1e8..cfe377f72f1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_defocus.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_defocus.cc
@@ -46,7 +46,7 @@ static void cmp_node_defocus_declare(NodeDeclarationBuilder &b)
static void node_composit_init_defocus(bNodeTree *UNUSED(ntree), bNode *node)
{
/* defocus node */
- NodeDefocus *nbd = (NodeDefocus *)MEM_callocN(sizeof(NodeDefocus), "node defocus data");
+ NodeDefocus *nbd = MEM_cnew<NodeDefocus>(__func__);
nbd->bktype = 0;
nbd->rotation = 0.0f;
nbd->preview = 1;
@@ -103,7 +103,7 @@ void register_node_type_cmp_defocus()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DEFOCUS, "Defocus", NODE_CLASS_OP_FILTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_DEFOCUS, "Defocus", NODE_CLASS_OP_FILTER);
ntype.declare = blender::nodes::cmp_node_defocus_declare;
ntype.draw_buttons = node_composit_buts_defocus;
node_type_init(&ntype, node_composit_init_defocus);
diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.cc b/source/blender/nodes/composite/nodes/node_composite_denoise.cc
index f1e5388a7a3..8dce28b4ac0 100644
--- a/source/blender/nodes/composite/nodes/node_composite_denoise.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_denoise.cc
@@ -23,6 +23,8 @@
* \ingroup cmpnodes
*/
+#include "BLI_system.h"
+
#include "UI_interface.h"
#include "UI_resources.h"
@@ -46,7 +48,7 @@ static void cmp_node_denoise_declare(NodeDeclarationBuilder &b)
static void node_composit_init_denonise(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeDenoise *ndg = (NodeDenoise *)MEM_callocN(sizeof(NodeDenoise), "node denoise data");
+ NodeDenoise *ndg = MEM_cnew<NodeDenoise>(__func__);
ndg->hdr = true;
ndg->prefilter = CMP_NODE_DENOISE_PREFILTER_ACCURATE;
node->storage = ndg;
@@ -74,7 +76,7 @@ void register_node_type_cmp_denoise()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DENOISE, "Denoise", NODE_CLASS_OP_FILTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_DENOISE, "Denoise", NODE_CLASS_OP_FILTER);
ntype.declare = blender::nodes::cmp_node_denoise_declare;
ntype.draw_buttons = node_composit_buts_denoise;
node_type_init(&ntype, node_composit_init_denonise);
diff --git a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
index 411bad14f25..3555bd6a693 100644
--- a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc
@@ -58,9 +58,10 @@ void register_node_type_cmp_despeckle()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DESPECKLE, "Despeckle", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_DESPECKLE, "Despeckle", NODE_CLASS_OP_FILTER);
ntype.declare = blender::nodes::cmp_node_despeckle_declare;
ntype.draw_buttons = node_composit_buts_despeckle;
+ ntype.flag |= NODE_PREVIEW;
node_type_init(&ntype, node_composit_init_despeckle);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc b/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc
index a9e3258c8fb..2bc171161be 100644
--- a/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc
@@ -42,7 +42,7 @@ static void cmp_node_diff_matte_declare(NodeDeclarationBuilder &b)
static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
node->storage = c;
c->t1 = 0.1f;
c->t2 = 0.1f;
@@ -62,10 +62,10 @@ void register_node_type_cmp_diff_matte()
{
static bNodeType ntype;
- cmp_node_type_base(
- &ntype, CMP_NODE_DIFF_MATTE, "Difference Key", NODE_CLASS_MATTE, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_DIFF_MATTE, "Difference Key", NODE_CLASS_MATTE);
ntype.declare = blender::nodes::cmp_node_diff_matte_declare;
ntype.draw_buttons = node_composit_buts_diff_matte;
+ ntype.flag |= NODE_PREVIEW;
node_type_init(&ntype, node_composit_init_diff_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_dilate.cc b/source/blender/nodes/composite/nodes/node_composite_dilate.cc
index 1af2bb0433b..867fc7f828f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_dilate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_dilate.cc
@@ -42,8 +42,7 @@ static void cmp_node_dilate_declare(NodeDeclarationBuilder &b)
static void node_composit_init_dilateerode(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeDilateErode *data = (NodeDilateErode *)MEM_callocN(sizeof(NodeDilateErode),
- "NodeDilateErode");
+ NodeDilateErode *data = MEM_cnew<NodeDilateErode>(__func__);
data->falloff = PROP_SMOOTH;
node->storage = data;
}
@@ -66,7 +65,7 @@ void register_node_type_cmp_dilateerode()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER);
ntype.draw_buttons = node_composit_buts_dilateerode;
ntype.declare = blender::nodes::cmp_node_dilate_declare;
node_type_init(&ntype, node_composit_init_dilateerode);
diff --git a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
index 36b130d55a4..8f39a25cf77 100644
--- a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc
@@ -38,7 +38,7 @@ static void cmp_node_directional_blur_declare(NodeDeclarationBuilder &b)
static void node_composit_init_dblur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeDBlurData *ndbd = (NodeDBlurData *)MEM_callocN(sizeof(NodeDBlurData), "node dblur data");
+ NodeDBlurData *ndbd = MEM_cnew<NodeDBlurData>(__func__);
node->storage = ndbd;
ndbd->iter = 1;
ndbd->center_x = 0.5;
@@ -73,7 +73,7 @@ void register_node_type_cmp_dblur()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DBLUR, "Directional Blur", NODE_CLASS_OP_FILTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_DBLUR, "Directional Blur", NODE_CLASS_OP_FILTER);
ntype.declare = blender::nodes::cmp_node_directional_blur_declare;
ntype.draw_buttons = node_composit_buts_dblur;
node_type_init(&ntype, node_composit_init_dblur);
diff --git a/source/blender/nodes/composite/nodes/node_composite_displace.cc b/source/blender/nodes/composite/nodes/node_composite_displace.cc
index 0137c1f7da8..dd53b3f46a5 100644
--- a/source/blender/nodes/composite/nodes/node_composite_displace.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_displace.cc
@@ -46,7 +46,7 @@ void register_node_type_cmp_displace()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DISPLACE, "Displace", NODE_CLASS_DISTORT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_DISPLACE, "Displace", NODE_CLASS_DISTORT);
ntype.declare = blender::nodes::cmp_node_displace_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc
index 47a48ed141e..2b6d5068d74 100644
--- a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc
@@ -42,7 +42,7 @@ static void cmp_node_distance_matte_declare(NodeDeclarationBuilder &b)
static void node_composit_init_distance_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
node->storage = c;
c->channel = 1;
c->t1 = 0.1f;
@@ -70,9 +70,10 @@ void register_node_type_cmp_distance_matte()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_DIST_MATTE, "Distance Key", NODE_CLASS_MATTE, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_DIST_MATTE, "Distance Key", NODE_CLASS_MATTE);
ntype.declare = blender::nodes::cmp_node_distance_matte_declare;
ntype.draw_buttons = node_composit_buts_distance_matte;
+ ntype.flag |= NODE_PREVIEW;
node_type_init(&ntype, node_composit_init_distance_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc b/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc
index 4fde539e6fb..1a0d268941e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc
@@ -57,7 +57,7 @@ void register_node_type_cmp_doubleedgemask()
{
static bNodeType ntype; /* Allocate a node type data structure. */
- cmp_node_type_base(&ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_MATTE, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_MATTE);
ntype.declare = blender::nodes::cmp_node_double_edge_mask_declare;
ntype.draw_buttons = node_composit_buts_double_edge_mask;
diff --git a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
index 8eb89e53790..1ae5bd9644c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc
@@ -24,7 +24,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
-#include "../node_composite_util.hh"
+#include "node_composite_util.hh"
/* **************** SCALAR MATH ******************** */
@@ -41,8 +41,7 @@ static void cmp_node_ellipsemask_declare(NodeDeclarationBuilder &b)
static void node_composit_init_ellipsemask(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeEllipseMask *data = (NodeEllipseMask *)MEM_callocN(sizeof(NodeEllipseMask),
- "NodeEllipseMask");
+ NodeEllipseMask *data = MEM_cnew<NodeEllipseMask>(__func__);
data->x = 0.5;
data->y = 0.5;
data->width = 0.2;
@@ -69,7 +68,7 @@ void register_node_type_cmp_ellipsemask()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MASK_ELLIPSE, "Ellipse Mask", NODE_CLASS_MATTE, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_MASK_ELLIPSE, "Ellipse Mask", NODE_CLASS_MATTE);
ntype.declare = blender::nodes::cmp_node_ellipsemask_declare;
ntype.draw_buttons = node_composit_buts_ellipsemask;
node_type_size(&ntype, 260, 110, 320);
diff --git a/source/blender/nodes/composite/nodes/node_composite_exposure.cc b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
index b696db41a3c..bee172b24c9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_exposure.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_exposure.cc
@@ -40,7 +40,7 @@ void register_node_type_cmp_exposure()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_EXPOSURE, "Exposure", NODE_CLASS_OP_COLOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_EXPOSURE, "Exposure", NODE_CLASS_OP_COLOR);
ntype.declare = blender::nodes::cmp_node_exposure_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_filter.cc b/source/blender/nodes/composite/nodes/node_composite_filter.cc
index 3671d502539..cc348af585e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_filter.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_filter.cc
@@ -48,10 +48,11 @@ void register_node_type_cmp_filter()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_FILTER, "Filter", NODE_CLASS_OP_FILTER, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_FILTER, "Filter", NODE_CLASS_OP_FILTER);
ntype.declare = blender::nodes::cmp_node_filter_declare;
ntype.draw_buttons = node_composit_buts_filter;
ntype.labelfunc = node_filter_label;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_flip.cc b/source/blender/nodes/composite/nodes/node_composite_flip.cc
index 38bc0f8b855..1087254ac7a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_flip.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_flip.cc
@@ -47,7 +47,7 @@ void register_node_type_cmp_flip()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_FLIP, "Flip", NODE_CLASS_DISTORT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_FLIP, "Flip", NODE_CLASS_DISTORT);
ntype.declare = blender::nodes::cmp_node_flip_declare;
ntype.draw_buttons = node_composit_buts_flip;
diff --git a/source/blender/nodes/composite/nodes/node_composite_gamma.cc b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
index 438770865ae..2ad2b955b9d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_gamma.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_gamma.cc
@@ -44,7 +44,7 @@ void register_node_type_cmp_gamma()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR);
ntype.declare = blender::nodes::cmp_node_gamma_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_glare.cc b/source/blender/nodes/composite/nodes/node_composite_glare.cc
index adaf22395c3..89701b3551a 100644
--- a/source/blender/nodes/composite/nodes/node_composite_glare.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_glare.cc
@@ -40,7 +40,7 @@ static void cmp_node_glare_declare(NodeDeclarationBuilder &b)
static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGlare *ndg = (NodeGlare *)MEM_callocN(sizeof(NodeGlare), "node glare data");
+ NodeGlare *ndg = MEM_cnew<NodeGlare>(__func__);
ndg->quality = 1;
ndg->type = 2;
ndg->iter = 3;
@@ -97,7 +97,7 @@ void register_node_type_cmp_glare()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_GLARE, "Glare", NODE_CLASS_OP_FILTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_GLARE, "Glare", NODE_CLASS_OP_FILTER);
ntype.declare = blender::nodes::cmp_node_glare_declare;
ntype.draw_buttons = node_composit_buts_glare;
node_type_init(&ntype, node_composit_init_glare);
diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
index 47fbaa4d384..5453ee4fae4 100644
--- a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc
@@ -51,7 +51,7 @@ void register_node_type_cmp_hue_sat()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR);
ntype.declare = blender::nodes::cmp_node_huesatval_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
index e78ba0c7f9c..a98e4cdd3ba 100644
--- a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc
@@ -55,7 +55,7 @@ void register_node_type_cmp_huecorrect()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_HUECORRECT, "Hue Correct", NODE_CLASS_OP_COLOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_HUECORRECT, "Hue Correct", NODE_CLASS_OP_COLOR);
ntype.declare = blender::nodes::cmp_node_huecorrect_declare;
node_type_size(&ntype, 320, 140, 500);
node_type_init(&ntype, node_composit_init_huecorrect);
diff --git a/source/blender/nodes/composite/nodes/node_composite_idMask.cc b/source/blender/nodes/composite/nodes/node_composite_idMask.cc
index f5b8cb6c567..c898734e758 100644
--- a/source/blender/nodes/composite/nodes/node_composite_idMask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_idMask.cc
@@ -48,7 +48,7 @@ void register_node_type_cmp_idmask()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_ID_MASK, "ID Mask", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_ID_MASK, "ID Mask", NODE_CLASS_CONVERTER);
ntype.declare = blender::nodes::cmp_node_idmask_declare;
ntype.draw_buttons = node_composit_buts_id_mask;
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc
index 8e3cc9bcd95..bb87991630d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_image.cc
@@ -108,8 +108,7 @@ static void cmp_node_image_add_pass_output(bNodeTree *ntree,
sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, type, PROP_NONE, name, name);
}
/* extra socket info */
- NodeImageLayer *sockdata = (NodeImageLayer *)MEM_callocN(sizeof(NodeImageLayer),
- "node image layer");
+ NodeImageLayer *sockdata = MEM_cnew<NodeImageLayer>(__func__);
sock->storage = sockdata;
}
@@ -412,7 +411,7 @@ static void cmp_node_image_update(bNodeTree *ntree, bNode *node)
static void node_composit_init_image(bNodeTree *ntree, bNode *node)
{
- ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user");
+ ImageUser *iuser = MEM_cnew<ImageUser>(__func__);
node->storage = iuser;
iuser->frames = 1;
iuser->sfra = 1;
@@ -452,11 +451,12 @@ void register_node_type_cmp_image()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_IMAGE, "Image", NODE_CLASS_INPUT);
node_type_init(&ntype, node_composit_init_image);
node_type_storage(&ntype, "ImageUser", node_composit_free_image, node_composit_copy_image);
node_type_update(&ntype, cmp_node_image_update);
ntype.labelfunc = node_image_label;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
@@ -489,8 +489,7 @@ static void node_composit_init_rlayers(const bContext *C, PointerRNA *ptr)
for (bNodeSocket *sock = (bNodeSocket *)node->outputs.first; sock;
sock = sock->next, sock_index++) {
- NodeImageLayer *sockdata = (NodeImageLayer *)MEM_callocN(sizeof(NodeImageLayer),
- "node image layer");
+ NodeImageLayer *sockdata = MEM_cnew<NodeImageLayer>(__func__);
sock->storage = sockdata;
BLI_strncpy(sockdata->pass_name,
@@ -607,11 +606,12 @@ void register_node_type_cmp_rlayers()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, nullptr, cmp_node_rlayers_out);
ntype.draw_buttons = node_composit_buts_viewlayers;
ntype.initfunc_api = node_composit_init_rlayers;
ntype.poll = node_composit_poll_rlayers;
+ ntype.flag |= NODE_PREVIEW;
node_type_storage(&ntype, nullptr, node_composit_free_rlayers, node_composit_copy_rlayers);
node_type_update(&ntype, cmp_node_rlayers_update);
node_type_init(&ntype, node_cmp_rlayers_outputs);
diff --git a/source/blender/nodes/composite/nodes/node_composite_inpaint.cc b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
index 976b1cd5a15..6776837f002 100644
--- a/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc
@@ -47,7 +47,7 @@ void register_node_type_cmp_inpaint()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_INPAINT, "Inpaint", NODE_CLASS_OP_FILTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_INPAINT, "Inpaint", NODE_CLASS_OP_FILTER);
ntype.declare = blender::nodes::cmp_node_inpaint_declare;
ntype.draw_buttons = node_composit_buts_inpaint;
diff --git a/source/blender/nodes/composite/nodes/node_composite_invert.cc b/source/blender/nodes/composite/nodes/node_composite_invert.cc
index 2243608d5c3..c149e943c6d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_invert.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_invert.cc
@@ -58,7 +58,7 @@ void register_node_type_cmp_invert()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR);
ntype.declare = blender::nodes::cmp_node_invert_declare;
ntype.draw_buttons = node_composit_buts_invert;
node_type_init(&ntype, node_composit_init_invert);
diff --git a/source/blender/nodes/composite/nodes/node_composite_keying.cc b/source/blender/nodes/composite/nodes/node_composite_keying.cc
index de1da3289f9..0d392f65f3f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_keying.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_keying.cc
@@ -51,7 +51,7 @@ static void cmp_node_keying_declare(NodeDeclarationBuilder &b)
static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeKeyingData *data = (NodeKeyingData *)MEM_callocN(sizeof(NodeKeyingData), "node keying data");
+ NodeKeyingData *data = MEM_cnew<NodeKeyingData>(__func__);
data->screen_balance = 0.5f;
data->despill_balance = 0.5f;
@@ -85,7 +85,7 @@ void register_node_type_cmp_keying()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_KEYING, "Keying", NODE_CLASS_MATTE, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_KEYING, "Keying", NODE_CLASS_MATTE);
ntype.declare = blender::nodes::cmp_node_keying_declare;
ntype.draw_buttons = node_composit_buts_keying;
node_type_init(&ntype, node_composit_init_keying);
diff --git a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
index d90fbe05211..785a904d1fa 100644
--- a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc
@@ -46,8 +46,7 @@ static void cmp_node_keyingscreen_declare(NodeDeclarationBuilder &b)
static void node_composit_init_keyingscreen(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeKeyingScreenData *data = (NodeKeyingScreenData *)MEM_callocN(sizeof(NodeKeyingScreenData),
- "node keyingscreen data");
+ NodeKeyingScreenData *data = MEM_cnew<NodeKeyingScreenData>(__func__);
node->storage = data;
}
@@ -82,7 +81,7 @@ void register_node_type_cmp_keyingscreen()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_KEYINGSCREEN, "Keying Screen", NODE_CLASS_MATTE, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_KEYINGSCREEN, "Keying Screen", NODE_CLASS_MATTE);
ntype.declare = blender::nodes::cmp_node_keyingscreen_declare;
ntype.draw_buttons = node_composit_buts_keyingscreen;
node_type_init(&ntype, node_composit_init_keyingscreen);
diff --git a/source/blender/nodes/composite/nodes/node_composite_lensdist.cc b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
index 11ee0cf0aa3..de8dea9947c 100644
--- a/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc
@@ -42,7 +42,7 @@ static void cmp_node_lensdist_declare(NodeDeclarationBuilder &b)
static void node_composit_init_lensdist(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeLensDist *nld = (NodeLensDist *)MEM_callocN(sizeof(NodeLensDist), "node lensdist data");
+ NodeLensDist *nld = MEM_cnew<NodeLensDist>(__func__);
nld->jit = nld->proj = nld->fit = 0;
node->storage = nld;
}
@@ -64,7 +64,7 @@ void register_node_type_cmp_lensdist()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_LENSDIST, "Lens Distortion", NODE_CLASS_DISTORT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_LENSDIST, "Lens Distortion", NODE_CLASS_DISTORT);
ntype.declare = blender::nodes::cmp_node_lensdist_declare;
ntype.draw_buttons = node_composit_buts_lensdist;
node_type_init(&ntype, node_composit_init_lensdist);
diff --git a/source/blender/nodes/composite/nodes/node_composite_levels.cc b/source/blender/nodes/composite/nodes/node_composite_levels.cc
index 891f79f9bf9..817de75ef55 100644
--- a/source/blender/nodes/composite/nodes/node_composite_levels.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_levels.cc
@@ -53,9 +53,10 @@ void register_node_type_cmp_view_levels()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT);
ntype.declare = blender::nodes::cmp_node_levels_declare;
ntype.draw_buttons = node_composit_buts_view_levels;
+ ntype.flag |= NODE_PREVIEW;
node_type_init(&ntype, node_composit_init_view_levels);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc b/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc
index f5193bd5df2..313bbf73955 100644
--- a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc
@@ -41,7 +41,7 @@ static void cmp_node_luma_matte_declare(NodeDeclarationBuilder &b)
static void node_composit_init_luma_matte(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma");
+ NodeChroma *c = MEM_cnew<NodeChroma>(__func__);
node->storage = c;
c->t1 = 1.0f;
c->t2 = 0.0f;
@@ -62,9 +62,10 @@ void register_node_type_cmp_luma_matte()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_LUMA_MATTE, "Luminance Key", NODE_CLASS_MATTE, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_LUMA_MATTE, "Luminance Key", NODE_CLASS_MATTE);
ntype.declare = blender::nodes::cmp_node_luma_matte_declare;
ntype.draw_buttons = node_composit_buts_luma_matte;
+ ntype.flag |= NODE_PREVIEW;
node_type_init(&ntype, node_composit_init_luma_matte);
node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapRange.cc b/source/blender/nodes/composite/nodes/node_composite_mapRange.cc
index 1ae80f68dfd..3d90c050fa7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapRange.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mapRange.cc
@@ -54,7 +54,7 @@ void register_node_type_cmp_map_range()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MAP_RANGE, "Map Range", NODE_CLASS_OP_VECTOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_MAP_RANGE, "Map Range", NODE_CLASS_OP_VECTOR);
ntype.declare = blender::nodes::cmp_node_map_range_declare;
ntype.draw_buttons = node_composit_buts_map_range;
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapUV.cc b/source/blender/nodes/composite/nodes/node_composite_mapUV.cc
index 71446e3a3c4..924a17d5c0b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapUV.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mapUV.cc
@@ -48,7 +48,7 @@ void register_node_type_cmp_mapuv()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MAP_UV, "Map UV", NODE_CLASS_DISTORT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_MAP_UV, "Map UV", NODE_CLASS_DISTORT);
ntype.declare = blender::nodes::cmp_node_map_uv_declare;
ntype.draw_buttons = node_composit_buts_map_uv;
diff --git a/source/blender/nodes/composite/nodes/node_composite_mapValue.cc b/source/blender/nodes/composite/nodes/node_composite_mapValue.cc
index 4bd9124fa68..b94ea676ca0 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mapValue.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mapValue.cc
@@ -70,7 +70,7 @@ void register_node_type_cmp_map_value()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MAP_VALUE, "Map Value", NODE_CLASS_OP_VECTOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_MAP_VALUE, "Map Value", NODE_CLASS_OP_VECTOR);
ntype.declare = blender::nodes::cmp_node_map_value_declare;
ntype.draw_buttons = node_composit_buts_map_value;
node_type_init(&ntype, node_composit_init_map_value);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mask.cc b/source/blender/nodes/composite/nodes/node_composite_mask.cc
index 8cbf526a289..0fea7148a4d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mask.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mask.cc
@@ -41,7 +41,7 @@ static void cmp_node_mask_declare(NodeDeclarationBuilder &b)
static void node_composit_init_mask(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeMask *data = (NodeMask *)MEM_callocN(sizeof(NodeMask), "NodeMask");
+ NodeMask *data = MEM_cnew<NodeMask>(__func__);
data->size_x = data->size_y = 256;
node->storage = data;
@@ -96,7 +96,7 @@ void register_node_type_cmp_mask()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MASK, "Mask", NODE_CLASS_INPUT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_MASK, "Mask", NODE_CLASS_INPUT);
ntype.declare = blender::nodes::cmp_node_mask_declare;
ntype.draw_buttons = node_composit_buts_mask;
node_type_init(&ntype, node_composit_init_mask);
diff --git a/source/blender/nodes/composite/nodes/node_composite_math.cc b/source/blender/nodes/composite/nodes/node_composite_math.cc
index b34cfab5eb5..21d76756e0e 100644
--- a/source/blender/nodes/composite/nodes/node_composite_math.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_math.cc
@@ -47,7 +47,7 @@ void register_node_type_cmp_math()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTER);
ntype.declare = blender::nodes::cmp_node_math_declare;
ntype.labelfunc = node_math_label;
node_type_update(&ntype, node_math_update);
diff --git a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
index 4432b031ee7..7bc37fd5024 100644
--- a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc
@@ -42,7 +42,8 @@ void register_node_type_cmp_mix_rgb()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR);
+ ntype.flag |= NODE_PREVIEW;
ntype.declare = blender::nodes::cmp_node_mixrgb_declare;
ntype.labelfunc = node_blend_label;
diff --git a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
index 47a2c89a2f9..3c0be471564 100644
--- a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc
@@ -49,8 +49,7 @@ static void init(const bContext *C, PointerRNA *ptr)
{
bNode *node = (bNode *)ptr->data;
Scene *scene = CTX_data_scene(C);
- MovieClipUser *user = (MovieClipUser *)MEM_callocN(sizeof(MovieClipUser),
- "node movie clip user");
+ MovieClipUser *user = MEM_cnew<MovieClipUser>(__func__);
node->id = (ID *)scene->clip;
id_us_plus(node->id);
@@ -101,11 +100,12 @@ void register_node_type_cmp_movieclip()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MOVIECLIP, "Movie Clip", NODE_CLASS_INPUT, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_MOVIECLIP, "Movie Clip", NODE_CLASS_INPUT);
ntype.declare = blender::nodes::cmp_node_movieclip_declare;
ntype.draw_buttons = node_composit_buts_movieclip;
ntype.draw_buttons_ex = node_composit_buts_movieclip_ex;
ntype.initfunc_api = init;
+ ntype.flag |= NODE_PREVIEW;
node_type_storage(
&ntype, "MovieClipUser", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
index e7d9cac7c1a..17c9fd29b1d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc
@@ -102,7 +102,7 @@ void register_node_type_cmp_moviedistortion()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_MOVIEDISTORTION, "Movie Distortion", NODE_CLASS_DISTORT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_MOVIEDISTORTION, "Movie Distortion", NODE_CLASS_DISTORT);
ntype.declare = blender::nodes::cmp_node_moviedistortion_declare;
ntype.draw_buttons = node_composit_buts_moviedistortion;
ntype.labelfunc = label;
diff --git a/source/blender/nodes/composite/nodes/node_composite_normal.cc b/source/blender/nodes/composite/nodes/node_composite_normal.cc
index b541761a8cc..c84e02967b8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_normal.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_normal.cc
@@ -44,7 +44,7 @@ void register_node_type_cmp_normal()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR);
ntype.declare = blender::nodes::cmp_node_normal_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_normalize.cc b/source/blender/nodes/composite/nodes/node_composite_normalize.cc
index dd3939fa6e2..e89af5fb9fb 100644
--- a/source/blender/nodes/composite/nodes/node_composite_normalize.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_normalize.cc
@@ -39,7 +39,7 @@ void register_node_type_cmp_normalize()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_NORMALIZE, "Normalize", NODE_CLASS_OP_VECTOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_NORMALIZE, "Normalize", NODE_CLASS_OP_VECTOR);
ntype.declare = blender::nodes::cmp_node_normalize_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.cc b/source/blender/nodes/composite/nodes/node_composite_outputFile.cc
index 79074375a23..f4699ec02d0 100644
--- a/source/blender/nodes/composite/nodes/node_composite_outputFile.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.cc
@@ -135,8 +135,7 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree,
ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, name);
/* create format data for the input socket */
- NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)MEM_callocN(
- sizeof(NodeImageMultiFileSocket), "socket image format");
+ NodeImageMultiFileSocket *sockdata = MEM_cnew<NodeImageMultiFileSocket>(__func__);
sock->storage = sockdata;
BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path));
@@ -203,8 +202,7 @@ static void init_output_file(const bContext *C, PointerRNA *ptr)
Scene *scene = CTX_data_scene(C);
bNodeTree *ntree = (bNodeTree *)ptr->owner_id;
bNode *node = (bNode *)ptr->data;
- NodeImageMultiFile *nimf = (NodeImageMultiFile *)MEM_callocN(sizeof(NodeImageMultiFile),
- "node image multi file");
+ NodeImageMultiFile *nimf = MEM_cnew<NodeImageMultiFile>(__func__);
ImageFormatData *format = nullptr;
node->storage = nimf;
@@ -441,11 +439,12 @@ void register_node_type_cmp_output_file()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT);
node_type_socket_templates(&ntype, nullptr, nullptr);
ntype.draw_buttons = node_composit_buts_file_output;
ntype.draw_buttons_ex = node_composit_buts_file_output_ex;
ntype.initfunc_api = init_output_file;
+ ntype.flag |= NODE_PREVIEW;
node_type_storage(&ntype, "NodeImageMultiFile", free_output_file, copy_output_file);
node_type_update(&ntype, update_output_file);
diff --git a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
index 3679aada759..7fe4d84ed72 100644
--- a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
@@ -39,7 +39,7 @@ void register_node_type_cmp_pixelate()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_PIXELATE, "Pixelate", NODE_CLASS_OP_FILTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_PIXELATE, "Pixelate", NODE_CLASS_OP_FILTER);
ntype.declare = blender::nodes::cmp_node_pixelate_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
index d9d362f5175..4e5299d8b5f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc
@@ -41,8 +41,7 @@ static void cmp_node_planetrackdeform_declare(NodeDeclarationBuilder &b)
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)MEM_callocN(
- sizeof(NodePlaneTrackDeformData), "node plane track deform data");
+ NodePlaneTrackDeformData *data = MEM_cnew<NodePlaneTrackDeformData>(__func__);
data->motion_blur_samples = 16;
data->motion_blur_shutter = 0.5f;
node->storage = data;
@@ -101,8 +100,7 @@ void register_node_type_cmp_planetrackdeform()
{
static bNodeType ntype;
- cmp_node_type_base(
- &ntype, CMP_NODE_PLANETRACKDEFORM, "Plane Track Deform", NODE_CLASS_DISTORT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_PLANETRACKDEFORM, "Plane Track Deform", NODE_CLASS_DISTORT);
ntype.declare = blender::nodes::cmp_node_planetrackdeform_declare;
ntype.draw_buttons = node_composit_buts_planetrackdeform;
node_type_init(&ntype, init);
diff --git a/source/blender/nodes/composite/nodes/node_composite_posterize.cc b/source/blender/nodes/composite/nodes/node_composite_posterize.cc
index 8437c72e76c..347901a6578 100644
--- a/source/blender/nodes/composite/nodes/node_composite_posterize.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_posterize.cc
@@ -40,7 +40,7 @@ void register_node_type_cmp_posterize()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_POSTERIZE, "Posterize", NODE_CLASS_OP_COLOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_POSTERIZE, "Posterize", NODE_CLASS_OP_COLOR);
ntype.declare = blender::nodes::cmp_node_posterize_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
index a70adf68692..ad29d231b11 100644
--- a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc
@@ -47,7 +47,7 @@ void register_node_type_cmp_premulkey()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_PREMULKEY, "Alpha Convert", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_PREMULKEY, "Alpha Convert", NODE_CLASS_CONVERTER);
ntype.declare = blender::nodes::cmp_node_premulkey_declare;
ntype.draw_buttons = node_composit_buts_premulkey;
diff --git a/source/blender/nodes/composite/nodes/node_composite_rgb.cc b/source/blender/nodes/composite/nodes/node_composite_rgb.cc
index 54f152d1cd0..b7db175e1b1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_rgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_rgb.cc
@@ -38,7 +38,7 @@ void register_node_type_cmp_rgb()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_RGB, "RGB", NODE_CLASS_INPUT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_RGB, "RGB", NODE_CLASS_INPUT);
ntype.declare = blender::nodes::cmp_node_rgb_declare;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
diff --git a/source/blender/nodes/composite/nodes/node_composite_rotate.cc b/source/blender/nodes/composite/nodes/node_composite_rotate.cc
index cc1589a47ca..a147d81a344 100644
--- a/source/blender/nodes/composite/nodes/node_composite_rotate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_rotate.cc
@@ -57,7 +57,7 @@ void register_node_type_cmp_rotate()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT);
ntype.declare = blender::nodes::cmp_node_rotate_declare;
ntype.draw_buttons = node_composit_buts_rotate;
node_type_init(&ntype, node_composit_init_rotate);
diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.cc b/source/blender/nodes/composite/nodes/node_composite_scale.cc
index 98c9f6619f4..1aecf63d049 100644
--- a/source/blender/nodes/composite/nodes/node_composite_scale.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_scale.cc
@@ -77,7 +77,7 @@ void register_node_type_cmp_scale()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_SCALE, "Scale", NODE_CLASS_DISTORT);
ntype.declare = blender::nodes::cmp_node_scale_declare;
ntype.draw_buttons = node_composit_buts_scale;
node_type_update(&ntype, node_composite_update_scale);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
index 9eafc0e3594..45db11d26b7 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc
@@ -42,7 +42,7 @@ void register_node_type_cmp_sephsva()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTER);
ntype.declare = blender::nodes::cmp_node_sephsva_declare;
nodeRegisterType(&ntype);
}
@@ -66,7 +66,7 @@ void register_node_type_cmp_combhsva()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTER);
ntype.declare = blender::nodes::cmp_node_combhsva_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
index e81ea6f31be..0d4584f2d60 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc
@@ -41,7 +41,7 @@ void register_node_type_cmp_seprgba()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTER);
ntype.declare = blender::nodes::cmp_node_seprgba_declare;
nodeRegisterType(&ntype);
@@ -66,7 +66,7 @@ void register_node_type_cmp_combrgba()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTER);
ntype.declare = blender::nodes::cmp_node_combrgba_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
index 15c8efc2ef8..73790499a58 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc
@@ -47,7 +47,7 @@ void register_node_type_cmp_sepycca()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTER);
ntype.declare = blender::nodes::cmp_node_sepycca_declare;
node_type_init(&ntype, node_composit_init_mode_sepycca);
@@ -78,7 +78,7 @@ void register_node_type_cmp_combycca()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTER);
ntype.declare = blender::nodes::cmp_node_combycca_declare;
node_type_init(&ntype, node_composit_init_mode_combycca);
diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
index 4d4b01c2fb3..c026244d13b 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc
@@ -42,7 +42,7 @@ void register_node_type_cmp_sepyuva()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTER);
ntype.declare = blender::nodes::cmp_node_sepyuva_declare;
nodeRegisterType(&ntype);
@@ -67,7 +67,7 @@ void register_node_type_cmp_combyuva()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTER);
ntype.declare = blender::nodes::cmp_node_combyuva_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
index 3e66f884efd..8912e793a1d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc
@@ -41,7 +41,7 @@ static void cmp_node_setalpha_declare(NodeDeclarationBuilder &b)
static void node_composit_init_setalpha(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeSetAlpha *settings = (NodeSetAlpha *)MEM_callocN(sizeof(NodeSetAlpha), __func__);
+ NodeSetAlpha *settings = MEM_cnew<NodeSetAlpha>(__func__);
node->storage = settings;
settings->mode = CMP_NODE_SETALPHA_MODE_APPLY;
}
@@ -55,7 +55,7 @@ void register_node_type_cmp_setalpha()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SETALPHA, "Set Alpha", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_SETALPHA, "Set Alpha", NODE_CLASS_CONVERTER);
ntype.declare = blender::nodes::cmp_node_setalpha_declare;
ntype.draw_buttons = node_composit_buts_set_alpha;
node_type_init(&ntype, node_composit_init_setalpha);
diff --git a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc
index 63772a52840..2ff64c3d735 100644
--- a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc
@@ -43,7 +43,7 @@ static void cmp_node_split_viewer_declare(NodeDeclarationBuilder &b)
static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode *node)
{
- ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user");
+ ImageUser *iuser = MEM_cnew<ImageUser>(__func__);
node->storage = iuser;
iuser->sfra = 1;
node->custom1 = 50; /* default 50% split */
@@ -65,10 +65,10 @@ void register_node_type_cmp_splitviewer()
{
static bNodeType ntype;
- cmp_node_type_base(
- &ntype, CMP_NODE_SPLITVIEWER, "Split Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_SPLITVIEWER, "Split Viewer", NODE_CLASS_OUTPUT);
ntype.declare = blender::nodes::cmp_node_split_viewer_declare;
ntype.draw_buttons = node_composit_buts_splitviewer;
+ ntype.flag |= NODE_PREVIEW;
node_type_init(&ntype, node_composit_init_splitviewer);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
index de6cc21ccd5..7ab933ab8ea 100644
--- a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc
@@ -80,7 +80,7 @@ void register_node_type_cmp_stabilize2d()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_STABILIZE2D, "Stabilize 2D", NODE_CLASS_DISTORT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_STABILIZE2D, "Stabilize 2D", NODE_CLASS_DISTORT);
ntype.declare = blender::nodes::cmp_node_stabilize2d_declare;
ntype.draw_buttons = node_composit_buts_stabilize2d;
ntype.initfunc_api = init;
diff --git a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
index f5d69c7d17b..7ae9d927a81 100644
--- a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc
@@ -38,7 +38,7 @@ static void cmp_node_sunbeams_declare(NodeDeclarationBuilder &b)
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeSunBeams *data = (NodeSunBeams *)MEM_callocN(sizeof(NodeSunBeams), "sun beams node");
+ NodeSunBeams *data = MEM_cnew<NodeSunBeams>(__func__);
data->source[0] = 0.5f;
data->source[1] = 0.5f;
@@ -60,7 +60,7 @@ void register_node_type_cmp_sunbeams()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SUNBEAMS, "Sun Beams", NODE_CLASS_OP_FILTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_SUNBEAMS, "Sun Beams", NODE_CLASS_OP_FILTER);
ntype.declare = blender::nodes::cmp_node_sunbeams_declare;
ntype.draw_buttons = node_composit_buts_sunbeams;
node_type_init(&ntype, init);
diff --git a/source/blender/nodes/composite/nodes/node_composite_switch.cc b/source/blender/nodes/composite/nodes/node_composite_switch.cc
index d13bcc28d10..3ecd29230d1 100644
--- a/source/blender/nodes/composite/nodes/node_composite_switch.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_switch.cc
@@ -24,7 +24,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
-#include "../node_composite_util.hh"
+#include "node_composite_util.hh"
/* **************** Switch ******************** */
@@ -49,7 +49,7 @@ void register_node_type_cmp_switch()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SWITCH, "Switch", NODE_CLASS_LAYOUT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_SWITCH, "Switch", NODE_CLASS_LAYOUT);
ntype.declare = blender::nodes::cmp_node_switch_declare;
ntype.draw_buttons = node_composit_buts_switch;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
diff --git a/source/blender/nodes/composite/nodes/node_composite_switchview.cc b/source/blender/nodes/composite/nodes/node_composite_switchview.cc
index 159d66fc6cc..69bb8f532d6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_switchview.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_switchview.cc
@@ -28,7 +28,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
-#include "../node_composite_util.hh"
+#include "node_composite_util.hh"
/* **************** SWITCH VIEW ******************** */
@@ -159,7 +159,7 @@ void register_node_type_cmp_switch_view()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, nullptr, cmp_node_switch_view_out);
ntype.draw_buttons_ex = node_composit_buts_switch_view_ex;
ntype.initfunc_api = init_switch_view;
diff --git a/source/blender/nodes/composite/nodes/node_composite_texture.cc b/source/blender/nodes/composite/nodes/node_composite_texture.cc
index 5e5fca755b2..67bf95c5ae9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_texture.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_texture.cc
@@ -45,8 +45,9 @@ void register_node_type_cmp_texture()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT);
ntype.declare = blender::nodes::cmp_node_texture_declare;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
index c6015eda08c..fccfa6a3de9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc
@@ -40,7 +40,7 @@ static void cmp_node_tonemap_declare(NodeDeclarationBuilder &b)
static void node_composit_init_tonemap(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTonemap *ntm = (NodeTonemap *)MEM_callocN(sizeof(NodeTonemap), "node tonemap data");
+ NodeTonemap *ntm = MEM_cnew<NodeTonemap>(__func__);
ntm->type = 1;
ntm->key = 0.18;
ntm->offset = 1;
@@ -80,7 +80,7 @@ void register_node_type_cmp_tonemap()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TONEMAP, "Tonemap", NODE_CLASS_OP_COLOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_TONEMAP, "Tonemap", NODE_CLASS_OP_COLOR);
ntype.declare = blender::nodes::cmp_node_tonemap_declare;
ntype.draw_buttons = node_composit_buts_tonemap;
node_type_init(&ntype, node_composit_init_tonemap);
diff --git a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
index 3be52820f15..cce3052ef22 100644
--- a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc
@@ -41,8 +41,7 @@ static void cmp_node_trackpos_declare(NodeDeclarationBuilder &b)
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTrackPosData *data = (NodeTrackPosData *)MEM_callocN(sizeof(NodeTrackPosData),
- "node track position data");
+ NodeTrackPosData *data = MEM_cnew<NodeTrackPosData>(__func__);
node->storage = data;
}
@@ -99,7 +98,7 @@ void register_node_type_cmp_trackpos()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TRACKPOS, "Track Position", NODE_CLASS_INPUT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_TRACKPOS, "Track Position", NODE_CLASS_INPUT);
ntype.declare = blender::nodes::cmp_node_trackpos_declare;
ntype.draw_buttons = node_composit_buts_trackpos;
node_type_init(&ntype, init);
diff --git a/source/blender/nodes/composite/nodes/node_composite_transform.cc b/source/blender/nodes/composite/nodes/node_composite_transform.cc
index ad1cc4cd308..ee9f25531f6 100644
--- a/source/blender/nodes/composite/nodes/node_composite_transform.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_transform.cc
@@ -55,7 +55,7 @@ void register_node_type_cmp_transform()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TRANSFORM, "Transform", NODE_CLASS_DISTORT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_TRANSFORM, "Transform", NODE_CLASS_DISTORT);
ntype.declare = blender::nodes::cmp_node_transform_declare;
ntype.draw_buttons = node_composit_buts_transform;
diff --git a/source/blender/nodes/composite/nodes/node_composite_translate.cc b/source/blender/nodes/composite/nodes/node_composite_translate.cc
index ce29cc55ca2..96188b68496 100644
--- a/source/blender/nodes/composite/nodes/node_composite_translate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_translate.cc
@@ -42,8 +42,7 @@ static void cmp_node_translate_declare(NodeDeclarationBuilder &b)
static void node_composit_init_translate(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTranslateData *data = (NodeTranslateData *)MEM_callocN(sizeof(NodeTranslateData),
- "node translate data");
+ NodeTranslateData *data = MEM_cnew<NodeTranslateData>(__func__);
node->storage = data;
}
@@ -57,7 +56,7 @@ void register_node_type_cmp_translate()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT);
ntype.declare = blender::nodes::cmp_node_translate_declare;
ntype.draw_buttons = node_composit_buts_translate;
node_type_init(&ntype, node_composit_init_translate);
diff --git a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc b/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
index dca6c9c141c..65e28751ce2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc
@@ -45,7 +45,7 @@ void register_node_type_cmp_valtorgb()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER);
ntype.declare = blender::nodes::cmp_node_valtorgb_declare;
node_type_size(&ntype, 240, 200, 320);
node_type_init(&ntype, node_composit_init_valtorgb);
@@ -70,7 +70,7 @@ void register_node_type_cmp_rgbtobw()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER);
ntype.declare = blender::nodes::cmp_node_rgbtobw_declare;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
diff --git a/source/blender/nodes/composite/nodes/node_composite_value.cc b/source/blender/nodes/composite/nodes/node_composite_value.cc
index d2274d2d82a..c78b0a454d9 100644
--- a/source/blender/nodes/composite/nodes/node_composite_value.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_value.cc
@@ -38,7 +38,7 @@ void register_node_type_cmp_value()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_VALUE, "Value", NODE_CLASS_INPUT);
ntype.declare = blender::nodes::cmp_node_value_declare;
node_type_size_preset(&ntype, NODE_SIZE_SMALL);
diff --git a/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc b/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc
index c4bea269670..cef787a23b2 100644
--- a/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc
@@ -46,7 +46,7 @@ static void cmp_node_vec_blur_declare(NodeDeclarationBuilder &b)
static void node_composit_init_vecblur(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeBlurData *nbd = (NodeBlurData *)MEM_callocN(sizeof(NodeBlurData), "node blur data");
+ NodeBlurData *nbd = MEM_cnew<NodeBlurData>(__func__);
node->storage = nbd;
nbd->samples = 32;
nbd->fac = 1.0f;
@@ -73,7 +73,7 @@ void register_node_type_cmp_vecblur()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_VECBLUR, "Vector Blur", NODE_CLASS_OP_FILTER, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_VECBLUR, "Vector Blur", NODE_CLASS_OP_FILTER);
ntype.declare = blender::nodes::cmp_node_vec_blur_declare;
ntype.draw_buttons = node_composit_buts_vecblur;
node_type_init(&ntype, node_composit_init_vecblur);
diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.cc b/source/blender/nodes/composite/nodes/node_composite_viewer.cc
index fcebda3b8a4..ba3d620a1aa 100644
--- a/source/blender/nodes/composite/nodes/node_composite_viewer.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_viewer.cc
@@ -46,7 +46,7 @@ static void cmp_node_viewer_declare(NodeDeclarationBuilder &b)
static void node_composit_init_viewer(bNodeTree *UNUSED(ntree), bNode *node)
{
- ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user");
+ ImageUser *iuser = MEM_cnew<ImageUser>(__func__);
node->storage = iuser;
iuser->sfra = 1;
node->custom3 = 0.5f;
@@ -77,10 +77,11 @@ void register_node_type_cmp_viewer()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
+ cmp_node_type_base(&ntype, CMP_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT);
ntype.declare = blender::nodes::cmp_node_viewer_declare;
ntype.draw_buttons = node_composit_buts_viewer;
ntype.draw_buttons_ex = node_composit_buts_viewer_ex;
+ ntype.flag |= NODE_PREVIEW;
node_type_init(&ntype, node_composit_init_viewer);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/composite/nodes/node_composite_zcombine.cc b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
index dd6872e4dd9..d79b7aa5c14 100644
--- a/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc
@@ -55,7 +55,7 @@ void register_node_type_cmp_zcombine()
{
static bNodeType ntype;
- cmp_node_type_base(&ntype, CMP_NODE_ZCOMBINE, "Z Combine", NODE_CLASS_OP_COLOR, 0);
+ cmp_node_type_base(&ntype, CMP_NODE_ZCOMBINE, "Z Combine", NODE_CLASS_OP_COLOR);
ntype.declare = blender::nodes::cmp_node_zcombine_declare;
ntype.draw_buttons = node_composit_buts_zcombine;
diff --git a/source/blender/nodes/function/CMakeLists.txt b/source/blender/nodes/function/CMakeLists.txt
new file mode 100644
index 00000000000..118a1fbffd1
--- /dev/null
+++ b/source/blender/nodes/function/CMakeLists.txt
@@ -0,0 +1,75 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2021, Blender Foundation
+# All rights reserved.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ../
+ ../intern
+ ../../blenkernel
+ ../../blenlib
+ ../../blentranslation
+ ../../editors/include
+ ../../functions
+ ../../makesdna
+ ../../makesrna
+ ../../windowmanager
+ ../../../../intern/guardedalloc
+)
+
+
+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
+ nodes/node_fn_float_to_int.cc
+ nodes/node_fn_input_bool.cc
+ nodes/node_fn_input_color.cc
+ nodes/node_fn_input_int.cc
+ nodes/node_fn_input_special_characters.cc
+ nodes/node_fn_input_string.cc
+ nodes/node_fn_input_vector.cc
+ nodes/node_fn_random_value.cc
+ nodes/node_fn_replace_string.cc
+ nodes/node_fn_rotate_euler.cc
+ nodes/node_fn_slice_string.cc
+ nodes/node_fn_string_length.cc
+ nodes/node_fn_value_to_string.cc
+
+ node_function_util.cc
+
+ node_function_util.hh
+)
+
+set(LIB
+ bf_functions
+)
+
+if(WITH_INTERNATIONAL)
+ add_definitions(-DWITH_INTERNATIONAL)
+endif()
+
+blender_add_lib(bf_nodes_function "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_UNITY_BUILD)
+ set_target_properties(bf_nodes_function PROPERTIES UNITY_BUILD ON)
+ set_target_properties(bf_nodes_function PROPERTIES UNITY_BUILD_BATCH_SIZE 10)
+endif()
diff --git a/source/blender/nodes/function/node_function_util.cc b/source/blender/nodes/function/node_function_util.cc
index 83f5b571695..0137b298f45 100644
--- a/source/blender/nodes/function/node_function_util.cc
+++ b/source/blender/nodes/function/node_function_util.cc
@@ -31,9 +31,9 @@ static bool fn_node_poll_default(bNodeType *UNUSED(ntype),
return true;
}
-void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = fn_node_poll_default;
ntype->insert_link = node_insert_link_default;
ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
diff --git a/source/blender/nodes/function/node_function_util.hh b/source/blender/nodes/function/node_function_util.hh
index 46b485298e3..acde9c4b55b 100644
--- a/source/blender/nodes/function/node_function_util.hh
+++ b/source/blender/nodes/function/node_function_util.hh
@@ -37,5 +37,4 @@
#include "FN_multi_function_builder.hh"
-void fn_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
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
index d98d49c7273..582e6748a1e 100644
--- a/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
+++ b/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc
@@ -18,7 +18,7 @@
#include "BLI_hash.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_random_float_cc {
static void fn_node_legacy_random_float_declare(NodeDeclarationBuilder &b)
{
@@ -29,8 +29,6 @@ static void fn_node_legacy_random_float_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Value"));
};
-} // namespace blender::nodes
-
class RandomFloatFunction : public blender::fn::MultiFunction {
public:
RandomFloatFunction()
@@ -75,12 +73,16 @@ static void fn_node_legacy_random_float_build_multi_function(
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, 0);
- ntype.declare = blender::nodes::fn_node_legacy_random_float_declare;
- ntype.build_multi_function = fn_node_legacy_random_float_build_multi_function;
+ 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_align_euler_to_vector.cc b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc
index 4088fa24ca7..f4ce8d2f35a 100644
--- a/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc
+++ b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc
@@ -23,7 +23,7 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_align_euler_to_vector_cc {
static void fn_node_align_euler_to_vector_declare(NodeDeclarationBuilder &b)
{
@@ -207,16 +207,18 @@ static void fn_node_align_euler_to_vector_build_multi_function(NodeMultiFunction
builder.construct_and_set_matching_fn<MF_AlignEulerToVector>(node.custom1, node.custom2);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_align_euler_to_vector_cc
void register_node_type_fn_align_euler_to_vector()
{
+ namespace file_ns = blender::nodes::node_fn_align_euler_to_vector_cc;
+
static bNodeType ntype;
fn_node_type_base(
- &ntype, FN_NODE_ALIGN_EULER_TO_VECTOR, "Align Euler to Vector", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_align_euler_to_vector_declare;
- ntype.draw_buttons = blender::nodes::fn_node_align_euler_to_vector_layout;
- ntype.build_multi_function = blender::nodes::fn_node_align_euler_to_vector_build_multi_function;
+ &ntype, FN_NODE_ALIGN_EULER_TO_VECTOR, "Align Euler to Vector", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_align_euler_to_vector_declare;
+ ntype.draw_buttons = file_ns::fn_node_align_euler_to_vector_layout;
+ ntype.build_multi_function = file_ns::fn_node_align_euler_to_vector_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
index 4b59b49c632..e8c05defe7c 100644
--- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
+++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc
@@ -24,7 +24,7 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_boolean_math_cc {
static void fn_node_boolean_math_declare(NodeDeclarationBuilder &b)
{
@@ -87,17 +87,19 @@ static void fn_node_boolean_math_build_multi_function(NodeMultiFunctionBuilder &
builder.set_matching_fn(fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_boolean_math_cc
void register_node_type_fn_boolean_math()
{
+ namespace file_ns = blender::nodes::node_fn_boolean_math_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_boolean_math_declare;
- ntype.labelfunc = blender::nodes::node_boolean_math_label;
- node_type_update(&ntype, blender::nodes::node_boolean_math_update);
- ntype.build_multi_function = blender::nodes::fn_node_boolean_math_build_multi_function;
- ntype.draw_buttons = blender::nodes::fn_node_boolean_math_layout;
+ fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_boolean_math_declare;
+ ntype.labelfunc = file_ns::node_boolean_math_label;
+ node_type_update(&ntype, file_ns::node_boolean_math_update);
+ ntype.build_multi_function = file_ns::fn_node_boolean_math_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_boolean_math_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_compare.cc b/source/blender/nodes/function/nodes/node_fn_compare.cc
index e773563ca5f..28a6093e849 100644
--- a/source/blender/nodes/function/nodes/node_fn_compare.cc
+++ b/source/blender/nodes/function/nodes/node_fn_compare.cc
@@ -97,8 +97,7 @@ static void node_compare_update(bNodeTree *ntree, bNode *node)
static void node_compare_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeFunctionCompare *data = (NodeFunctionCompare *)MEM_callocN(sizeof(NodeFunctionCompare),
- __func__);
+ NodeFunctionCompare *data = MEM_cnew<NodeFunctionCompare>(__func__);
data->operation = NODE_COMPARE_GREATER_THAN;
data->data_type = SOCK_FLOAT;
data->mode = NODE_COMPARE_MODE_ELEMENT;
@@ -131,21 +130,33 @@ static void node_compare_gather_link_searches(GatherLinkSearchOpParams &params)
const eNodeSocketDatatype type = static_cast<eNodeSocketDatatype>(params.other_socket().type);
- if (ELEM(type, SOCK_FLOAT, SOCK_BOOLEAN, SOCK_RGBA, SOCK_VECTOR, SOCK_INT)) {
- params.add_item(IFACE_("A"), SocketSearchOp{"A", type, NODE_COMPARE_GREATER_THAN});
- params.add_item(IFACE_("B"), SocketSearchOp{"B", type, NODE_COMPARE_GREATER_THAN});
- params.add_item(
- IFACE_("C"),
- SocketSearchOp{
- "C", SOCK_VECTOR, NODE_COMPARE_GREATER_THAN, NODE_COMPARE_MODE_DOT_PRODUCT});
- params.add_item(
- IFACE_("Angle"),
- SocketSearchOp{
- "Angle", SOCK_VECTOR, NODE_COMPARE_GREATER_THAN, NODE_COMPARE_MODE_DIRECTION});
- }
- else if (type == SOCK_STRING) {
- params.add_item(IFACE_("A"), SocketSearchOp{"A", type, NODE_COMPARE_EQUAL});
- params.add_item(IFACE_("B"), SocketSearchOp{"B", type, NODE_COMPARE_EQUAL});
+ if (ELEM(type, SOCK_BOOLEAN, SOCK_FLOAT, SOCK_RGBA, SOCK_VECTOR, SOCK_INT, SOCK_STRING)) {
+ const eNodeSocketDatatype mode_type = (type == SOCK_BOOLEAN) ? SOCK_FLOAT : type;
+ const bool string_type = (type == SOCK_STRING);
+ /* Add socket A compare operations. */
+ for (const EnumPropertyItem *item = rna_enum_node_compare_operation_items;
+ item->identifier != nullptr;
+ item++) {
+ if (item->name != nullptr && item->identifier[0] != '\0') {
+ if (!string_type &&
+ ELEM(item->value, NODE_COMPARE_COLOR_BRIGHTER, NODE_COMPARE_COLOR_DARKER)) {
+ params.add_item(IFACE_(item->name),
+ SocketSearchOp{"A", SOCK_RGBA, (NodeCompareOperation)item->value});
+ }
+ else if ((!string_type) ||
+ (string_type && ELEM(item->value, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL))) {
+ params.add_item(IFACE_(item->name),
+ SocketSearchOp{"A", mode_type, (NodeCompareOperation)item->value});
+ }
+ }
+ }
+ /* Add Angle socket. */
+ if (!string_type) {
+ params.add_item(
+ IFACE_("Angle"),
+ SocketSearchOp{
+ "Angle", SOCK_VECTOR, NODE_COMPARE_GREATER_THAN, NODE_COMPARE_MODE_DIRECTION});
+ }
}
}
@@ -526,7 +537,7 @@ void register_node_type_fn_compare()
namespace file_ns = blender::nodes::node_fn_compare_cc;
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_COMPARE, "Compare", NODE_CLASS_CONVERTER, 0);
+ fn_node_type_base(&ntype, FN_NODE_COMPARE, "Compare", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::fn_node_compare_declare;
ntype.labelfunc = file_ns::node_compare_label;
node_type_update(&ntype, file_ns::node_compare_update);
diff --git a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
index 21f6734e4aa..1a130e748d5 100644
--- a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
+++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
@@ -25,7 +25,7 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_float_to_int_cc {
static void fn_node_float_to_int_declare(NodeDeclarationBuilder &b)
{
@@ -81,16 +81,18 @@ static void fn_node_float_to_int_build_multi_function(NodeMultiFunctionBuilder &
builder.set_matching_fn(fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_float_to_int_cc
void register_node_type_fn_float_to_int()
{
+ namespace file_ns = blender::nodes::node_fn_float_to_int_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_float_to_int_declare;
- ntype.labelfunc = blender::nodes::node_float_to_int_label;
- ntype.build_multi_function = blender::nodes::fn_node_float_to_int_build_multi_function;
- ntype.draw_buttons = blender::nodes::fn_node_float_to_int_layout;
+ fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_float_to_int_declare;
+ ntype.labelfunc = file_ns::node_float_to_int_label;
+ ntype.build_multi_function = file_ns::fn_node_float_to_int_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_float_to_int_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_bool.cc b/source/blender/nodes/function/nodes/node_fn_input_bool.cc
index 1358bf8a223..b6f7c802cc9 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_bool.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_bool.cc
@@ -21,7 +21,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_bool_cc {
static void fn_node_input_bool_declare(NodeDeclarationBuilder &b)
{
@@ -43,22 +43,24 @@ static void fn_node_input_bool_build_multi_function(NodeMultiFunctionBuilder &bu
static void fn_node_input_bool_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeInputBool *data = (NodeInputBool *)MEM_callocN(sizeof(NodeInputBool), __func__);
+ NodeInputBool *data = MEM_cnew<NodeInputBool>(__func__);
node->storage = data;
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_input_bool_cc
void register_node_type_fn_input_bool()
{
+ namespace file_ns = blender::nodes::node_fn_input_bool_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_INPUT_BOOL, "Boolean", 0, 0);
- ntype.declare = blender::nodes::fn_node_input_bool_declare;
- node_type_init(&ntype, blender::nodes::fn_node_input_bool_init);
+ fn_node_type_base(&ntype, FN_NODE_INPUT_BOOL, "Boolean", 0);
+ ntype.declare = file_ns::fn_node_input_bool_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_bool_init);
node_type_storage(
&ntype, "NodeInputBool", node_free_standard_storage, node_copy_standard_storage);
- ntype.build_multi_function = blender::nodes::fn_node_input_bool_build_multi_function;
- ntype.draw_buttons = blender::nodes::fn_node_input_bool_layout;
+ ntype.build_multi_function = file_ns::fn_node_input_bool_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_bool_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_color.cc b/source/blender/nodes/function/nodes/node_fn_input_color.cc
index 43bb654b776..5ace57810e1 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_color.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_color.cc
@@ -19,7 +19,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_color_cc {
static void fn_node_input_color_declare(NodeDeclarationBuilder &b)
{
@@ -43,23 +43,25 @@ static void fn_node_input_color_build_multi_function(
static void fn_node_input_color_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeInputColor *data = (NodeInputColor *)MEM_callocN(sizeof(NodeInputColor), __func__);
+ NodeInputColor *data = MEM_cnew<NodeInputColor>(__func__);
copy_v4_fl4(data->color, 0.5f, 0.5f, 0.5f, 1.0f);
node->storage = data;
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_input_color_cc
void register_node_type_fn_input_color()
{
+ namespace file_ns = blender::nodes::node_fn_input_color_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_INPUT_COLOR, "Color", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::fn_node_input_color_declare;
- node_type_init(&ntype, blender::nodes::fn_node_input_color_init);
+ fn_node_type_base(&ntype, FN_NODE_INPUT_COLOR, "Color", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::fn_node_input_color_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_color_init);
node_type_storage(
&ntype, "NodeInputColor", node_free_standard_storage, node_copy_standard_storage);
- ntype.build_multi_function = blender::nodes::fn_node_input_color_build_multi_function;
- ntype.draw_buttons = blender::nodes::fn_node_input_color_layout;
+ ntype.build_multi_function = file_ns::fn_node_input_color_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_color_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_int.cc b/source/blender/nodes/function/nodes/node_fn_input_int.cc
index ddbb86e2661..d96339ae365 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_int.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_int.cc
@@ -21,7 +21,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_int_cc {
static void fn_node_input_int_declare(NodeDeclarationBuilder &b)
{
@@ -43,22 +43,24 @@ static void fn_node_input_int_build_multi_function(NodeMultiFunctionBuilder &bui
static void fn_node_input_int_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeInputInt *data = (NodeInputInt *)MEM_callocN(sizeof(NodeInputInt), __func__);
+ NodeInputInt *data = MEM_cnew<NodeInputInt>(__func__);
node->storage = data;
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_input_int_cc
void register_node_type_fn_input_int()
{
+ namespace file_ns = blender::nodes::node_fn_input_int_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_INPUT_INT, "Integer", 0, 0);
- ntype.declare = blender::nodes::fn_node_input_int_declare;
- node_type_init(&ntype, blender::nodes::fn_node_input_int_init);
+ fn_node_type_base(&ntype, FN_NODE_INPUT_INT, "Integer", 0);
+ ntype.declare = file_ns::fn_node_input_int_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_int_init);
node_type_storage(
&ntype, "NodeInputInt", node_free_standard_storage, node_copy_standard_storage);
- ntype.build_multi_function = blender::nodes::fn_node_input_int_build_multi_function;
- ntype.draw_buttons = blender::nodes::fn_node_input_int_layout;
+ ntype.build_multi_function = file_ns::fn_node_input_int_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_int_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc b/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
index c61af419e50..8137b424143 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc
@@ -16,7 +16,7 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_special_characters_cc {
static void fn_node_input_special_characters_declare(NodeDeclarationBuilder &b)
{
@@ -59,16 +59,17 @@ static void fn_node_input_special_characters_build_multi_function(
builder.set_matching_fn(special_characters_fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_input_special_characters_cc
void register_node_type_fn_input_special_characters()
{
+ namespace file_ns = blender::nodes::node_fn_input_special_characters_cc;
+
static bNodeType ntype;
fn_node_type_base(
- &ntype, FN_NODE_INPUT_SPECIAL_CHARACTERS, "Special Characters", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::fn_node_input_special_characters_declare;
- ntype.build_multi_function =
- blender::nodes::fn_node_input_special_characters_build_multi_function;
+ &ntype, FN_NODE_INPUT_SPECIAL_CHARACTERS, "Special Characters", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::fn_node_input_special_characters_declare;
+ ntype.build_multi_function = file_ns::fn_node_input_special_characters_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_string.cc b/source/blender/nodes/function/nodes/node_fn_input_string.cc
index dd2d1292601..a326caf50bd 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_string.cc
@@ -19,7 +19,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_string_cc {
static void fn_node_input_string_declare(NodeDeclarationBuilder &b)
{
@@ -71,20 +71,20 @@ static void fn_node_string_copy(bNodeTree *UNUSED(dest_ntree),
dest_node->storage = destination_storage;
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_input_string_cc
void register_node_type_fn_input_string()
{
+ namespace file_ns = blender::nodes::node_fn_input_string_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_INPUT_STRING, "String", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::fn_node_input_string_declare;
- node_type_init(&ntype, blender::nodes::fn_node_input_string_init);
- node_type_storage(&ntype,
- "NodeInputString",
- blender::nodes::fn_node_input_string_free,
- blender::nodes::fn_node_string_copy);
- ntype.build_multi_function = blender::nodes::fn_node_input_string_build_multi_function;
- ntype.draw_buttons = blender::nodes::fn_node_input_string_layout;
+ fn_node_type_base(&ntype, FN_NODE_INPUT_STRING, "String", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::fn_node_input_string_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_string_init);
+ node_type_storage(
+ &ntype, "NodeInputString", file_ns::fn_node_input_string_free, file_ns::fn_node_string_copy);
+ ntype.build_multi_function = file_ns::fn_node_input_string_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_string_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_input_vector.cc b/source/blender/nodes/function/nodes/node_fn_input_vector.cc
index 1e5fd186b5a..34515c4414c 100644
--- a/source/blender/nodes/function/nodes/node_fn_input_vector.cc
+++ b/source/blender/nodes/function/nodes/node_fn_input_vector.cc
@@ -21,7 +21,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_input_vector_cc {
static void fn_node_input_vector_declare(NodeDeclarationBuilder &b)
{
@@ -44,23 +44,24 @@ static void fn_node_input_vector_build_multi_function(NodeMultiFunctionBuilder &
static void fn_node_input_vector_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeInputVector *data = (NodeInputVector *)MEM_callocN(sizeof(NodeInputVector),
- "input vector node");
+ NodeInputVector *data = MEM_cnew<NodeInputVector>(__func__);
node->storage = data;
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_input_vector_cc
void register_node_type_fn_input_vector()
{
+ namespace file_ns = blender::nodes::node_fn_input_vector_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_INPUT_VECTOR, "Vector", 0, 0);
- ntype.declare = blender::nodes::fn_node_input_vector_declare;
- node_type_init(&ntype, blender::nodes::fn_node_input_vector_init);
+ fn_node_type_base(&ntype, FN_NODE_INPUT_VECTOR, "Vector", 0);
+ ntype.declare = file_ns::fn_node_input_vector_declare;
+ node_type_init(&ntype, file_ns::fn_node_input_vector_init);
node_type_storage(
&ntype, "NodeInputVector", node_free_standard_storage, node_copy_standard_storage);
- ntype.build_multi_function = blender::nodes::fn_node_input_vector_build_multi_function;
- ntype.draw_buttons = blender::nodes::fn_node_input_vector_layout;
+ ntype.build_multi_function = file_ns::fn_node_input_vector_build_multi_function;
+ ntype.draw_buttons = file_ns::fn_node_input_vector_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_random_value.cc b/source/blender/nodes/function/nodes/node_fn_random_value.cc
index b053482c99d..ceea6246cb0 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_value.cc
+++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc
@@ -24,7 +24,7 @@
#include "UI_interface.h"
#include "UI_resources.h"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_random_value_cc {
NODE_STORAGE_FUNCS(NodeRandomValue)
@@ -63,7 +63,7 @@ static void fn_node_random_value_layout(uiLayout *layout, bContext *UNUSED(C), P
static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeRandomValue *data = (NodeRandomValue *)MEM_callocN(sizeof(NodeRandomValue), __func__);
+ NodeRandomValue *data = MEM_cnew<NodeRandomValue>(__func__);
data->data_type = CD_PROP_FLOAT;
node->storage = data;
}
@@ -110,9 +110,8 @@ static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSock
case SOCK_INT:
return CD_PROP_INT32;
case SOCK_VECTOR:
- return CD_PROP_FLOAT3;
case SOCK_RGBA:
- return CD_PROP_COLOR;
+ return CD_PROP_FLOAT3;
default:
return {};
}
@@ -338,18 +337,21 @@ static void fn_node_random_value_build_multi_function(NodeMultiFunctionBuilder &
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_random_value_cc
void register_node_type_fn_random_value()
{
+ namespace file_ns = blender::nodes::node_fn_random_value_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_RANDOM_VALUE, "Random Value", NODE_CLASS_CONVERTER, 0);
- node_type_init(&ntype, blender::nodes::fn_node_random_value_init);
- node_type_update(&ntype, blender::nodes::fn_node_random_value_update);
- ntype.draw_buttons = blender::nodes::fn_node_random_value_layout;
- ntype.declare = blender::nodes::fn_node_random_value_declare;
- ntype.build_multi_function = blender::nodes::fn_node_random_value_build_multi_function;
- ntype.gather_link_search_ops = blender::nodes::fn_node_random_value_gather_link_search;
+
+ fn_node_type_base(&ntype, FN_NODE_RANDOM_VALUE, "Random Value", NODE_CLASS_CONVERTER);
+ node_type_init(&ntype, file_ns::fn_node_random_value_init);
+ node_type_update(&ntype, file_ns::fn_node_random_value_update);
+ ntype.draw_buttons = file_ns::fn_node_random_value_layout;
+ ntype.declare = file_ns::fn_node_random_value_declare;
+ ntype.build_multi_function = file_ns::fn_node_random_value_build_multi_function;
+ ntype.gather_link_search_ops = file_ns::fn_node_random_value_gather_link_search;
node_type_storage(
&ntype, "NodeRandomValue", node_free_standard_storage, node_copy_standard_storage);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/function/nodes/node_fn_replace_string.cc b/source/blender/nodes/function/nodes/node_fn_replace_string.cc
index 881a3c68e7d..243cb63d713 100644
--- a/source/blender/nodes/function/nodes/node_fn_replace_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_replace_string.cc
@@ -18,7 +18,7 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_replace_string_cc {
static void fn_node_replace_string_declare(NodeDeclarationBuilder &b)
{
@@ -53,14 +53,16 @@ static void fn_node_replace_string_build_multi_function(NodeMultiFunctionBuilder
builder.set_matching_fn(&substring_fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_replace_string_cc
void register_node_type_fn_replace_string()
{
+ namespace file_ns = blender::nodes::node_fn_replace_string_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_REPLACE_STRING, "Replace String", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_replace_string_declare;
- ntype.build_multi_function = blender::nodes::fn_node_replace_string_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_REPLACE_STRING, "Replace String", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_replace_string_declare;
+ ntype.build_multi_function = file_ns::fn_node_replace_string_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 7dbc11fb161..582a9bb10a8 100644
--- a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
+++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc
@@ -24,7 +24,7 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_rotate_euler_cc {
static void fn_node_rotate_euler_declare(NodeDeclarationBuilder &b)
{
@@ -125,15 +125,18 @@ static void fn_node_rotate_euler_build_multi_function(NodeMultiFunctionBuilder &
builder.set_matching_fn(fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_rotate_euler_cc
void register_node_type_fn_rotate_euler()
{
+ namespace file_ns = blender::nodes::node_fn_rotate_euler_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_ROTATE_EULER, "Rotate Euler", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_rotate_euler_declare;
- ntype.draw_buttons = blender::nodes::fn_node_rotate_euler_layout;
- node_type_update(&ntype, blender::nodes::fn_node_rotate_euler_update);
- ntype.build_multi_function = blender::nodes::fn_node_rotate_euler_build_multi_function;
+
+ fn_node_type_base(&ntype, FN_NODE_ROTATE_EULER, "Rotate Euler", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_rotate_euler_declare;
+ ntype.draw_buttons = file_ns::fn_node_rotate_euler_layout;
+ node_type_update(&ntype, file_ns::fn_node_rotate_euler_update);
+ ntype.build_multi_function = file_ns::fn_node_rotate_euler_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_slice_string.cc b/source/blender/nodes/function/nodes/node_fn_slice_string.cc
index 5cb753e8f34..f9d0af5ba9b 100644
--- a/source/blender/nodes/function/nodes/node_fn_slice_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_slice_string.cc
@@ -18,7 +18,7 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_slice_string_cc {
static void fn_node_slice_string_declare(NodeDeclarationBuilder &b)
{
@@ -40,14 +40,16 @@ static void fn_node_slice_string_build_multi_function(NodeMultiFunctionBuilder &
builder.set_matching_fn(&slice_fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_slice_string_cc
void register_node_type_fn_slice_string()
{
+ namespace file_ns = blender::nodes::node_fn_slice_string_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_SLICE_STRING, "Slice String", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_slice_string_declare;
- ntype.build_multi_function = blender::nodes::fn_node_slice_string_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_SLICE_STRING, "Slice String", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_slice_string_declare;
+ ntype.build_multi_function = file_ns::fn_node_slice_string_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_string_length.cc b/source/blender/nodes/function/nodes/node_fn_string_length.cc
index 63429d35993..8ab56812125 100644
--- a/source/blender/nodes/function/nodes/node_fn_string_length.cc
+++ b/source/blender/nodes/function/nodes/node_fn_string_length.cc
@@ -20,7 +20,7 @@
#include "node_function_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_fn_string_length_cc {
static void fn_node_string_length_declare(NodeDeclarationBuilder &b)
{
@@ -35,14 +35,16 @@ static void fn_node_string_length_build_multi_function(NodeMultiFunctionBuilder
builder.set_matching_fn(&str_len_fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_string_length_cc
void register_node_type_fn_string_length()
{
+ namespace file_ns = blender::nodes::node_fn_string_length_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_STRING_LENGTH, "String Length", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_string_length_declare;
- ntype.build_multi_function = blender::nodes::fn_node_string_length_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_STRING_LENGTH, "String Length", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_string_length_declare;
+ ntype.build_multi_function = file_ns::fn_node_string_length_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/function/nodes/node_fn_value_to_string.cc b/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
index 96a56760664..235c612dc15 100644
--- a/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
+++ b/source/blender/nodes/function/nodes/node_fn_value_to_string.cc
@@ -17,7 +17,7 @@
#include "node_function_util.hh"
#include <iomanip>
-namespace blender::nodes {
+namespace blender::nodes::node_fn_value_to_string_cc {
static void fn_node_value_to_string_declare(NodeDeclarationBuilder &b)
{
@@ -37,14 +37,16 @@ static void fn_node_value_to_string_build_multi_function(NodeMultiFunctionBuilde
builder.set_matching_fn(&to_str_fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_fn_value_to_string_cc
void register_node_type_fn_value_to_string()
{
+ namespace file_ns = blender::nodes::node_fn_value_to_string_cc;
+
static bNodeType ntype;
- fn_node_type_base(&ntype, FN_NODE_VALUE_TO_STRING, "Value to String", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::fn_node_value_to_string_declare;
- ntype.build_multi_function = blender::nodes::fn_node_value_to_string_build_multi_function;
+ fn_node_type_base(&ntype, FN_NODE_VALUE_TO_STRING, "Value to String", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::fn_node_value_to_string_declare;
+ ntype.build_multi_function = file_ns::fn_node_value_to_string_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt
index f9a64381981..e0c31fad97f 100644
--- a/source/blender/nodes/geometry/CMakeLists.txt
+++ b/source/blender/nodes/geometry/CMakeLists.txt
@@ -80,6 +80,7 @@ set(SRC
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
nodes/node_geo_attribute_remove.cc
@@ -105,8 +106,8 @@ set(SRC
nodes/node_geo_curve_reverse.cc
nodes/node_geo_curve_sample.cc
nodes/node_geo_curve_set_handles.cc
- nodes/node_geo_curve_spline_type.cc
nodes/node_geo_curve_spline_parameter.cc
+ nodes/node_geo_curve_spline_type.cc
nodes/node_geo_curve_subdivide.cc
nodes/node_geo_curve_to_mesh.cc
nodes/node_geo_curve_to_points.cc
@@ -123,6 +124,7 @@ set(SRC
nodes/node_geo_input_index.cc
nodes/node_geo_input_material_index.cc
nodes/node_geo_input_material.cc
+ nodes/node_geo_input_mesh_edge_angle.cc
nodes/node_geo_input_mesh_edge_neighbors.cc
nodes/node_geo_input_mesh_edge_vertices.cc
nodes/node_geo_input_mesh_face_area.cc
diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc
index 89ab4d9961e..a6dec71ed06 100644
--- a/source/blender/nodes/geometry/node_geometry_tree.cc
+++ b/source/blender/nodes/geometry/node_geometry_tree.cc
@@ -32,6 +32,8 @@
#include "RNA_access.h"
+#include "UI_resources.h"
+
#include "node_common.h"
bNodeTreeType *ntreeType_Geometry;
@@ -121,7 +123,7 @@ void register_node_tree_type_geo()
tt->type = NTREE_GEOMETRY;
strcpy(tt->idname, "GeometryNodeTree");
strcpy(tt->ui_name, N_("Geometry Node Editor"));
- tt->ui_icon = 0; /* Defined in `drawnode.c`. */
+ tt->ui_icon = ICON_NODETREE;
strcpy(tt->ui_description, N_("Geometry nodes"));
tt->rna_ext.srna = &RNA_GeometryNodeTree;
tt->update = geometry_node_tree_update;
diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc
index 49991a40c1b..ceb9a7e1467 100644
--- a/source/blender/nodes/geometry/node_geometry_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -89,9 +89,9 @@ bool geo_node_poll_default(bNodeType *UNUSED(ntype),
return true;
}
-void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = geo_node_poll_default;
ntype->insert_link = node_insert_link_default;
ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 3376b75d05b..3a6c5e38f82 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -36,8 +36,7 @@
#include "node_util.h"
-void geo_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void geo_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
bool geo_node_poll_default(struct bNodeType *ntype,
struct bNodeTree *ntree,
const char **r_disabled_hint);
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
index 4366c6f9234..36ad4605a4b 100644
--- 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
@@ -53,8 +53,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *)
- MEM_callocN(sizeof(NodeGeometryAlignRotationToVector), __func__);
+ 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;
@@ -228,8 +228,7 @@ void register_node_type_geo_align_rotation_to_vector()
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ALIGN_ROTATION_TO_VECTOR,
"Align Rotation to Vector",
- NODE_CLASS_GEOMETRY,
- 0);
+ NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(&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
index 7435152a966..cac2a90a76c 100644
--- 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
@@ -46,8 +46,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeClamp *data = (NodeAttributeClamp *)MEM_callocN(sizeof(NodeAttributeClamp),
- __func__);
+ NodeAttributeClamp *data = MEM_cnew<NodeAttributeClamp>(__func__);
data->data_type = CD_PROP_FLOAT;
data->operation = NODE_CLAMP_MINMAX;
node->storage = data;
@@ -271,7 +270,7 @@ void register_node_type_geo_attribute_clamp()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE, 0);
+ &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;
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
index 4efdf786e4e..672dbfdbf86 100644
--- 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
@@ -40,8 +40,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)MEM_callocN(
- sizeof(NodeAttributeColorRamp), __func__);
+ NodeAttributeColorRamp *node_storage = MEM_cnew<NodeAttributeColorRamp>(__func__);
BKE_colorband_init(&node_storage->color_ramp, true);
node->storage = node_storage;
}
@@ -125,11 +124,8 @@ void register_node_type_geo_attribute_color_ramp()
static bNodeType ntype;
- geo_node_type_base(&ntype,
- GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP,
- "Attribute Color Ramp",
- NODE_CLASS_ATTRIBUTE,
- 0);
+ 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);
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
index 7ba64c8db2b..403b9446f75 100644
--- 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
@@ -46,8 +46,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeCombineXYZ *data = (NodeAttributeCombineXYZ *)MEM_callocN(
- sizeof(NodeAttributeCombineXYZ), __func__);
+ NodeAttributeCombineXYZ *data = MEM_cnew<NodeAttributeCombineXYZ>(__func__);
data->input_type_x = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
data->input_type_y = GEO_NODE_ATTRIBUTE_INPUT_FLOAT;
@@ -139,8 +138,7 @@ void register_node_type_geo_attribute_combine_xyz()
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_COMBINE_XYZ,
"Attribute Combine XYZ",
- NODE_CLASS_ATTRIBUTE,
- 0);
+ NODE_CLASS_ATTRIBUTE);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(
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
index 8aa1adb0cf3..6cec73d76a2 100644
--- 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
@@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeCompare *data = (NodeAttributeCompare *)MEM_callocN(sizeof(NodeAttributeCompare),
- __func__);
+ 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;
@@ -348,7 +347,7 @@ void register_node_type_geo_attribute_compare()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_COMPARE, "Attribute Compare", NODE_CLASS_ATTRIBUTE, 0);
+ &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;
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
index 28c133871f7..2b13f57e990 100644
--- 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
@@ -39,8 +39,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeConvert *data = (NodeAttributeConvert *)MEM_callocN(sizeof(NodeAttributeConvert),
- __func__);
+ NodeAttributeConvert *data = MEM_cnew<NodeAttributeConvert>(__func__);
data->data_type = CD_AUTO_FROM_NAME;
data->domain = ATTR_DOMAIN_AUTO;
@@ -182,7 +181,7 @@ void register_node_type_geo_attribute_convert()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CONVERT, "Attribute Convert", NODE_CLASS_ATTRIBUTE, 0);
+ &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;
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
index 0a7b5dd8463..8e1e763f1ad 100644
--- 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
@@ -75,8 +75,7 @@ static void node_copy_storage(bNodeTree *UNUSED(dest_ntree),
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)MEM_callocN(sizeof(NodeAttributeCurveMap),
- __func__);
+ 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);
@@ -210,7 +209,7 @@ void register_node_type_geo_attribute_curve_map()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP, "Attribute Curve Map", NODE_CLASS_ATTRIBUTE, 0);
+ &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);
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
index a05bcf1bed8..a32e3b7412f 100644
--- 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
@@ -155,7 +155,7 @@ void register_node_type_geo_attribute_fill()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_FILL, "Attribute Fill", NODE_CLASS_ATTRIBUTE, 0);
+ &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;
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
index 8ebcf34ad0b..398af087499 100644
--- 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
@@ -51,8 +51,7 @@ static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C),
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeMapRange *data = (NodeAttributeMapRange *)MEM_callocN(sizeof(NodeAttributeMapRange),
- __func__);
+ NodeAttributeMapRange *data = MEM_cnew<NodeAttributeMapRange>(__func__);
data->data_type = CD_PROP_FLOAT;
data->interpolation_type = NODE_MAP_RANGE_LINEAR;
@@ -425,7 +424,7 @@ void register_node_type_geo_attribute_map_range()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE, "Attribute Map Range", NODE_CLASS_ATTRIBUTE, 0);
+ &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);
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
index e0a829b4100..3257d2d7358 100644
--- 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
@@ -121,7 +121,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeMath *data = (NodeAttributeMath *)MEM_callocN(sizeof(NodeAttributeMath), __func__);
+ NodeAttributeMath *data = MEM_cnew<NodeAttributeMath>(__func__);
data->operation = NODE_MATH_ADD;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
@@ -309,7 +309,7 @@ void register_node_type_geo_attribute_math()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MATH, "Attribute Math", NODE_CLASS_ATTRIBUTE, 0);
+ &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;
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
index 4a110e9690a..c0c30898584 100644
--- 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
@@ -61,8 +61,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeMix *data = (NodeAttributeMix *)MEM_callocN(sizeof(NodeAttributeMix),
- "attribute mix 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;
@@ -248,8 +247,7 @@ void register_node_type_geo_attribute_mix()
namespace file_ns = blender::nodes::node_geo_legacy_attribute_mix_cc;
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MIX, "Attribute Mix", NODE_CLASS_ATTRIBUTE, 0);
+ 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;
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
index 080bf38a740..74dac73f255 100644
--- 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
@@ -44,8 +44,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryAttributeProximity *node_storage = (NodeGeometryAttributeProximity *)MEM_callocN(
- sizeof(NodeGeometryAttributeProximity), __func__);
+ NodeGeometryAttributeProximity *node_storage = MEM_cnew<NodeGeometryAttributeProximity>(
+ __func__);
node_storage->target_geometry_element = GEO_NODE_PROXIMITY_TARGET_FACES;
node->storage = node_storage;
@@ -237,7 +237,7 @@ void register_node_type_geo_legacy_attribute_proximity()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Attribute Proximity", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Attribute Proximity", NODE_CLASS_ATTRIBUTE);
node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryAttributeProximity",
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
index ab2bc7b379c..92a946b225b 100644
--- 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
@@ -81,8 +81,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeRandomize *data = (NodeAttributeRandomize *)MEM_callocN(
- sizeof(NodeAttributeRandomize), __func__);
+ 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;
@@ -335,7 +334,7 @@ void register_node_type_geo_legacy_attribute_randomize()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE, 0);
+ &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);
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
index bc18cb32e73..ae034d152be 100644
--- 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
@@ -130,8 +130,7 @@ void register_node_type_geo_sample_texture()
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE,
"Attribute Sample Texture",
- NODE_CLASS_ATTRIBUTE,
- 0);
+ 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;
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
index c5aac118baf..960ec540556 100644
--- 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
@@ -41,8 +41,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeSeparateXYZ *data = (NodeAttributeSeparateXYZ *)MEM_callocN(
- sizeof(NodeAttributeSeparateXYZ), __func__);
+ NodeAttributeSeparateXYZ *data = MEM_cnew<NodeAttributeSeparateXYZ>(__func__);
data->input_type = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
node->storage = data;
}
@@ -160,8 +159,7 @@ void register_node_type_geo_attribute_separate_xyz()
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ,
"Attribute Separate XYZ",
- NODE_CLASS_ATTRIBUTE,
- 0);
+ 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);
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
index 686edc80f62..b0210f2eb94 100644
--- 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
@@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryAttributeTransfer *data = (NodeGeometryAttributeTransfer *)MEM_callocN(
- sizeof(NodeGeometryAttributeTransfer), __func__);
+ NodeGeometryAttributeTransfer *data = MEM_cnew<NodeGeometryAttributeTransfer>(__func__);
data->domain = ATTR_DOMAIN_AUTO;
node->storage = data;
}
@@ -517,7 +516,7 @@ void register_node_type_geo_legacy_attribute_transfer()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, "Attribute Transfer", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, "Attribute Transfer", NODE_CLASS_ATTRIBUTE);
node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryAttributeTransfer",
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
index 68051e81f57..5b3c3c05a6a 100644
--- 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
@@ -103,8 +103,7 @@ static CustomDataType operation_get_read_type_c(const NodeVectorMathOperation op
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeAttributeVectorMath *data = (NodeAttributeVectorMath *)MEM_callocN(
- sizeof(NodeAttributeVectorMath), __func__);
+ NodeAttributeVectorMath *data = MEM_cnew<NodeAttributeVectorMath>(__func__);
data->operation = NODE_VECTOR_MATH_ADD;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
@@ -560,8 +559,7 @@ void register_node_type_geo_attribute_vector_math()
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_MATH,
"Attribute Vector Math",
- NODE_CLASS_ATTRIBUTE,
- 0);
+ 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;
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
index 1ef50e69775..3738c4ad14d 100644
--- 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
@@ -112,8 +112,7 @@ static float3 vector_rotate_around_axis(const float3 vector,
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)MEM_callocN(
- sizeof(NodeAttributeVectorRotate), __func__);
+ 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;
@@ -337,8 +336,7 @@ void register_node_type_geo_attribute_vector_rotate()
geo_node_type_base(&ntype,
GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_ROTATE,
"Attribute Vector Rotate",
- NODE_CLASS_ATTRIBUTE,
- 0);
+ 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);
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
index e61dee4bee1..51564d8d200 100644
--- 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
@@ -213,7 +213,7 @@ void register_node_type_geo_legacy_curve_endpoints()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY, 0);
+ &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;
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
index 7c550495b41..844baa53962 100644
--- 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
@@ -65,8 +65,7 @@ void register_node_type_geo_legacy_curve_reverse()
namespace file_ns = blender::nodes::node_geo_legacy_curve_reverse_cc;
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY, 0);
+ 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
index c702e9ff686..780756bcbca 100644
--- 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
@@ -40,8 +40,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN(
- sizeof(NodeGeometryCurveSelectHandles), __func__);
+ 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;
@@ -127,11 +126,8 @@ void register_node_type_geo_legacy_select_by_handle_type()
static bNodeType ntype;
- geo_node_type_base(&ntype,
- GEO_NODE_LEGACY_CURVE_SELECT_HANDLES,
- "Select by Handle Type",
- NODE_CLASS_GEOMETRY,
- 0);
+ 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);
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
index 1e476d01148..a82b917e817 100644
--- 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
@@ -38,8 +38,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN(
- sizeof(NodeGeometryCurveSetHandles), __func__);
+ 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;
@@ -130,7 +129,7 @@ void register_node_type_geo_legacy_curve_set_handles()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0);
+ &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);
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
index f3599f4328f..6fd82e6a1bb 100644
--- 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
@@ -39,8 +39,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN(
- sizeof(NodeGeometryCurveSplineType), __func__);
+ NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__);
data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
node->storage = data;
@@ -288,7 +287,7 @@ void register_node_type_geo_legacy_curve_spline_type()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0);
+ &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);
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
index 9878402dd35..4621a1656aa 100644
--- 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
@@ -44,8 +44,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSubdivide *data = (NodeGeometryCurveSubdivide *)MEM_callocN(
- sizeof(NodeGeometryCurveSubdivide), __func__);
+ NodeGeometryCurveSubdivide *data = MEM_cnew<NodeGeometryCurveSubdivide>(__func__);
data->cuts_type = GEO_NODE_ATTRIBUTE_INPUT_INTEGER;
node->storage = data;
@@ -379,7 +378,7 @@ void register_node_type_geo_legacy_curve_subdivide()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, "Curve Subdivide", NODE_CLASS_GEOMETRY, 0);
+ &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,
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
index 3bd03f3cee0..8555d7cc8a3 100644
--- 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
@@ -95,8 +95,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN(
- sizeof(NodeGeometryCurveToPoints), __func__);
+ NodeGeometryCurveToPoints *data = MEM_cnew<NodeGeometryCurveToPoints>(__func__);
data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT;
node->storage = data;
@@ -353,7 +352,7 @@ void register_node_type_geo_legacy_curve_to_points()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0);
+ &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;
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
index abd75e710ae..0953d05bc36 100644
--- 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
@@ -671,7 +671,7 @@ void register_node_type_geo_legacy_delete_geometry()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0);
+ &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;
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
index c046fda4686..e628edb7e17 100644
--- 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
@@ -84,7 +84,7 @@ void register_node_type_geo_legacy_edge_split()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_LEGACY_EDGE_SPLIT, "Edge Split", NODE_CLASS_GEOMETRY, 0);
+ 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
index 88e8374f5d6..8fd6b1e299f 100644
--- 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
@@ -90,7 +90,7 @@ void register_node_type_geo_legacy_material_assign()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY, 0);
+ &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
index 2ff7410f3f6..d026fff003f 100644
--- 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
@@ -73,8 +73,7 @@ void register_node_type_geo_legacy_mesh_to_curve()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0);
+ 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
index 2451a7447ec..c712e82ca18 100644
--- 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
@@ -662,7 +662,7 @@ void register_node_type_geo_point_distribute()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0);
+ &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;
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
index 8915a58feb1..faf0b1a5fe7 100644
--- 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
@@ -46,8 +46,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryPointInstance *data = (NodeGeometryPointInstance *)MEM_callocN(
- sizeof(NodeGeometryPointInstance), __func__);
+ 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;
@@ -271,7 +270,7 @@ void register_node_type_geo_point_instance()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINT_INSTANCE, "Point Instance", NODE_CLASS_GEOMETRY, 0);
+ &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);
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
index a0a7674797a..ad87ec5541b 100644
--- 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
@@ -59,8 +59,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)MEM_callocN(
- sizeof(NodeGeometryRotatePoints), __func__);
+ 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;
@@ -226,7 +225,7 @@ void register_node_type_geo_point_rotate()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_ROTATE, "Point Rotate", NODE_CLASS_GEOMETRY, 0);
+ 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(
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
index d38df124979..69e69a24e29 100644
--- 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
@@ -43,8 +43,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryPointScale *data = (NodeGeometryPointScale *)MEM_callocN(
- sizeof(NodeGeometryPointScale), __func__);
+ NodeGeometryPointScale *data = MEM_cnew<NodeGeometryPointScale>(__func__);
data->input_type = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
node->storage = data;
@@ -128,7 +127,7 @@ void register_node_type_geo_point_scale()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_SCALE, "Point Scale", NODE_CLASS_GEOMETRY, 0);
+ 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);
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
index 9260928b311..b9760587706 100644
--- 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
@@ -171,7 +171,7 @@ void register_node_type_geo_point_separate()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY, 0);
+ &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;
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
index c70478182ec..385c3d9f22d 100644
--- 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
@@ -74,8 +74,7 @@ static void node_geo_exec(GeoNodeExecParams params)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryPointTranslate *data = (NodeGeometryPointTranslate *)MEM_callocN(
- sizeof(NodeGeometryPointTranslate), __func__);
+ NodeGeometryPointTranslate *data = MEM_cnew<NodeGeometryPointTranslate>(__func__);
data->input_type = GEO_NODE_ATTRIBUTE_INPUT_VECTOR;
node->storage = data;
@@ -98,7 +97,7 @@ void register_node_type_geo_point_translate()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINT_TRANSLATE, "Point Translate", NODE_CLASS_GEOMETRY, 0);
+ &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,
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
index ec1ab67b530..7b1bbed8ae4 100644
--- 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
@@ -51,8 +51,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN(
- sizeof(NodeGeometryPointsToVolume), __func__);
+ 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;
@@ -266,7 +265,7 @@ void register_node_type_geo_legacy_points_to_volume()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_LEGACY_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY);
node_type_storage(&ntype,
"NodeGeometryPointsToVolume",
node_free_standard_storage,
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
index 599ffd617a5..dd03092a594 100644
--- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc
@@ -58,8 +58,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast),
- __func__);
+ 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;
@@ -315,7 +314,7 @@ void register_node_type_geo_legacy_raycast()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_LEGACY_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0);
+ 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);
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
index b61ba5ff67e..59ac697b658 100644
--- 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
@@ -87,7 +87,7 @@ void register_node_type_geo_legacy_select_by_material()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, "Select by Material", NODE_CLASS_GEOMETRY, 0);
+ &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
index 819ffb2c20c..7c5553cb5e4 100644
--- 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
@@ -47,8 +47,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN(
- sizeof(NodeGeometrySubdivisionSurface), __func__);
+ NodeGeometrySubdivisionSurface *data = MEM_cnew<NodeGeometrySubdivisionSurface>(__func__);
data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL;
node->storage = data;
@@ -133,7 +132,7 @@ void register_node_type_geo_legacy_subdivision_surface()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0);
+ &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;
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
index acff0be7126..42fbc49ed4b 100644
--- 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
@@ -57,8 +57,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
- sizeof(NodeGeometryVolumeToMesh), __func__);
+ NodeGeometryVolumeToMesh *data = MEM_cnew<NodeGeometryVolumeToMesh>(__func__);
data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Density");
@@ -164,7 +163,7 @@ void register_node_type_geo_legacy_volume_to_mesh()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0);
+ &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);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
new file mode 100644
index 00000000000..6c2e72cf14f
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc
@@ -0,0 +1,430 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BKE_attribute_math.hh"
+
+#include "NOD_socket_search_link.hh"
+
+#include "node_geometry_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+namespace blender::nodes::node_geo_accumulate_field_cc {
+
+NODE_STORAGE_FUNCS(NodeAccumulateField)
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ std::string value_in_description = "The values to be accumulated";
+ std::string leading_out_description =
+ "The running total of values in the corresponding group, starting at the first value";
+ std::string trailing_out_description =
+ "The running total of values in the corresponding group, starting at zero";
+ std::string total_out_description = "The total of all of the values in the corresponding group";
+
+ b.add_input<decl::Vector>(N_("Value"), "Value Vector")
+ .default_value({1.0f, 1.0f, 1.0f})
+ .supports_field()
+ .description(N_(value_in_description));
+ b.add_input<decl::Float>(N_("Value"), "Value Float")
+ .default_value(1.0f)
+ .supports_field()
+ .description(N_(value_in_description));
+ b.add_input<decl::Int>(N_("Value"), "Value Int")
+ .default_value(1)
+ .supports_field()
+ .description(N_(value_in_description));
+ b.add_input<decl::Int>(N_("Group Index"))
+ .supports_field()
+ .description(
+ N_("An index used to group values together for multiple separate accumulations"));
+
+ b.add_output<decl::Vector>(N_("Leading"), "Leading Vector")
+ .field_source()
+ .description(N_(leading_out_description));
+ b.add_output<decl::Float>(N_("Leading"), "Leading Float")
+ .field_source()
+ .description(N_(leading_out_description));
+ b.add_output<decl::Int>(N_("Leading"), "Leading Int")
+ .field_source()
+ .description(N_(leading_out_description));
+
+ b.add_output<decl::Vector>(N_("Trailing"), "Trailing Vector")
+ .field_source()
+ .description(N_(trailing_out_description));
+ b.add_output<decl::Float>(N_("Trailing"), "Trailing Float")
+ .field_source()
+ .description(N_(trailing_out_description));
+ b.add_output<decl::Int>(N_("Trailing"), "Trailing Int")
+ .field_source()
+ .description(N_(trailing_out_description));
+
+ b.add_output<decl::Vector>(N_("Total"), "Total Vector")
+ .field_source()
+ .description(N_(total_out_description));
+ b.add_output<decl::Float>(N_("Total"), "Total Float")
+ .field_source()
+ .description(N_(total_out_description));
+ b.add_output<decl::Int>(N_("Total"), "Total Int")
+ .field_source()
+ .description(N_(total_out_description));
+}
+
+static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "domain", 0, "", ICON_NONE);
+}
+
+static void node_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeAccumulateField *data = MEM_cnew<NodeAccumulateField>(__func__);
+ data->data_type = CD_PROP_FLOAT;
+ data->domain = ATTR_DOMAIN_POINT;
+ node->storage = data;
+}
+
+static void node_update(bNodeTree *ntree, bNode *node)
+{
+ const NodeAccumulateField &storage = node_storage(*node);
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+
+ bNodeSocket *sock_in_vector = (bNodeSocket *)node->inputs.first;
+ bNodeSocket *sock_in_float = sock_in_vector->next;
+ bNodeSocket *sock_in_int = sock_in_float->next;
+
+ bNodeSocket *sock_out_vector = (bNodeSocket *)node->outputs.first;
+ bNodeSocket *sock_out_float = sock_out_vector->next;
+ bNodeSocket *sock_out_int = sock_out_float->next;
+
+ bNodeSocket *sock_out_first_vector = sock_out_int->next;
+ bNodeSocket *sock_out_first_float = sock_out_first_vector->next;
+ bNodeSocket *sock_out_first_int = sock_out_first_float->next;
+ bNodeSocket *sock_out_total_vector = sock_out_first_int->next;
+ bNodeSocket *sock_out_total_float = sock_out_total_vector->next;
+ bNodeSocket *sock_out_total_int = sock_out_total_float->next;
+
+ nodeSetSocketAvailability(ntree, sock_in_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_in_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_in_int, data_type == CD_PROP_INT32);
+
+ nodeSetSocketAvailability(ntree, sock_out_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_out_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_out_int, data_type == CD_PROP_INT32);
+
+ nodeSetSocketAvailability(ntree, sock_out_first_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_out_first_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_out_first_int, data_type == CD_PROP_INT32);
+
+ nodeSetSocketAvailability(ntree, sock_out_total_vector, data_type == CD_PROP_FLOAT3);
+ nodeSetSocketAvailability(ntree, sock_out_total_float, data_type == CD_PROP_FLOAT);
+ nodeSetSocketAvailability(ntree, sock_out_total_int, data_type == CD_PROP_INT32);
+}
+
+enum class AccumulationMode { Leading = 0, Trailing = 1 };
+
+static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+{
+ switch (socket.type) {
+ case SOCK_FLOAT:
+ return CD_PROP_FLOAT;
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ return CD_PROP_INT32;
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ return CD_PROP_FLOAT3;
+ default:
+ return {};
+ }
+}
+
+static void node_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ if (!type) {
+ return;
+ }
+ if (params.in_out() == SOCK_OUT) {
+ params.add_item(
+ IFACE_("Leading"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Leading");
+ },
+ 0);
+ params.add_item(
+ IFACE_("Trailing"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Trailing");
+ },
+ -1);
+ params.add_item(
+ IFACE_("Total"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Total");
+ },
+ -2);
+ }
+ else {
+ params.add_item(
+ IFACE_("Value"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Value");
+ },
+ 0);
+
+ params.add_item(
+ IFACE_("Group Index"),
+ [type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node("GeometryNodeAccumulateField");
+ node_storage(node).data_type = *type;
+ params.update_and_connect_available_socket(node, "Group Index");
+ },
+ -1);
+ }
+}
+
+template<typename T> class AccumulateFieldInput final : public GeometryFieldInput {
+ private:
+ Field<T> input_;
+ Field<int> group_index_;
+ AttributeDomain source_domain_;
+ AccumulationMode accumulation_mode_;
+
+ public:
+ AccumulateFieldInput(const AttributeDomain source_domain,
+ Field<T> input,
+ Field<int> group_index,
+ AccumulationMode accumulation_mode)
+ : GeometryFieldInput(CPPType::get<T>(), "Accumulation"),
+ input_(input),
+ group_index_(group_index),
+ source_domain_(source_domain),
+ accumulation_mode_(accumulation_mode)
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ const GeometryComponentFieldContext field_context{component, source_domain_};
+ const int domain_size = component.attribute_domain_size(field_context.domain());
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(input_);
+ evaluator.add(group_index_);
+ evaluator.evaluate();
+ const VArray<T> &values = evaluator.get_evaluated<T>(0);
+ const VArray<int> &group_indices = evaluator.get_evaluated<int>(1);
+
+ Array<T> accumulations_out(domain_size);
+
+ if (group_indices.is_single()) {
+ T accumulation = T();
+ if (accumulation_mode_ == AccumulationMode::Leading) {
+ for (const int i : values.index_range()) {
+ accumulation = values[i] + accumulation;
+ accumulations_out[i] = accumulation;
+ }
+ }
+ else {
+ for (const int i : values.index_range()) {
+ accumulations_out[i] = accumulation;
+ accumulation = values[i] + accumulation;
+ }
+ }
+ }
+ else {
+ Map<int, T> accumulations;
+ if (accumulation_mode_ == AccumulationMode::Leading) {
+ for (const int i : values.index_range()) {
+ T &accumulation_value = accumulations.lookup_or_add_default(group_indices[i]);
+ accumulation_value += values[i];
+ accumulations_out[i] = accumulation_value;
+ }
+ }
+ else {
+ for (const int i : values.index_range()) {
+ T &accumulation_value = accumulations.lookup_or_add_default(group_indices[i]);
+ accumulations_out[i] = accumulation_value;
+ accumulation_value += values[i];
+ }
+ }
+ }
+
+ return component.attribute_try_adapt_domain<T>(
+ VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ return get_default_hash_4(input_, group_index_, source_domain_, accumulation_mode_);
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const AccumulateFieldInput *other_accumulate = dynamic_cast<const AccumulateFieldInput *>(
+ &other)) {
+ return input_ == other_accumulate->input_ &&
+ group_index_ == other_accumulate->group_index_ &&
+ source_domain_ == other_accumulate->source_domain_ &&
+ accumulation_mode_ == other_accumulate->accumulation_mode_;
+ }
+ return false;
+ }
+};
+
+template<typename T> class TotalFieldInput final : public GeometryFieldInput {
+ private:
+ Field<T> input_;
+ Field<int> group_index_;
+ AttributeDomain source_domain_;
+
+ public:
+ TotalFieldInput(const AttributeDomain source_domain, Field<T> input, Field<int> group_index)
+ : GeometryFieldInput(CPPType::get<T>(), "Total Value"),
+ input_(input),
+ group_index_(group_index),
+ source_domain_(source_domain)
+ {
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ const GeometryComponentFieldContext field_context{component, source_domain_};
+ const int domain_size = component.attribute_domain_size(field_context.domain());
+
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(input_);
+ evaluator.add(group_index_);
+ evaluator.evaluate();
+ const VArray<T> &values = evaluator.get_evaluated<T>(0);
+ const VArray<int> &group_indices = evaluator.get_evaluated<int>(1);
+
+ if (group_indices.is_single()) {
+ T accumulation = T();
+ for (const int i : values.index_range()) {
+ accumulation = values[i] + accumulation;
+ }
+ return VArray<T>::ForSingle(accumulation, domain_size);
+ }
+
+ Array<T> accumulations_out(domain_size);
+ Map<int, T> accumulations;
+ for (const int i : values.index_range()) {
+ T &value = accumulations.lookup_or_add_default(group_indices[i]);
+ value = value + values[i];
+ }
+ for (const int i : values.index_range()) {
+ accumulations_out[i] = accumulations.lookup(group_indices[i]);
+ }
+
+ return component.attribute_try_adapt_domain<T>(
+ VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ return get_default_hash_3(input_, group_index_, source_domain_);
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ if (const TotalFieldInput *other_field = dynamic_cast<const TotalFieldInput *>(&other)) {
+ return input_ == other_field->input_ && group_index_ == other_field->group_index_ &&
+ source_domain_ == other_field->source_domain_;
+ }
+ return false;
+ }
+};
+
+template<typename T> std::string identifier_suffix()
+{
+ if constexpr (std::is_same_v<T, int>) {
+ return "Int";
+ }
+ if constexpr (std::is_same_v<T, float>) {
+ return "Float";
+ }
+ if constexpr (std::is_same_v<T, float3>) {
+ return "Vector";
+ }
+}
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ const NodeAccumulateField &storage = node_storage(params.node());
+ const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type);
+ const AttributeDomain source_domain = static_cast<AttributeDomain>(storage.domain);
+
+ Field<int> group_index_field = params.extract_input<Field<int>>("Group Index");
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ if constexpr (std::is_same_v<T, int> || std::is_same_v<T, float> ||
+ std::is_same_v<T, float3>) {
+ const std::string suffix = " " + identifier_suffix<T>();
+ Field<T> input_field = params.extract_input<Field<T>>("Value" + suffix);
+ if (params.output_is_required("Leading" + suffix)) {
+ params.set_output(
+ "Leading" + suffix,
+ Field<T>{std::make_shared<AccumulateFieldInput<T>>(
+ source_domain, input_field, group_index_field, AccumulationMode::Leading)});
+ }
+ if (params.output_is_required("Trailing" + suffix)) {
+ params.set_output(
+ "Trailing" + suffix,
+ Field<T>{std::make_shared<AccumulateFieldInput<T>>(
+ source_domain, input_field, group_index_field, AccumulationMode::Trailing)});
+ }
+ if (params.output_is_required("Total" + suffix)) {
+ params.set_output("Total" + suffix,
+ Field<T>{std::make_shared<TotalFieldInput<T>>(
+ source_domain, input_field, group_index_field)});
+ }
+ }
+ });
+}
+} // namespace blender::nodes::node_geo_accumulate_field_cc
+
+void register_node_type_geo_accumulate_field()
+{
+ namespace file_ns = blender::nodes::node_geo_accumulate_field_cc;
+
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_ACCUMULATE_FIELD, "Accumulate Field", NODE_CLASS_CONVERTER);
+ 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);
+ ntype.draw_buttons = file_ns::node_layout;
+ ntype.declare = file_ns::node_declare;
+ ntype.gather_link_search_ops = file_ns::node_gather_link_searches;
+ node_type_storage(
+ &ntype, "NodeAccumulateField", node_free_standard_storage, node_copy_standard_storage);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
index be0baa706af..9001cb2d1f2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc
@@ -54,8 +54,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryAttributeCapture *data = (NodeGeometryAttributeCapture *)MEM_callocN(
- sizeof(NodeGeometryAttributeCapture), __func__);
+ NodeGeometryAttributeCapture *data = MEM_cnew<NodeGeometryAttributeCapture>(__func__);
data->data_type = CD_PROP_FLOAT;
data->domain = ATTR_DOMAIN_POINT;
@@ -235,7 +234,7 @@ void register_node_type_geo_attribute_capture()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_CAPTURE_ATTRIBUTE, "Capture Attribute", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_CAPTURE_ATTRIBUTE, "Capture Attribute", NODE_CLASS_ATTRIBUTE);
node_type_storage(&ntype,
"NodeGeometryAttributeCapture",
node_free_standard_storage,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
index d6662e4e637..609ef39eb3f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc
@@ -143,8 +143,7 @@ void register_node_type_geo_attribute_domain_size()
namespace file_ns = blender::nodes::node_geo_attribute_domain_size_cc;
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, "Domain Size", NODE_CLASS_ATTRIBUTE, 0);
+ geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, "Domain Size", NODE_CLASS_ATTRIBUTE);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
ntype.draw_buttons = file_ns::node_layout;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
index 6f26b2c756b..8ed50b2cc75 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc
@@ -74,8 +74,7 @@ void register_node_type_geo_attribute_remove()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE, 0);
+ geo_node_type_base(&ntype, GEO_NODE_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/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
index b79125d43d1..7df032b150b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc
@@ -132,27 +132,24 @@ static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSock
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
{
const bNodeType &node_type = params.node_type();
+ const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
+ search_link_ops_for_declarations(params, declaration.inputs().take_front(2));
+
const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ if (!type) {
+ return;
+ }
+
if (params.in_out() == SOCK_IN) {
- if (params.other_socket().type == SOCK_GEOMETRY) {
- params.add_item(IFACE_("Geometry"), [node_type](LinkSearchOpParams &params) {
- bNode &node = params.add_node(node_type);
- params.connect_available_socket(node, "Geometry");
- });
- }
- if (type) {
- params.add_item(IFACE_("Attribute"), [&](LinkSearchOpParams &params) {
- bNode &node = params.add_node(node_type);
- node.custom1 = *type;
- params.update_and_connect_available_socket(node, "Attribute");
- });
- }
+ params.add_item(IFACE_("Attribute"), [node_type, type](LinkSearchOpParams &params) {
+ bNode &node = params.add_node(node_type);
+ node.custom1 = *type;
+ params.update_and_connect_available_socket(node, "Attribute");
+ });
}
- else if (type) {
- /* Only use the first 8 declarations since we set the type automatically. */
- const NodeDeclaration &declaration = *params.node_type().fixed_declaration;
- for (const SocketDeclarationPtr &socket_decl : declaration.outputs().take_front(8)) {
- StringRefNull name = socket_decl->name();
+ else {
+ for (const StringRefNull name :
+ {"Mean", "Median", "Sum", "Min", "Max", "Range", "Standard Deviation", "Variance"}) {
params.add_item(IFACE_(name.c_str()), [node_type, name, type](LinkSearchOpParams &params) {
bNode &node = params.add_node(node_type);
node.custom1 = *type;
@@ -402,7 +399,7 @@ void register_node_type_geo_attribute_statistic()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_ATTRIBUTE_STATISTIC, "Attribute Statistic", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_ATTRIBUTE_STATISTIC, "Attribute Statistic", NODE_CLASS_ATTRIBUTE);
ntype.declare = file_ns::node_declare;
node_type_init(&ntype, file_ns::node_init);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
index 0947632cc09..a9158e0ef7a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc
@@ -127,7 +127,7 @@ void register_node_type_geo_boolean()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_BOOLEAN, "Mesh Boolean", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_BOOLEAN, "Mesh Boolean", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.draw_buttons = file_ns::node_layout;
ntype.updatefunc = file_ns::node_update;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
index da1f9a00c69..465bd72b57a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
@@ -86,7 +86,7 @@ void register_node_type_geo_bounding_box()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_BOUNDING_BOX, "Bounding Box", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_BOUNDING_BOX, "Bounding Box", 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/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
index 6b8c895879d..43816b8d8dc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc
@@ -51,8 +51,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCollectionInfo *data = (NodeGeometryCollectionInfo *)MEM_callocN(
- sizeof(NodeGeometryCollectionInfo), __func__);
+ NodeGeometryCollectionInfo *data = MEM_cnew<NodeGeometryCollectionInfo>(__func__);
data->transform_space = GEO_NODE_TRANSFORM_SPACE_ORIGINAL;
node->storage = data;
}
@@ -163,7 +162,7 @@ void register_node_type_geo_collection_info()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
node_type_init(&ntype, file_ns::node_node_init);
node_type_storage(&ntype,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_common.cc b/source/blender/nodes/geometry/nodes/node_geo_common.cc
index 64b7a80bdb4..1e00ea3d896 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_common.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_common.cc
@@ -26,7 +26,7 @@ void register_node_type_geo_group()
{
static bNodeType ntype;
- node_type_base_custom(&ntype, "GeometryNodeGroup", "Group", NODE_CLASS_GROUP, 0);
+ node_type_base_custom(&ntype, "GeometryNodeGroup", "Group", NODE_CLASS_GROUP);
ntype.type = NODE_GROUP;
ntype.poll = geo_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
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 56c1e95bd70..11bb8a61df5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -324,7 +324,7 @@ void register_node_type_geo_convex_hull()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CONVEX_HULL, "Convex Hull", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CONVEX_HULL, "Convex Hull", 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/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc
index fc407414667..13a3d6534a3 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
@@ -139,7 +139,7 @@ void register_node_type_geo_curve_endpoint_selection()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_CURVE_ENDPOINT_SELECTION, "Endpoint Selection", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_CURVE_ENDPOINT_SELECTION, "Endpoint Selection", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
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 3aabf8e21eb..7e09721273a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc
@@ -48,8 +48,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryCurveFill *data = (NodeGeometryCurveFill *)MEM_callocN(sizeof(NodeGeometryCurveFill),
- __func__);
+ NodeGeometryCurveFill *data = MEM_cnew<NodeGeometryCurveFill>(__func__);
data->mode = GEO_NODE_CURVE_FILL_MODE_TRIANGULATED;
node->storage = data;
@@ -170,7 +169,7 @@ void register_node_type_geo_curve_fill()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_FILL_CURVE, "Fill Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_FILL_CURVE, "Fill Curve", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_storage(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
index a438c1d6086..1a44fce86a6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc
@@ -55,8 +55,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveFillet *data = (NodeGeometryCurveFillet *)MEM_callocN(
- sizeof(NodeGeometryCurveFillet), __func__);
+ NodeGeometryCurveFillet *data = MEM_cnew<NodeGeometryCurveFillet>(__func__);
data->mode = GEO_NODE_CURVE_FILLET_BEZIER;
node->storage = data;
@@ -647,7 +646,7 @@ void register_node_type_geo_curve_fillet()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_FILLET_CURVE, "Fillet Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_FILLET_CURVE, "Fillet Curve", NODE_CLASS_GEOMETRY);
ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
&ntype, "NodeGeometryCurveFillet", node_free_standard_storage, node_copy_standard_storage);
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 381bb0fc1d0..e4e87e519f7 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
@@ -38,8 +38,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN(
- sizeof(NodeGeometryCurveSelectHandles), __func__);
+ 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;
@@ -156,7 +155,7 @@ void register_node_type_geo_curve_handle_type_selection()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, "Handle Type Selection", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, "Handle Type Selection", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
node_type_init(&ntype, file_ns::node_init);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
index 73ad8a8cf65..21ae88a6852 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
@@ -48,7 +48,7 @@ void register_node_type_geo_curve_length()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_LENGTH, "Curve Length", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_LENGTH, "Curve Length", 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/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
index 4299b5cc022..7d84ddf9917 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
@@ -62,8 +62,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveBezierSegment *data = (NodeGeometryCurvePrimitiveBezierSegment *)
- MEM_callocN(sizeof(NodeGeometryCurvePrimitiveBezierSegment), __func__);
+ NodeGeometryCurvePrimitiveBezierSegment *data =
+ MEM_cnew<NodeGeometryCurvePrimitiveBezierSegment>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION;
node->storage = data;
@@ -79,44 +79,29 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve(
{
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>();
+ spline->set_resolution(resolution);
+
+ spline->resize(2);
+ MutableSpan<float3> positions = spline->positions();
+ spline->handle_types_left().fill(BezierSpline::HandleType::Align);
+ spline->handle_types_right().fill(BezierSpline::HandleType::Align);
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+
+ positions.first() = start;
+ positions.last() = end;
if (mode == GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION) {
- spline->add_point(start,
- BezierSpline::HandleType::Align,
- 2.0f * start - start_handle_right,
- BezierSpline::HandleType::Align,
- start_handle_right,
- 1.0f,
- 0.0f);
- spline->add_point(end,
- BezierSpline::HandleType::Align,
- end_handle_left,
- BezierSpline::HandleType::Align,
- 2.0f * end - end_handle_left,
- 1.0f,
- 0.0f);
+ spline->set_handle_position_right(0, start_handle_right);
+ spline->set_handle_position_left(1, end_handle_left);
}
else {
- spline->add_point(start,
- BezierSpline::HandleType::Align,
- start - start_handle_right,
- BezierSpline::HandleType::Align,
- start + start_handle_right,
- 1.0f,
- 0.0f);
- spline->add_point(end,
- BezierSpline::HandleType::Align,
- end + end_handle_left,
- BezierSpline::HandleType::Align,
- end - end_handle_left,
- 1.0f,
- 0.0f);
+ spline->set_handle_position_right(0, start + start_handle_right);
+ spline->set_handle_position_left(1, end + end_handle_left);
}
- spline->set_resolution(resolution);
- spline->attributes.reallocate(spline->size());
curve->add_spline(std::move(spline));
- curve->attributes.reallocate(curve->splines().size());
+ curve->attributes.reallocate(1);
return curve;
}
@@ -144,7 +129,7 @@ void register_node_type_geo_curve_primitive_bezier_segment()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, "Bezier Segment", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, "Bezier Segment", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_storage(&ntype,
"NodeGeometryCurvePrimitiveBezierSegment",
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 70abf4c64a7..a7fb493c7d7 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
@@ -68,8 +68,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveCircle *data = (NodeGeometryCurvePrimitiveCircle *)MEM_callocN(
- sizeof(NodeGeometryCurvePrimitiveCircle), __func__);
+ NodeGeometryCurvePrimitiveCircle *data = MEM_cnew<NodeGeometryCurvePrimitiveCircle>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS;
node->storage = data;
@@ -232,8 +231,7 @@ void register_node_type_geo_curve_primitive_circle()
namespace file_ns = blender::nodes::node_geo_curve_primitive_circle_cc;
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
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 6d71c97b15a..ff9218b1ac2 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
@@ -52,8 +52,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveLine *data = (NodeGeometryCurvePrimitiveLine *)MEM_callocN(
- sizeof(NodeGeometryCurvePrimitiveLine), __func__);
+ NodeGeometryCurvePrimitiveLine *data = MEM_cnew<NodeGeometryCurvePrimitiveLine>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS;
node->storage = data;
@@ -136,7 +135,7 @@ void register_node_type_geo_curve_primitive_line()
namespace file_ns = blender::nodes::node_geo_curve_primitive_line_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_LINE, "Curve Line", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_LINE, "Curve Line", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
index 92a9b1b4966..084d27e9d24 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
@@ -50,15 +50,19 @@ static std::unique_ptr<CurveEval> create_quadratic_bezier_curve(const float3 p1,
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ spline->resize(resolution + 1);
+ MutableSpan<float3> positions = spline->positions();
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+
const float step = 1.0f / resolution;
- for (int i : IndexRange(resolution + 1)) {
+ for (const int i : IndexRange(resolution + 1)) {
const float factor = step * i;
const float3 q1 = float3::interpolate(p1, p2, factor);
const float3 q2 = float3::interpolate(p2, p3, factor);
- const float3 out = float3::interpolate(q1, q2, factor);
- spline->add_point(out, 1.0f, 0.0f);
+ positions[i] = float3::interpolate(q1, q2, factor);
}
- spline->attributes.reallocate(spline->size());
+
curve->add_spline(std::move(spline));
curve->attributes.reallocate(curve->splines().size());
return curve;
@@ -81,11 +85,8 @@ void register_node_type_geo_curve_primitive_quadratic_bezier()
namespace file_ns = blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype,
- GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER,
- "Quadratic Bezier",
- NODE_CLASS_GEOMETRY,
- 0);
+ geo_node_type_base(
+ &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, "Quadratic Bezier", 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/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
index ff6294b9b6b..02e7247fe59 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
@@ -89,8 +89,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurvePrimitiveQuad *data = (NodeGeometryCurvePrimitiveQuad *)MEM_callocN(
- sizeof(NodeGeometryCurvePrimitiveQuad), __func__);
+ NodeGeometryCurvePrimitiveQuad *data = MEM_cnew<NodeGeometryCurvePrimitiveQuad>(__func__);
data->mode = GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE;
node->storage = data;
}
@@ -113,35 +112,26 @@ static void node_update(bNodeTree *ntree, bNode *node)
bNodeSocket *p3 = p2->next;
bNodeSocket *p4 = p3->next;
- LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- nodeSetSocketAvailability(ntree, sock, false);
- }
+ Vector<bNodeSocket *> available_sockets;
if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE) {
- nodeSetSocketAvailability(ntree, width, true);
- nodeSetSocketAvailability(ntree, height, true);
+ available_sockets.extend({width, height});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM) {
- nodeSetSocketAvailability(ntree, width, true);
- nodeSetSocketAvailability(ntree, height, true);
- nodeSetSocketAvailability(ntree, offset, true);
+ available_sockets.extend({width, height, offset});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID) {
- nodeSetSocketAvailability(ntree, bottom, true);
- nodeSetSocketAvailability(ntree, top, true);
- nodeSetSocketAvailability(ntree, offset, true);
- nodeSetSocketAvailability(ntree, height, true);
+ available_sockets.extend({bottom, top, offset, height});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE) {
- nodeSetSocketAvailability(ntree, width, true);
- nodeSetSocketAvailability(ntree, bottom_height, true);
- nodeSetSocketAvailability(ntree, top_height, true);
+ available_sockets.extend({width, bottom_height, top_height});
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS) {
- nodeSetSocketAvailability(ntree, p1, true);
- nodeSetSocketAvailability(ntree, p2, true);
- nodeSetSocketAvailability(ntree, p3, true);
- nodeSetSocketAvailability(ntree, p4, true);
+ available_sockets.extend({p1, p2, p3, p4});
+ }
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ nodeSetSocketAvailability(ntree, sock, available_sockets.contains(sock));
}
}
@@ -299,7 +289,7 @@ void register_node_type_geo_curve_primitive_quadrilateral()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", 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;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
index d5ae3551904..6aba65b5638 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc
@@ -65,6 +65,11 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations,
const float delta_theta = (M_PI * 2 * rotations) / (float)totalpoints *
(direction ? 1.0f : -1.0f);
+ spline->resize(totalpoints + 1);
+ MutableSpan<float3> positions = spline->positions();
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+
for (const int i : IndexRange(totalpoints + 1)) {
const float theta = i * delta_theta;
const float radius = start_radius + i * delta_radius;
@@ -72,10 +77,9 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations,
const float y = radius * sin(theta);
const float z = delta_height * i;
- spline->add_point(float3(x, y, z), 1.0f, 0.0f);
+ positions[i] = {x, y, z};
}
- spline->attributes.reallocate(spline->size());
curve->add_spline(std::move(spline));
curve->attributes.reallocate(curve->splines().size());
return curve;
@@ -107,7 +111,7 @@ void register_node_type_geo_curve_primitive_spiral()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, "Spiral", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, "Spiral", 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/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
index 731be0f0f49..14517a79037 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
@@ -54,19 +54,24 @@ static std::unique_ptr<CurveEval> create_star_curve(const float inner_radius,
{
std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ spline->set_cyclic(true);
+
+ spline->resize(points * 2);
+ MutableSpan<float3> positions = spline->positions();
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
const float theta_step = (2.0f * M_PI) / float(points);
- for (int i : IndexRange(points)) {
+ for (const int i : IndexRange(points)) {
const float x = outer_radius * cos(theta_step * i);
const float y = outer_radius * sin(theta_step * i);
- spline->add_point(float3(x, y, 0.0f), 1.0f, 0.0f);
+ positions[i * 2] = {x, y, 0.0f};
const float inner_x = inner_radius * cos(theta_step * i + theta_step * 0.5f + twist);
const float inner_y = inner_radius * sin(theta_step * i + theta_step * 0.5f + twist);
- spline->add_point(float3(inner_x, inner_y, 0.0f), 1.0f, 0.0f);
+ positions[i * 2 + 1] = {inner_x, inner_y, 0.0f};
}
- spline->set_cyclic(true);
- spline->attributes.reallocate(spline->size());
+
curve->add_spline(std::move(spline));
curve->attributes.reallocate(curve->splines().size());
@@ -110,7 +115,7 @@ void register_node_type_geo_curve_primitive_star()
namespace file_ns = blender::nodes::node_geo_curve_primitive_star_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_STAR, "Star", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_STAR, "Star", 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/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index 7e465714265..8494b4868e8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveResample *data = (NodeGeometryCurveResample *)MEM_callocN(
- sizeof(NodeGeometryCurveResample), __func__);
+ NodeGeometryCurveResample *data = MEM_cnew<NodeGeometryCurveResample>(__func__);
data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT;
node->storage = data;
@@ -82,8 +81,11 @@ static SplinePtr resample_spline(const Spline &src, const int count)
Spline::copy_base_settings(src, *dst);
if (src.evaluated_edges_size() < 1 || count == 1) {
- dst->add_point(src.positions().first(), src.radii().first(), src.tilts().first());
- dst->attributes.reallocate(1);
+ dst->resize(1);
+ dst->positions().first() = src.positions().first();
+ dst->radii().first() = src.radii().first();
+ dst->tilts().first() = src.tilts().first();
+
src.attributes.foreach_attribute(
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
std::optional<GSpan> src_attribute = src.attributes.get_for_read(attribute_id);
@@ -295,7 +297,7 @@ void register_node_type_geo_curve_resample()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_RESAMPLE_CURVE, "Resample Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_RESAMPLE_CURVE, "Resample Curve", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.draw_buttons = file_ns::node_layout;
node_type_storage(
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 d07e89ec7f2..38974fafce7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc
@@ -67,7 +67,7 @@ void register_node_type_geo_curve_reverse()
namespace file_ns = blender::nodes::node_geo_curve_reverse_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_REVERSE_CURVE, "Reverse Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_REVERSE_CURVE, "Reverse 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/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
index eff760266f5..038f7625825 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc
@@ -55,8 +55,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_type_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSample *data = (NodeGeometryCurveSample *)MEM_callocN(
- sizeof(NodeGeometryCurveSample), __func__);
+ NodeGeometryCurveSample *data = MEM_cnew<NodeGeometryCurveSample>(__func__);
data->mode = GEO_NODE_CURVE_SAMPLE_LENGTH;
node->storage = data;
}
@@ -287,7 +286,7 @@ void register_node_type_geo_curve_sample()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SAMPLE_CURVE, " Sample Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SAMPLE_CURVE, "Sample Curve", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
node_type_init(&ntype, file_ns::node_type_init);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
index 8c0827570c6..b4ca51d0fa7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc
@@ -40,8 +40,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN(
- sizeof(NodeGeometryCurveSetHandles), __func__);
+ NodeGeometryCurveSetHandles *data = MEM_cnew<NodeGeometryCurveSetHandles>(__func__);
data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO;
data->mode = GEO_NODE_CURVE_HANDLE_LEFT;
@@ -136,8 +135,7 @@ void register_node_type_geo_curve_set_handles()
namespace file_ns = blender::nodes::node_geo_curve_set_handles_cc;
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_SET_HANDLES, "Set 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);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
index de352d217ed..40dde645756 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc
@@ -319,7 +319,7 @@ void register_node_type_geo_curve_spline_parameter()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_CURVE_SPLINE_PARAMETER, "Spline Parameter", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_CURVE_SPLINE_PARAMETER, "Spline Parameter", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
index eef8c1b0db5..5745eb86949 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc
@@ -41,8 +41,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN(
- sizeof(NodeGeometryCurveSplineType), __func__);
+ NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__);
data->spline_type = GEO_NODE_SPLINE_TYPE_POLY;
node->storage = data;
@@ -298,8 +297,7 @@ void register_node_type_geo_curve_spline_type()
namespace file_ns = blender::nodes::node_geo_curve_spline_type_cc;
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_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);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
index 6de188fc1c4..ae282017e0c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -359,7 +359,7 @@ void register_node_type_geo_curve_subdivide()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_CURVE, "Subdivide Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_CURVE, "Subdivide 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/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
index ff3e85cb6b7..ef4fc51d1b3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
@@ -80,7 +80,7 @@ void register_node_type_geo_curve_to_mesh()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_MESH, "Curve to Mesh", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_MESH, "Curve to Mesh", 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/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
index 0e9425246cb..a8553b636a4 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
@@ -72,8 +72,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN(
- sizeof(NodeGeometryCurveToPoints), __func__);
+ NodeGeometryCurveToPoints *data = MEM_cnew<NodeGeometryCurveToPoints>(__func__);
data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT;
node->storage = data;
@@ -403,7 +402,7 @@ void register_node_type_geo_curve_to_points()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_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;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
index 746392a66cc..359863d39e0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc
@@ -67,8 +67,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryCurveTrim *data = (NodeGeometryCurveTrim *)MEM_callocN(sizeof(NodeGeometryCurveTrim),
- __func__);
+ NodeGeometryCurveTrim *data = MEM_cnew<NodeGeometryCurveTrim>(__func__);
data->mode = GEO_NODE_CURVE_SAMPLE_FACTOR;
node->storage = data;
@@ -608,7 +607,7 @@ void register_node_type_geo_curve_trim()
namespace file_ns = blender::nodes::node_geo_curve_trim_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_TRIM_CURVE, "Trim Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_TRIM_CURVE, "Trim Curve", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.draw_buttons = file_ns::node_layout;
ntype.declare = file_ns::node_declare;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
index 1de809b30e4..5ea8034c437 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -529,6 +529,30 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set,
geometry_set.replace_pointcloud(pointcloud);
}
+static void separate_instance_selection(GeometrySet &geometry_set,
+ const Field<bool> &selection_field,
+ const bool invert)
+{
+ InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>();
+ GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE};
+
+ const int domain_size = instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE);
+ fn::FieldEvaluator evaluator{field_context, domain_size};
+ evaluator.add(selection_field);
+ evaluator.evaluate();
+ const VArray_Span<bool> &selection = evaluator.get_evaluated<bool>(0);
+
+ Vector<int64_t> indices;
+ const IndexMask mask = index_mask_indices(selection, invert, indices);
+
+ if (mask.is_empty()) {
+ geometry_set.remove<InstancesComponent>();
+ return;
+ }
+
+ instances.remove_instances(mask);
+}
+
static void compute_selected_vertices_from_vertex_selection(const Span<bool> vertex_selection,
const bool invert,
MutableSpan<int> r_vertex_map,
@@ -979,8 +1003,8 @@ static void do_mesh_separation(GeometrySet &geometry_set,
/* Needed in all cases. */
Vector<int> selected_poly_indices;
Vector<int> new_loop_starts;
- int num_selected_polys;
- int num_selected_loops;
+ int num_selected_polys = 0;
+ int num_selected_loops = 0;
const Mesh &mesh_in = *in_component.get_for_read();
Mesh *mesh_out;
@@ -1261,7 +1285,7 @@ void separate_geometry(GeometrySet &geometry_set,
}
}
if (geometry_set.has_mesh()) {
- if (domain != ATTR_DOMAIN_CURVE) {
+ if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER)) {
separate_mesh_selection(geometry_set, selection_field, domain, mode, invert);
some_valid_domain = true;
}
@@ -1272,6 +1296,12 @@ void separate_geometry(GeometrySet &geometry_set,
some_valid_domain = true;
}
}
+ if (geometry_set.has_instances()) {
+ if (domain == ATTR_DOMAIN_INSTANCE) {
+ separate_instance_selection(geometry_set, selection_field, invert);
+ some_valid_domain = true;
+ }
+ }
r_is_error = !some_valid_domain && geometry_set.has_realized_data();
}
@@ -1307,8 +1337,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN(
- sizeof(NodeGeometryDeleteGeometry), __func__);
+ NodeGeometryDeleteGeometry *data = MEM_cnew<NodeGeometryDeleteGeometry>(__func__);
data->domain = ATTR_DOMAIN_POINT;
data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL;
@@ -1348,7 +1377,7 @@ void register_node_type_geo_delete_geometry()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY);
node_type_storage(&ntype,
"NodeGeometryDeleteGeometry",
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 3537b62c76e..a257af4391c 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
@@ -573,8 +573,7 @@ void register_node_type_geo_distribute_points_on_faces()
geo_node_type_base(&ntype,
GEO_NODE_DISTRIBUTE_POINTS_ON_FACES,
"Distribute Points on Faces",
- NODE_CLASS_GEOMETRY,
- 0);
+ NODE_CLASS_GEOMETRY);
node_type_update(&ntype, file_ns::node_point_distribute_points_on_faces_update);
node_type_size(&ntype, 170, 100, 320);
ntype.declare = file_ns::node_declare;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
index a3bbeca7af3..ed4def0cf68 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc
@@ -537,6 +537,77 @@ static void add_edge(const Mesh &mesh,
loop_edges.append(new_edge_i);
}
+/* Returns true if the vertex is connected only to the two polygons and is not on the boundary. */
+static bool vertex_needs_dissolving(const int vertex,
+ const int first_poly_index,
+ const int second_poly_index,
+ const Span<VertexType> vertex_types,
+ const Span<Vector<int>> vertex_poly_indices)
+{
+ /* Order is guaranteed to be the same because 2poly verts that are not on the boundary are
+ * ignored in `sort_vertex_polys`. */
+ return (vertex_types[vertex] != VertexType::Boundary &&
+ vertex_poly_indices[vertex].size() == 2 &&
+ vertex_poly_indices[vertex][0] == first_poly_index &&
+ vertex_poly_indices[vertex][1] == second_poly_index);
+}
+
+/**
+ * Finds 'normal' vertices which are connected to only two polygons and marks them to not be
+ * used in the datastructures derived from the mesh. For each pair of polygons which has such a
+ * vertex, an edge is created for the dual mesh between the centers of those two polygons. All
+ * edges in the input mesh which contain such a vertex are marked as 'done' to prevent duplicate
+ * edges being created. (See T94144)
+ */
+static void dissolve_redundant_verts(const Mesh &mesh,
+ const Span<Vector<int>> vertex_poly_indices,
+ MutableSpan<VertexType> vertex_types,
+ MutableSpan<int> old_to_new_edges_map,
+ Vector<MEdge> &new_edges,
+ Vector<int> &new_to_old_edges_map)
+{
+ for (const int vert_i : IndexRange(mesh.totvert)) {
+ if (vertex_poly_indices[vert_i].size() != 2 || vertex_types[vert_i] != VertexType::Normal) {
+ continue;
+ }
+ const int first_poly_index = vertex_poly_indices[vert_i][0];
+ const int second_poly_index = vertex_poly_indices[vert_i][1];
+ const int new_edge_index = new_edges.size();
+ bool edge_created = false;
+ const MPoly &poly = mesh.mpoly[first_poly_index];
+ for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) {
+ const MEdge &edge = mesh.medge[loop.e];
+ const int v1 = edge.v1;
+ const int v2 = edge.v2;
+ bool mark_edge = false;
+ if (vertex_needs_dissolving(
+ v1, first_poly_index, second_poly_index, vertex_types, vertex_poly_indices)) {
+ /* This vertex is now 'removed' and should be ignored elsewhere. */
+ vertex_types[v1] = VertexType::Loose;
+ mark_edge = true;
+ }
+ if (vertex_needs_dissolving(
+ v2, first_poly_index, second_poly_index, vertex_types, vertex_poly_indices)) {
+ /* This vertex is now 'removed' and should be ignored elsewhere. */
+ vertex_types[v2] = VertexType::Loose;
+ mark_edge = true;
+ }
+ if (mark_edge) {
+ if (!edge_created) {
+ MEdge new_edge = MEdge(edge);
+ /* The vertex indices in the dual mesh are the polygon indices of the input mesh. */
+ new_edge.v1 = first_poly_index;
+ new_edge.v2 = second_poly_index;
+ new_to_old_edges_map.append(loop.e);
+ new_edges.append(new_edge);
+ edge_created = true;
+ }
+ old_to_new_edges_map[loop.e] = new_edge_index;
+ }
+ }
+ }
+}
+
/**
* Calculate the barycentric dual of a mesh. The dual is only "dual" in terms of connectivity,
* i.e. applying the function twice will give the same vertices, edges, and faces, but not the
@@ -564,6 +635,9 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
Array<VertexType> vertex_types(mesh_in.totvert);
Array<EdgeType> edge_types(mesh_in.totedge);
calc_boundaries(mesh_in, vertex_types, edge_types);
+ /* Stores the indices of the polygons connected to the vertex. Because the polygons are looped
+ * over in order of their indices, the polygon's indices will be sorted in ascending order.
+ (This can change once they are sorted using `sort_vertex_polys`). */
Array<Vector<int>> vertex_poly_indices(mesh_in.totvert);
Array<Array<int>> vertex_shared_edges(mesh_in.totvert);
Array<Array<int>> vertex_corners(mesh_in.totvert);
@@ -632,6 +706,16 @@ static void calc_dual_mesh(GeometrySet &geometry_set,
* don't need a hashmap for that. */
Array<int> old_to_new_edges_map(mesh_in.totedge);
old_to_new_edges_map.fill(-1);
+
+ /* This is necessary to prevent duplicate edges from being created, but will likely not do
+ * anything for most meshes. */
+ dissolve_redundant_verts(mesh_in,
+ vertex_poly_indices,
+ vertex_types,
+ old_to_new_edges_map,
+ new_edges,
+ new_to_old_edges_map);
+
for (const int i : IndexRange(mesh_in.totvert)) {
if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold ||
(!keep_boundaries && vertex_types[i] == VertexType::Boundary)) {
@@ -840,7 +924,7 @@ void register_node_type_geo_dual_mesh()
namespace file_ns = blender::nodes::node_geo_dual_mesh_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_DUAL_MESH, "Dual Mesh", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_DUAL_MESH, "Dual Mesh", 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/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
index d23a18ba37b..9376789cf2c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -90,7 +90,7 @@ void register_node_type_geo_edge_split()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SPLIT_EDGES, "Split Edges", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SPLIT_EDGES, "Split Edges", 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/node_geo_geometry_to_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
index 7faf104737f..f65af5b6737 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc
@@ -47,7 +47,7 @@ void register_node_type_geo_geometry_to_instance()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_GEOMETRY_TO_INSTANCE, "Geometry to Instance", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_GEOMETRY_TO_INSTANCE, "Geometry to Instance", NODE_CLASS_GEOMETRY);
node_type_size(&ntype, 160, 100, 300);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
index 0003f15854d..28a8fb80294 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc
@@ -55,8 +55,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryImageTexture *tex = (NodeGeometryImageTexture *)MEM_callocN(
- sizeof(NodeGeometryImageTexture), __func__);
+ NodeGeometryImageTexture *tex = MEM_cnew<NodeGeometryImageTexture>(__func__);
node->storage = tex;
}
@@ -416,7 +415,7 @@ void register_node_type_geo_image_texture()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_IMAGE_TEXTURE, "Image Texture", NODE_CLASS_TEXTURE, 0);
+ geo_node_type_base(&ntype, GEO_NODE_IMAGE_TEXTURE, "Image Texture", NODE_CLASS_TEXTURE);
ntype.declare = file_ns::node_declare;
ntype.draw_buttons = file_ns::node_layout;
node_type_init(&ntype, file_ns::node_init);
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 dae8fda2099..c3c26736e88 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
@@ -40,7 +40,7 @@ void register_node_type_geo_input_curve_handles()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INPUT_CURVE_HANDLES, "Curve Handle Positions", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_INPUT_CURVE_HANDLES, "Curve Handle Positions", NODE_CLASS_INPUT);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
index 5ba85b6f34e..61b4b6bb9e9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc
@@ -37,7 +37,7 @@ void register_node_type_geo_input_curve_tilt()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_CURVE_TILT, "Curve Tilt", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_CURVE_TILT, "Curve Tilt", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
index d2e103a093a..3fe0588a46d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc
@@ -37,7 +37,7 @@ void register_node_type_geo_input_id()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_ID, "ID", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_ID, "ID", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
index 74cddfc6a4a..98c2c9d58f0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc
@@ -37,7 +37,7 @@ void register_node_type_geo_input_index()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_INDEX, "Index", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_INDEX, "Index", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
index 1b6e3c8fc68..a1c905fccaa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc
@@ -45,7 +45,7 @@ void register_node_type_geo_input_material()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL, "Material", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL, "Material", NODE_CLASS_INPUT);
ntype.draw_buttons = file_ns::node_layout;
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
index 4df218eb669..fca29feb73c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc
@@ -37,7 +37,7 @@ void register_node_type_geo_input_material_index()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL_INDEX, "Material Index", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL_INDEX, "Material Index", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
new file mode 100644
index 00000000000..2d16c60ba86
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc
@@ -0,0 +1,128 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_mesh.h"
+
+#include "node_geometry_util.hh"
+
+namespace blender::nodes::node_geo_input_mesh_edge_angle_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Float>(N_("Angle"))
+ .field_source()
+ .description(
+ "The angle in radians between two faces where they meet at an edge. Flat edges and "
+ "Non-manifold edges have an angle of zero");
+}
+
+struct EdgeMapEntry {
+ int face_count;
+ int face_index_1;
+ int face_index_2;
+};
+
+class AngleFieldInput final : public GeometryFieldInput {
+ public:
+ AngleFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Angle Field")
+ {
+ category_ = Category::Generated;
+ }
+
+ GVArray get_varray_for_context(const GeometryComponent &component,
+ const AttributeDomain domain,
+ IndexMask UNUSED(mask)) const final
+ {
+ if (component.type() != GEO_COMPONENT_TYPE_MESH) {
+ return {};
+ }
+
+ const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
+ const Mesh *mesh = mesh_component.get_for_read();
+ if (mesh == nullptr) {
+ return {};
+ }
+
+ Span<MPoly> polys{mesh->mpoly, mesh->totpoly};
+ Span<MLoop> loops{mesh->mloop, mesh->totloop};
+ Array<EdgeMapEntry> edge_map(mesh->totedge, {0, 0, 0});
+
+ for (const int i_poly : polys.index_range()) {
+ const MPoly &mpoly = polys[i_poly];
+ for (const MLoop &loop : loops.slice(mpoly.loopstart, mpoly.totloop)) {
+ EdgeMapEntry &entry = edge_map[loop.e];
+ if (entry.face_count == 0) {
+ entry.face_index_1 = i_poly;
+ }
+ else if (entry.face_count == 1) {
+ entry.face_index_2 = i_poly;
+ }
+ entry.face_count++;
+ }
+ }
+
+ auto angle_fn = [edge_map, polys, loops, mesh](const int i) -> float {
+ if (edge_map[i].face_count == 2) {
+ const MPoly &mpoly_1 = polys[edge_map[i].face_index_1];
+ const MPoly &mpoly_2 = polys[edge_map[i].face_index_2];
+ float3 normal_1, normal_2;
+ BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], mesh->mvert, normal_1);
+ BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, normal_2);
+ return angle_normalized_v3v3(normal_1, normal_2);
+ }
+ else {
+ return 0.0f;
+ }
+ };
+
+ VArray<float> angles = VArray<float>::ForFunc(mesh->totedge, angle_fn);
+ return component.attribute_try_adapt_domain<float>(
+ std::move(angles), ATTR_DOMAIN_EDGE, domain);
+ }
+
+ uint64_t hash() const override
+ {
+ /* Some random constant hash. */
+ return 32426725235;
+ }
+
+ bool is_equal_to(const fn::FieldNode &other) const override
+ {
+ return dynamic_cast<const AngleFieldInput *>(&other) != nullptr;
+ }
+};
+
+static void node_geo_exec(GeoNodeExecParams params)
+{
+ Field<float> angle_field{std::make_shared<AngleFieldInput>()};
+ params.set_output("Angle", std::move(angle_field));
+}
+
+} // namespace blender::nodes::node_geo_input_mesh_edge_angle_cc
+
+void register_node_type_geo_input_mesh_edge_angle()
+{
+ namespace file_ns = blender::nodes::node_geo_input_mesh_edge_angle_cc;
+
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_EDGE_ANGLE, "Edge Angle", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ ntype.geometry_node_execute = file_ns::node_geo_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
index ede87252312..ddeb3ded511 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc
@@ -86,7 +86,7 @@ void register_node_type_geo_input_mesh_edge_neighbors()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, "Edge Neighbors", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, "Edge Neighbors", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
index 473bef63e92..f54c92fea7b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc
@@ -50,12 +50,11 @@ static VArray<int> construct_edge_vertices_gvarray(const MeshComponent &componen
return {};
}
if (domain == ATTR_DOMAIN_EDGE) {
-
if (vertex == VERTEX_ONE) {
- return VArray<int>::ForFunc(mesh->totpoly,
+ return VArray<int>::ForFunc(mesh->totedge,
[mesh](const int i) -> int { return mesh->medge[i].v1; });
}
- return VArray<int>::ForFunc(mesh->totpoly,
+ return VArray<int>::ForFunc(mesh->totedge,
[mesh](const int i) -> int { return mesh->medge[i].v2; });
}
return {};
@@ -180,8 +179,7 @@ void register_node_type_geo_input_mesh_edge_vertices()
namespace file_ns = blender::nodes::node_geo_input_mesh_edge_vertices_cc;
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_INPUT_MESH_EDGE_VERTICES, "Edge Vertices", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_EDGE_VERTICES, "Edge Vertices", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
index 538b9e9682d..ef8adff48f1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc
@@ -89,7 +89,7 @@ void register_node_type_geo_input_mesh_face_area()
namespace file_ns = blender::nodes::node_geo_input_mesh_face_area_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_FACE_AREA, "Face Area", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_FACE_AREA, "Face Area", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
index 80bb25dc7ca..8d196e5f8dd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc
@@ -150,7 +150,7 @@ void register_node_type_geo_input_mesh_face_neighbors()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, "Face Neighbors", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, "Face Neighbors", NODE_CLASS_INPUT);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
index 3c713ef6ca9..629279a44e9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc
@@ -94,7 +94,7 @@ void register_node_type_geo_input_mesh_island()
namespace file_ns = blender::nodes::node_geo_input_mesh_island_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_ISLAND, "Mesh Island", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_ISLAND, "Mesh Island", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
index 05140c92205..7d79164634d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc
@@ -148,7 +148,7 @@ void register_node_type_geo_input_mesh_vertex_neighbors()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, "Vertex Neighbors", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, "Vertex Neighbors", NODE_CLASS_INPUT);
ntype.declare = file_ns::node_declare;
ntype.geometry_node_execute = file_ns::node_geo_exec;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
index 1cc508d9d9d..86c2b0e4543 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc
@@ -282,7 +282,7 @@ void register_node_type_geo_input_normal()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_NORMAL, "Normal", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_NORMAL, "Normal", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
index 8322831a871..beb528d2fd8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc
@@ -37,7 +37,7 @@ void register_node_type_geo_input_position()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_POSITION, "Position", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_POSITION, "Position", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
index 26fb74f5a5b..c7777da08c6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc
@@ -37,7 +37,7 @@ void register_node_type_geo_input_radius()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_RADIUS, "Radius", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_RADIUS, "Radius", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
index cfc1a81f7b9..4ed65e99a1c 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc
@@ -43,7 +43,7 @@ void register_node_type_geo_input_scene_time()
{
static bNodeType ntype;
namespace file_ns = blender::nodes::node_geo_input_scene_time_cc;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_SCENE_TIME, "Scene Time", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_SCENE_TIME, "Scene Time", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
index 3efe8577e51..b27ab097223 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc
@@ -37,7 +37,7 @@ void register_node_type_geo_input_shade_smooth()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_SHADE_SMOOTH, "Is Shade Smooth", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_SHADE_SMOOTH, "Is Shade Smooth", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
index 5f833445a76..2db00a1ae68 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc
@@ -37,8 +37,7 @@ void register_node_type_geo_input_spline_cyclic()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_INPUT_SPLINE_CYCLIC, "Is Spline Cyclic", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_CYCLIC, "Is Spline Cyclic", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc
index 810d6e2fddd..b8c8ce840eb 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
@@ -156,7 +156,7 @@ void register_node_type_geo_input_spline_length()
namespace file_ns = blender::nodes::node_geo_input_spline_length_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_LENGTH, "Spline Length", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_LENGTH, "Spline Length", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
index 77b6e27e6a2..d79f2ffd64d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc
@@ -38,7 +38,7 @@ void register_node_type_geo_input_spline_resolution()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INPUT_SPLINE_RESOLUTION, "Spline Resolution", NODE_CLASS_INPUT, 0);
+ &ntype, GEO_NODE_INPUT_SPLINE_RESOLUTION, "Spline Resolution", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
index 86f882df3cd..f80fdfbf334 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
@@ -161,7 +161,7 @@ void register_node_type_geo_input_tangent()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_INPUT_TANGENT, "Curve Tangent", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_INPUT_TANGENT, "Curve Tangent", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
index 486f90760f5..66ac618be5f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc
@@ -259,7 +259,7 @@ void register_node_type_geo_instance_on_points()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INSTANCE_ON_POINTS, "Instance on Points", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_INSTANCE_ON_POINTS, "Instance on Points", 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/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
index 9942e388ba5..f9beed956bb 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc
@@ -130,7 +130,7 @@ void register_node_type_geo_instances_to_points()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_INSTANCES_TO_POINTS, "Instances to Points", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_INSTANCES_TO_POINTS, "Instances to Points", 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/node_geo_is_viewport.cc b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
index 5925d440317..c97bbad4665 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc
@@ -42,7 +42,7 @@ void register_node_type_geo_is_viewport()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_IS_VIEWPORT, "Is Viewport", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_IS_VIEWPORT, "Is Viewport", NODE_CLASS_INPUT);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index bf7a9f49829..1e521af6b13 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -180,8 +180,7 @@ static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet
InstancesComponent &instances =
instances_geometry_set.get_component_for_write<InstancesComponent>();
- if constexpr (std::is_same_v<Component, InstancesComponent> ||
- std::is_same_v<Component, VolumeComponent>) {
+ if constexpr (is_same_any_v<Component, InstancesComponent, VolumeComponent>) {
join_components(components, result);
}
else {
@@ -221,7 +220,7 @@ void register_node_type_geo_join_geometry()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_JOIN_GEOMETRY, "Join Geometry", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_JOIN_GEOMETRY, "Join Geometry", 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/node_geo_material_replace.cc b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
index 5a334126350..0309121db74 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc
@@ -63,8 +63,7 @@ void register_node_type_geo_material_replace()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_REPLACE_MATERIAL, "Replace Material", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_REPLACE_MATERIAL, "Replace 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/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
index 2aad68e7c25..0b5f0bf34c5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc
@@ -122,7 +122,7 @@ void register_node_type_geo_material_selection()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_MATERIAL_SELECTION, "Material Selection", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_MATERIAL_SELECTION, "Material Selection", 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/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
index 7a1cb8a62a3..b07d809a091 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
@@ -52,8 +52,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshCircle *node_storage = (NodeGeometryMeshCircle *)MEM_callocN(
- sizeof(NodeGeometryMeshCircle), __func__);
+ NodeGeometryMeshCircle *node_storage = MEM_cnew<NodeGeometryMeshCircle>(__func__);
node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NONE;
@@ -214,8 +213,6 @@ static void node_geo_exec(GeoNodeExecParams params)
Mesh *mesh = create_circle_mesh(radius, verts_num, fill);
- BLI_assert(BKE_mesh_is_valid(mesh));
-
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
}
@@ -227,8 +224,7 @@ void register_node_type_geo_mesh_primitive_circle()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_storage(
&ntype, "NodeGeometryMeshCircle", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index 70b093798f8..2aa9522cf56 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -770,8 +770,7 @@ static void node_declare(NodeDeclarationBuilder &b)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN(
- sizeof(NodeGeometryMeshCone), __func__);
+ NodeGeometryMeshCone *node_storage = MEM_cnew<NodeGeometryMeshCone>(__func__);
node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
@@ -879,7 +878,7 @@ void register_node_type_geo_mesh_primitive_cone()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
index 2542542c919..e90a9eb393b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
@@ -527,7 +527,7 @@ void register_node_type_geo_mesh_primitive_cube()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", 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/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
index b8d2ed3be92..73f21cf31fa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
@@ -71,8 +71,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshCylinder *node_storage = (NodeGeometryMeshCylinder *)MEM_callocN(
- sizeof(NodeGeometryMeshCylinder), __func__);
+ NodeGeometryMeshCylinder *node_storage = MEM_cnew<NodeGeometryMeshCylinder>(__func__);
node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON;
@@ -168,7 +167,7 @@ void register_node_type_geo_mesh_primitive_cylinder()
namespace file_ns = blender::nodes::node_geo_mesh_primitive_cylinder_cc;
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
index 77634a03af6..2c4b5df6030 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
@@ -14,6 +14,8 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "BLI_task.hh"
+
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -38,11 +40,13 @@ static void calculate_uvs(
const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x;
const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y;
- for (const int i : loops.index_range()) {
- const float3 &co = verts[loops[i].v].co;
- uvs[i].x = (co.x + size_x * 0.5f) * dx;
- uvs[i].y = (co.y + size_y * 0.5f) * dy;
- }
+ threading::parallel_for(loops.index_range(), 1024, [&](IndexRange range) {
+ for (const int i : range) {
+ const float3 &co = verts[loops[i].v].co;
+ uvs[i].x = (co.x + size_x * 0.5f) * dx;
+ uvs[i].y = (co.y + size_y * 0.5f) * dy;
+ }
+ });
uv_attribute.save();
}
@@ -70,72 +74,95 @@ Mesh *create_grid_mesh(const int verts_x,
const float dy = edges_y == 0 ? 0.0f : size_y / edges_y;
const float x_shift = edges_x / 2.0f;
const float y_shift = edges_y / 2.0f;
- for (const int x_index : IndexRange(verts_x)) {
- for (const int y_index : IndexRange(verts_y)) {
- const int vert_index = x_index * verts_y + y_index;
- verts[vert_index].co[0] = (x_index - x_shift) * dx;
- verts[vert_index].co[1] = (y_index - y_shift) * dy;
- verts[vert_index].co[2] = 0.0f;
+ threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int y_offset = x * verts_y;
+ threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int vert_index = y_offset + y;
+ verts[vert_index].co[0] = (x - x_shift) * dx;
+ verts[vert_index].co[1] = (y - y_shift) * dy;
+ verts[vert_index].co[2] = 0.0f;
+ }
+ });
}
- }
+ });
}
/* Point all vertex normals in the up direction. */
- const short up_normal[3] = {0, 0, SHRT_MAX};
- for (MVert &vert : verts) {
- copy_v3_v3_short(vert.no, up_normal);
+ {
+ const short up_normal[3] = {0, 0, SHRT_MAX};
+ for (MVert &vert : verts) {
+ copy_v3_v3_short(vert.no, up_normal);
+ }
}
- /* Build the horizontal edges in the X direction. */
const int y_edges_start = 0;
+ const int x_edges_start = verts_x * edges_y;
const short edge_flag = (edges_x == 0 || edges_y == 0) ? ME_LOOSEEDGE :
ME_EDGEDRAW | ME_EDGERENDER;
- int edge_index = 0;
- for (const int x : IndexRange(verts_x)) {
- for (const int y : IndexRange(edges_y)) {
- const int vert_index = x * verts_y + y;
- MEdge &edge = edges[edge_index++];
- edge.v1 = vert_index;
- edge.v2 = vert_index + 1;
- edge.flag = edge_flag;
+
+ /* Build the horizontal edges in the X direction. */
+ threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int y_vert_offset = x * verts_y;
+ const int y_edge_offset = y_edges_start + x * edges_y;
+ threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int vert_index = y_vert_offset + y;
+ MEdge &edge = edges[y_edge_offset + y];
+ edge.v1 = vert_index;
+ edge.v2 = vert_index + 1;
+ edge.flag = edge_flag;
+ }
+ });
}
- }
+ });
/* Build the vertical edges in the Y direction. */
- const int x_edges_start = edge_index;
- for (const int y : IndexRange(verts_y)) {
- for (const int x : IndexRange(edges_x)) {
- const int vert_index = x * verts_y + y;
- MEdge &edge = edges[edge_index++];
- edge.v1 = vert_index;
- edge.v2 = vert_index + verts_y;
- edge.flag = edge_flag;
+ threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int x_edge_offset = x_edges_start + y * edges_x;
+ threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int vert_index = x * verts_y + y;
+ MEdge &edge = edges[x_edge_offset + x];
+ edge.v1 = vert_index;
+ edge.v2 = vert_index + verts_y;
+ edge.flag = edge_flag;
+ }
+ });
}
- }
-
- int loop_index = 0;
- int poly_index = 0;
- for (const int x : IndexRange(edges_x)) {
- for (const int y : IndexRange(edges_y)) {
- MPoly &poly = polys[poly_index++];
- poly.loopstart = loop_index;
- poly.totloop = 4;
- const int vert_index = x * verts_y + y;
-
- MLoop &loop_a = loops[loop_index++];
- loop_a.v = vert_index;
- loop_a.e = x_edges_start + edges_x * y + x;
- MLoop &loop_b = loops[loop_index++];
- loop_b.v = vert_index + verts_y;
- loop_b.e = y_edges_start + edges_y * (x + 1) + y;
- MLoop &loop_c = loops[loop_index++];
- loop_c.v = vert_index + verts_y + 1;
- loop_c.e = x_edges_start + edges_x * (y + 1) + x;
- MLoop &loop_d = loops[loop_index++];
- loop_d.v = vert_index + 1;
- loop_d.e = y_edges_start + edges_y * x + y;
+ });
+
+ threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) {
+ for (const int x : x_range) {
+ const int y_offset = x * edges_y;
+ threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) {
+ for (const int y : y_range) {
+ const int poly_index = y_offset + y;
+ const int loop_index = poly_index * 4;
+ MPoly &poly = polys[poly_index];
+ poly.loopstart = loop_index;
+ poly.totloop = 4;
+ const int vert_index = x * verts_y + y;
+
+ MLoop &loop_a = loops[loop_index];
+ loop_a.v = vert_index;
+ loop_a.e = x_edges_start + edges_x * y + x;
+ MLoop &loop_b = loops[loop_index + 1];
+ loop_b.v = vert_index + verts_y;
+ loop_b.e = y_edges_start + edges_y * (x + 1) + y;
+ MLoop &loop_c = loops[loop_index + 2];
+ loop_c.v = vert_index + verts_y + 1;
+ loop_c.e = x_edges_start + edges_x * (y + 1) + x;
+ MLoop &loop_d = loops[loop_index + 3];
+ loop_d.v = vert_index + 1;
+ loop_d.e = y_edges_start + edges_y * x + y;
+ }
+ });
}
- }
+ });
if (mesh->totpoly != 0) {
calculate_uvs(mesh, verts, loops, size_x, size_y);
@@ -185,7 +212,6 @@ static void node_geo_exec(GeoNodeExecParams params)
}
Mesh *mesh = create_grid_mesh(verts_x, verts_y, size_x, size_y);
- BLI_assert(BKE_mesh_is_valid(mesh));
BKE_id_material_eval_ensure_default_slot(&mesh->id);
params.set_output("Mesh", GeometrySet::create_with_mesh(mesh));
@@ -199,7 +225,7 @@ void register_node_type_geo_mesh_primitive_grid()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", 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/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
index 5f483a95063..28a505c5bb8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
@@ -87,7 +87,7 @@ void register_node_type_geo_mesh_primitive_ico_sphere()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", 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/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
index 9a87c040bdf..5116e78fdda 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
@@ -67,8 +67,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryMeshLine *node_storage = (NodeGeometryMeshLine *)MEM_callocN(
- sizeof(NodeGeometryMeshLine), __func__);
+ NodeGeometryMeshLine *node_storage = MEM_cnew<NodeGeometryMeshLine>(__func__);
node_storage->mode = GEO_NODE_MESH_LINE_MODE_OFFSET;
node_storage->count_mode = GEO_NODE_MESH_LINE_COUNT_TOTAL;
@@ -225,7 +224,7 @@ void register_node_type_geo_mesh_primitive_line()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", 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);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
index ce2e0923a30..373e6bfdd18 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
@@ -287,8 +287,6 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const
calculate_sphere_uvs(mesh, segments, rings);
- BLI_assert(BKE_mesh_is_valid(mesh));
-
return mesh;
}
@@ -321,8 +319,7 @@ void register_node_type_geo_mesh_primitive_uv_sphere()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", 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/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
index 1ec9808044f..6d8a2fac8ad 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
@@ -105,7 +105,7 @@ void register_node_type_geo_mesh_subdivide()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_MESH, "Subdivide Mesh", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_MESH, "Subdivide Mesh", 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/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
index 90f0af75788..0f0fb3c230a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -64,7 +64,7 @@ void register_node_type_geo_mesh_to_curve()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_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/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
index 77314341fec..d0546cd2583 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc
@@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryMeshToPoints *data = (NodeGeometryMeshToPoints *)MEM_callocN(
- sizeof(NodeGeometryMeshToPoints), __func__);
+ NodeGeometryMeshToPoints *data = MEM_cnew<NodeGeometryMeshToPoints>(__func__);
data->mode = GEO_NODE_MESH_TO_POINTS_VERTICES;
node->storage = data;
}
@@ -179,7 +178,7 @@ void register_node_type_geo_mesh_to_points()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_TO_POINTS, "Mesh to Points", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_TO_POINTS, "Mesh to Points", 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);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
index 38c3b9cbcd9..d32875d2627 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc
@@ -102,8 +102,7 @@ static void node_geo_exec(GeoNodeExecParams params)
static void node_node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryObjectInfo *data = (NodeGeometryObjectInfo *)MEM_callocN(
- sizeof(NodeGeometryObjectInfo), __func__);
+ NodeGeometryObjectInfo *data = MEM_cnew<NodeGeometryObjectInfo>(__func__);
data->transform_space = GEO_NODE_TRANSFORM_SPACE_ORIGINAL;
node->storage = data;
}
@@ -116,7 +115,7 @@ void register_node_type_geo_object_info()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT);
node_type_init(&ntype, file_ns::node_node_init);
node_type_storage(
&ntype, "NodeGeometryObjectInfo", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
index 5510773eabd..f3da591f684 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc
@@ -113,7 +113,7 @@ void register_node_type_geo_points_to_vertices()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_POINTS_TO_VERTICES, "Points to Vertices", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_POINTS_TO_VERTICES, "Points to Vertices", 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/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
index 744cce6d445..dda4543d5e1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
@@ -66,8 +66,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN(
- sizeof(NodeGeometryPointsToVolume), __func__);
+ NodeGeometryPointsToVolume *data = MEM_cnew<NodeGeometryPointsToVolume>(__func__);
data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT;
node->storage = data;
}
@@ -270,8 +269,7 @@ void register_node_type_geo_points_to_volume()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY);
node_type_storage(&ntype,
"NodeGeometryPointsToVolume",
node_free_standard_storage,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
index aa3383e68be..e0117c4726d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc
@@ -48,8 +48,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void geo_proximity_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryProximity *node_storage = (NodeGeometryProximity *)MEM_callocN(
- sizeof(NodeGeometryProximity), __func__);
+ NodeGeometryProximity *node_storage = MEM_cnew<NodeGeometryProximity>(__func__);
node_storage->target_element = GEO_NODE_PROX_TARGET_FACES;
node->storage = node_storage;
}
@@ -178,7 +177,7 @@ class ProximityFunction : public fn::MultiFunction {
* comparison per vertex, so it's likely not worth it. */
MutableSpan<float> distances = params.uninitialized_single_output<float>(2, "Distance");
- distances.fill(FLT_MAX);
+ distances.fill_indices(mask, FLT_MAX);
bool success = false;
if (target_.has_mesh()) {
@@ -192,8 +191,8 @@ class ProximityFunction : public fn::MultiFunction {
}
if (!success) {
- positions.fill(float3(0));
- distances.fill(0.0f);
+ positions.fill_indices(mask, float3(0));
+ distances.fill_indices(mask, 0.0f);
return;
}
@@ -239,7 +238,7 @@ void register_node_type_geo_proximity()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_PROXIMITY, "Geometry Proximity", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_PROXIMITY, "Geometry Proximity", NODE_CLASS_GEOMETRY);
node_type_init(&ntype, file_ns::geo_proximity_init);
node_type_storage(
&ntype, "NodeGeometryProximity", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
index d255fe482f6..2c35ca0afc9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -75,8 +75,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast),
- __func__);
+ NodeGeometryRaycast *data = MEM_cnew<NodeGeometryRaycast>(__func__);
data->mapping = GEO_NODE_RAYCAST_INTERPOLATED;
data->data_type = CD_PROP_FLOAT;
node->storage = data;
@@ -449,7 +448,7 @@ void register_node_type_geo_raycast()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
index fad35389823..48b88705ed2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc
@@ -54,8 +54,7 @@ void register_node_type_geo_realize_instances()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_REALIZE_INSTANCES, "Realize Instances", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_REALIZE_INSTANCES, "Realize Instances", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
ntype.draw_buttons_ex = file_ns::node_layout;
ntype.geometry_node_execute = file_ns::node_geo_exec;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
index 335484c62b0..5a088e16221 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc
@@ -112,8 +112,7 @@ void register_node_type_geo_rotate_instances()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_ROTATE_INSTANCES, "Rotate Instances", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_ROTATE_INSTANCES, "Rotate Instances", 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/node_geo_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
index 1779ac8bff7..04c4e097f8d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc
@@ -91,7 +91,7 @@ void register_node_type_geo_scale_instances()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SCALE_INSTANCES, "Scale Instances", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SCALE_INSTANCES, "Scale Instances", 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/node_geo_separate_components.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
index e4adfe6587d..3e34378d3e0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc
@@ -70,7 +70,7 @@ void register_node_type_geo_separate_components()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_SEPARATE_COMPONENTS, "Separate Components", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_SEPARATE_COMPONENTS, "Separate Components", 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/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
index 7f1cc1be421..63da7399c3e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc
@@ -44,8 +44,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometrySeparateGeometry *data = (NodeGeometrySeparateGeometry *)MEM_callocN(
- sizeof(NodeGeometrySeparateGeometry), __func__);
+ NodeGeometrySeparateGeometry *data = MEM_cnew<NodeGeometrySeparateGeometry>(__func__);
data->domain = ATTR_DOMAIN_POINT;
node->storage = data;
@@ -60,38 +59,38 @@ static void node_geo_exec(GeoNodeExecParams params)
const NodeGeometrySeparateGeometry &storage = node_storage(params.node());
const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain);
- bool all_is_error = false;
- GeometrySet second_set(geometry_set);
- if (params.output_is_required("Selection")) {
- geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- bool this_is_error = false;
+ auto separate_geometry_maybe_recursively = [&](bool invert) {
+ bool is_error;
+ if (domain == ATTR_DOMAIN_INSTANCE) {
+ /* Only delete top level instances. */
separate_geometry(geometry_set,
domain,
GEO_NODE_DELETE_GEOMETRY_MODE_ALL,
selection_field,
- false,
- this_is_error);
- all_is_error &= this_is_error;
- });
+ invert,
+ is_error);
+ }
+ else {
+ geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
+ separate_geometry(geometry_set,
+ domain,
+ GEO_NODE_DELETE_GEOMETRY_MODE_ALL,
+ selection_field,
+ invert,
+ is_error);
+ });
+ }
+ };
+
+ GeometrySet second_set(geometry_set);
+ if (params.output_is_required("Selection")) {
+ separate_geometry_maybe_recursively(false);
params.set_output("Selection", std::move(geometry_set));
}
if (params.output_is_required("Inverted")) {
- second_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
- bool this_is_error = false;
- separate_geometry(geometry_set,
- domain,
- GEO_NODE_DELETE_GEOMETRY_MODE_ALL,
- selection_field,
- true,
- this_is_error);
- all_is_error &= this_is_error;
- });
+ separate_geometry_maybe_recursively(true);
params.set_output("Inverted", std::move(second_set));
}
- if (all_is_error) {
- /* Only show this if none of the instances/components actually changed. */
- params.error_message_add(NodeWarningType::Info, TIP_("No geometry with given domain"));
- }
}
} // namespace blender::nodes::node_geo_separate_geometry_cc
@@ -102,8 +101,7 @@ void register_node_type_geo_separate_geometry()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_SEPARATE_GEOMETRY, "Separate Geometry", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SEPARATE_GEOMETRY, "Separate Geometry", NODE_CLASS_GEOMETRY);
node_type_storage(&ntype,
"NodeGeometrySeparateGeometry",
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 30a61574e19..feab0a6743f 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
@@ -41,8 +41,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometrySetCurveHandlePositions *data = (NodeGeometrySetCurveHandlePositions *)MEM_callocN(
- sizeof(NodeGeometrySetCurveHandlePositions), __func__);
+ NodeGeometrySetCurveHandlePositions *data = MEM_cnew<NodeGeometrySetCurveHandlePositions>(
+ __func__);
data->mode = GEO_NODE_CURVE_HANDLE_LEFT;
node->storage = data;
@@ -65,7 +65,7 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode,
evaluator.add(position_field);
evaluator.add(offset_field);
evaluator.evaluate();
- const IndexMask selection = evaluator.get_evaluated_as_mask(0);
+ const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
CurveComponent *curve_component = static_cast<CurveComponent *>(&component);
CurveEval *curve = curve_component->get_for_write();
@@ -167,7 +167,7 @@ void register_node_type_geo_set_curve_handles()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_SET_CURVE_HANDLES, "Set Handle Positions", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_SET_CURVE_HANDLES, "Set Handle Positions", NODE_CLASS_GEOMETRY);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
ntype.minwidth = 100.0f;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
index 7d99f42c487..06fe4427520 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc
@@ -75,8 +75,7 @@ void register_node_type_geo_set_curve_radius()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_SET_CURVE_RADIUS, "Set Curve Radius", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_RADIUS, "Set Curve Radius", 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/node_geo_set_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
index 447310e1ad7..0854d0a4549 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc
@@ -71,7 +71,7 @@ void register_node_type_geo_set_curve_tilt()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_TILT, "Set Curve Tilt", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_TILT, "Set Curve Tilt", 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/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
index db4083acd4b..110b8206944 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc
@@ -87,7 +87,7 @@ void register_node_type_geo_set_id()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SET_ID, "Set ID", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_ID, "Set ID", 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/node_geo_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
index 30510c3570c..ab2c778d6fc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc
@@ -40,6 +40,12 @@ static void node_declare(NodeDeclarationBuilder &b)
static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Material *material)
{
+ if (selection.size() != mesh.totpoly) {
+ /* If the entire mesh isn't selected, and there is no material slot yet, add an empty
+ * slot so that the faces that aren't selected can still refer to the default material. */
+ BKE_id_material_eval_ensure_default_slot(&mesh.id);
+ }
+
int new_material_index = -1;
for (const int i : IndexRange(mesh.totcol)) {
Material *other_material = mesh.mat[i];
@@ -121,7 +127,7 @@ void register_node_type_geo_set_material()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SET_MATERIAL, "Set Material", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_MATERIAL, "Set 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/node_geo_set_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
index 4451907132a..ca6d78adc80 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc
@@ -70,7 +70,7 @@ void register_node_type_geo_set_material_index()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_SET_MATERIAL_INDEX, "Set Material Index", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_SET_MATERIAL_INDEX, "Set Material Index", 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/node_geo_set_point_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
index 98adff7c939..b7dd091da44 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc
@@ -76,8 +76,7 @@ void register_node_type_geo_set_point_radius()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_SET_POINT_RADIUS, "Set Point Radius", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_POINT_RADIUS, "Set Point Radius", 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/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
index 93073c2436d..4a8e4e6eab8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc
@@ -159,7 +159,7 @@ void register_node_type_geo_set_position()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SET_POSITION, "Set Position", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_POSITION, "Set Position", 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/node_geo_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
index 879a868cc0e..d442cd37e81 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc
@@ -70,8 +70,7 @@ void register_node_type_geo_set_shade_smooth()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_SET_SHADE_SMOOTH, "Set Shade Smooth", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_SHADE_SMOOTH, "Set Shade Smooth", 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/node_geo_set_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
index 694491d7e6d..13230e185a3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc
@@ -71,8 +71,7 @@ void register_node_type_geo_set_spline_cyclic()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_SET_SPLINE_CYCLIC, "Set Spline Cyclic", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SET_SPLINE_CYCLIC, "Set Spline Cyclic", 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/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc
index 0f93db5e6f6..e472e14671c 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
@@ -88,7 +88,7 @@ void register_node_type_geo_set_spline_resolution()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_SET_SPLINE_RESOLUTION, "Set Spline Resolution", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_SET_SPLINE_RESOLUTION, "Set Spline Resolution", 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/node_geo_string_join.cc b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
index 5308b43afb2..0fbe9a41ca5 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc
@@ -48,7 +48,7 @@ void register_node_type_geo_string_join()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_STRING_JOIN, "Join Strings", NODE_CLASS_CONVERTER, 0);
+ geo_node_type_base(&ntype, GEO_NODE_STRING_JOIN, "Join Strings", NODE_CLASS_CONVERTER);
ntype.geometry_node_execute = file_ns::node_geo_exec;
ntype.declare = file_ns::node_declare;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
index 33614eb3c46..68d62a842e6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc
@@ -88,8 +88,7 @@ static void node_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryStringToCurves *data = (NodeGeometryStringToCurves *)MEM_callocN(
- sizeof(NodeGeometryStringToCurves), __func__);
+ NodeGeometryStringToCurves *data = MEM_cnew<NodeGeometryStringToCurves>(__func__);
data->overflow = GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW;
data->align_x = GEO_NODE_STRING_TO_CURVES_ALIGN_X_LEFT;
@@ -311,8 +310,7 @@ void register_node_type_geo_string_to_curves()
static bNodeType ntype;
- geo_node_type_base(
- &ntype, GEO_NODE_STRING_TO_CURVES, "String to Curves", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_STRING_TO_CURVES, "String to Curves", 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);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index 74e0560b32f..eb1a5496845 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -52,8 +52,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN(
- sizeof(NodeGeometrySubdivisionSurface), __func__);
+ NodeGeometrySubdivisionSurface *data = MEM_cnew<NodeGeometrySubdivisionSurface>(__func__);
data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES;
data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL;
node->storage = data;
@@ -153,7 +152,7 @@ void register_node_type_geo_subdivision_surface()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_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;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
index d22522fe087..a2f05677310 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
@@ -94,7 +94,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeSwitch *data = (NodeSwitch *)MEM_callocN(sizeof(NodeSwitch), __func__);
+ NodeSwitch *data = MEM_cnew<NodeSwitch>(__func__);
data->input_type = SOCK_GEOMETRY;
node->storage = data;
}
@@ -327,7 +327,7 @@ void register_node_type_geo_switch()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER);
ntype.declare = file_ns::node_declare;
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
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 1f099dcd04d..331460296a6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc
@@ -88,8 +88,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryTransferAttribute *data = (NodeGeometryTransferAttribute *)MEM_callocN(
- sizeof(NodeGeometryTransferAttribute), __func__);
+ NodeGeometryTransferAttribute *data = MEM_cnew<NodeGeometryTransferAttribute>(__func__);
data->data_type = CD_PROP_FLOAT;
data->mode = GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED;
node->storage = data;
@@ -828,7 +827,7 @@ void register_node_type_geo_transfer_attribute()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_TRANSFER_ATTRIBUTE, "Transfer Attribute", NODE_CLASS_ATTRIBUTE, 0);
+ &ntype, GEO_NODE_TRANSFER_ATTRIBUTE, "Transfer Attribute", NODE_CLASS_ATTRIBUTE);
node_type_init(&ntype, file_ns::node_init);
node_type_update(&ntype, file_ns::node_update);
node_type_storage(&ntype,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index 8322de20d20..7f866ea6f4a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -226,7 +226,7 @@ void register_node_type_geo_transform()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", 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/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
index 59049ecf0ed..1061ece49a9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc
@@ -77,7 +77,7 @@ void register_node_type_geo_translate_instances()
static bNodeType ntype;
geo_node_type_base(
- &ntype, GEO_NODE_TRANSLATE_INSTANCES, "Translate Instances", NODE_CLASS_GEOMETRY, 0);
+ &ntype, GEO_NODE_TRANSLATE_INSTANCES, "Translate Instances", 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/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
index f8deaaa4a14..998e4d58bf3 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -77,7 +77,7 @@ void register_node_type_geo_triangulate()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", NODE_CLASS_GEOMETRY);
ntype.declare = file_ns::node_declare;
node_type_init(&ntype, file_ns::geo_triangulate_init);
ntype.geometry_node_execute = file_ns::node_geo_exec;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
index 18f2fa4cd36..c717d90f7cc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
@@ -42,8 +42,7 @@ static void node_declare(NodeDeclarationBuilder &b)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
- NodeGeometryViewer *data = (NodeGeometryViewer *)MEM_callocN(sizeof(NodeGeometryViewer),
- __func__);
+ NodeGeometryViewer *data = MEM_cnew<NodeGeometryViewer>(__func__);
data->data_type = CD_PROP_FLOAT;
node->storage = data;
@@ -141,7 +140,7 @@ void register_node_type_geo_viewer()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, 0);
+ geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT);
node_type_storage(
&ntype, "NodeGeometryViewer", node_free_standard_storage, node_copy_standard_storage);
node_type_update(&ntype, file_ns::node_update);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
index 0819b401941..c7dc73f8a91 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
@@ -69,8 +69,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN(
- sizeof(NodeGeometryVolumeToMesh), __func__);
+ NodeGeometryVolumeToMesh *data = MEM_cnew<NodeGeometryVolumeToMesh>(__func__);
data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID;
node->storage = data;
}
@@ -215,7 +214,7 @@ void register_node_type_geo_volume_to_mesh()
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_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);
diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc
index dc223f07a26..449c6598307 100644
--- a/source/blender/nodes/intern/derived_node_tree.cc
+++ b/source/blender/nodes/intern/derived_node_tree.cc
@@ -270,6 +270,9 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn,
}
}
else if (linked_node->is_group_output_node()) {
+ if (linked_node.node_ref() != context_->tree().group_output_node()) {
+ continue;
+ }
if (context_->is_root()) {
/* This is a group output in the root node group. */
path_info.sockets.append(linked_socket);
diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc
index c302b1081af..1c9a1730635 100644
--- a/source/blender/nodes/intern/node_common.cc
+++ b/source/blender/nodes/intern/node_common.cc
@@ -38,6 +38,7 @@
#include "BLT_translation.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "RNA_types.h"
@@ -153,8 +154,6 @@ static void update_socket_to_match_interface(bNodeTree &node_tree,
/* Update socket type if necessary */
if (socket_to_update.typeinfo != interface_socket.typeinfo) {
nodeModifySocketType(&node_tree, &node, &socket_to_update, interface_socket.idname);
- /* Flag the tree to make sure link validity is updated after type changes. */
- node_tree.update |= NTREE_UPDATE_LINKS;
}
if (interface_socket.typeinfo->interface_verify_socket) {
@@ -225,7 +224,7 @@ void node_group_update(struct bNodeTree *ntree, struct bNode *node)
static void node_frame_init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeFrame *data = (NodeFrame *)MEM_callocN(sizeof(NodeFrame), "frame node storage");
+ NodeFrame *data = MEM_cnew<NodeFrame>("frame node storage");
node->storage = data;
data->flag |= NODE_FRAME_SHRINK;
@@ -233,16 +232,17 @@ static void node_frame_init(bNodeTree *UNUSED(ntree), bNode *node)
data->label_size = 20;
}
-void register_node_type_frame(void)
+void register_node_type_frame()
{
/* frame type is used for all tree types, needs dynamic allocation */
- bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "frame node type");
+ bNodeType *ntype = MEM_cnew<bNodeType>("frame node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
- node_type_base(ntype, NODE_FRAME, "Frame", NODE_CLASS_LAYOUT, NODE_BACKGROUND);
+ node_type_base(ntype, NODE_FRAME, "Frame", NODE_CLASS_LAYOUT);
node_type_init(ntype, node_frame_init);
node_type_storage(ntype, "NodeFrame", node_free_standard_storage, node_copy_standard_storage);
node_type_size(ntype, 150, 100, 0);
+ ntype->flag |= NODE_BACKGROUND;
nodeRegisterType(ntype);
}
@@ -262,13 +262,13 @@ static void node_reroute_init(bNodeTree *ntree, bNode *node)
nodeAddStaticSocket(ntree, node, SOCK_OUT, SOCK_RGBA, PROP_NONE, "Output", "Output");
}
-void register_node_type_reroute(void)
+void register_node_type_reroute()
{
/* frame type is used for all tree types, needs dynamic allocation */
- bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "frame node type");
+ bNodeType *ntype = MEM_cnew<bNodeType>("frame node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
- node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT, 0);
+ node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT);
node_type_init(ntype, node_reroute_init);
nodeRegisterType(ntype);
@@ -455,7 +455,7 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
}
if (link->fromsock == extsock) {
- bNodeLink *tlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "temporary link");
+ bNodeLink *tlink = MEM_cnew<bNodeLink>("temporary link");
*tlink = *link;
BLI_addtail(&tmplinks, tlink);
@@ -503,13 +503,13 @@ void node_group_input_update(bNodeTree *ntree, bNode *node)
}
}
-void register_node_type_group_input(void)
+void register_node_type_group_input()
{
/* used for all tree types, needs dynamic allocation */
- bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "node type");
+ bNodeType *ntype = MEM_cnew<bNodeType>("node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
- node_type_base(ntype, NODE_GROUP_INPUT, "Group Input", NODE_CLASS_INTERFACE, 0);
+ node_type_base(ntype, NODE_GROUP_INPUT, "Group Input", NODE_CLASS_INTERFACE);
node_type_size(ntype, 140, 80, 400);
node_type_init(ntype, node_group_input_init);
node_type_update(ntype, node_group_input_update);
@@ -552,7 +552,7 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
}
if (link->tosock == extsock) {
- bNodeLink *tlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "temporary link");
+ bNodeLink *tlink = MEM_cnew<bNodeLink>("temporary link");
*tlink = *link;
BLI_addtail(&tmplinks, tlink);
@@ -601,13 +601,13 @@ void node_group_output_update(bNodeTree *ntree, bNode *node)
}
}
-void register_node_type_group_output(void)
+void register_node_type_group_output()
{
/* used for all tree types, needs dynamic allocation */
- bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "node type");
+ bNodeType *ntype = MEM_cnew<bNodeType>("node type");
ntype->free_self = (void (*)(bNodeType *))MEM_freeN;
- node_type_base(ntype, NODE_GROUP_OUTPUT, "Group Output", NODE_CLASS_INTERFACE, 0);
+ node_type_base(ntype, NODE_GROUP_OUTPUT, "Group Output", NODE_CLASS_INTERFACE);
node_type_size(ntype, 140, 80, 400);
node_type_init(ntype, node_group_output_init);
node_type_update(ntype, node_group_output_update);
diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc
index 75d47cfd386..28e8bf5a4b7 100644
--- a/source/blender/nodes/intern/node_declaration.cc
+++ b/source/blender/nodes/intern/node_declaration.cc
@@ -63,6 +63,7 @@ void SocketDeclaration::set_common_flags(bNodeSocket &socket) const
SET_FLAG_FROM_TEST(socket.flag, hide_label_, SOCK_HIDE_LABEL);
SET_FLAG_FROM_TEST(socket.flag, is_multi_input_, SOCK_MULTI_INPUT);
SET_FLAG_FROM_TEST(socket.flag, no_mute_links_, SOCK_NO_INTERNAL_LINK);
+ SET_FLAG_FROM_TEST(socket.flag, is_unavailable_, SOCK_UNAVAIL);
}
bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const
@@ -88,6 +89,9 @@ bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const
if (((socket.flag & SOCK_NO_INTERNAL_LINK) != 0) != no_mute_links_) {
return false;
}
+ if (((socket.flag & SOCK_UNAVAIL) != 0) != is_unavailable_) {
+ return false;
+ }
return true;
}
diff --git a/source/blender/nodes/intern/node_exec.cc b/source/blender/nodes/intern/node_exec.cc
index 95070bf735e..4ff662036c3 100644
--- a/source/blender/nodes/intern/node_exec.cc
+++ b/source/blender/nodes/intern/node_exec.cc
@@ -28,6 +28,7 @@
#include "BKE_global.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "MEM_guardedalloc.h"
@@ -170,13 +171,13 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context,
/* Using global main here is likely totally wrong, not sure what to do about that one though...
* We cannot even check ntree is in global main,
* since most of the time it won't be (thanks to ntree design)!!! */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
/* get a dependency-sorted list of nodes */
ntreeGetDependencyList(ntree, &nodelist, &totnodes);
/* XXX could let callbacks do this for specialized data */
- exec = (bNodeTreeExec *)MEM_callocN(sizeof(bNodeTreeExec), "node tree execution data");
+ exec = MEM_cnew<bNodeTreeExec>("node tree execution data");
/* backpointer to node tree */
exec->nodetree = ntree;
@@ -291,7 +292,7 @@ bNodeThreadStack *ntreeGetThreadStack(bNodeTreeExec *exec, int thread)
}
if (!nts) {
- nts = (bNodeThreadStack *)MEM_callocN(sizeof(bNodeThreadStack), "bNodeThreadStack");
+ nts = MEM_cnew<bNodeThreadStack>("bNodeThreadStack");
nts->stack = (bNodeStack *)MEM_dupallocN(exec->stack);
nts->used = true;
BLI_addtail(lb, nts);
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index d83c05b38a1..6a6b6e3d3cc 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -236,6 +236,14 @@ static void refresh_socket_list(bNodeTree &ntree,
link->tosock = new_socket;
}
}
+ LISTBASE_FOREACH (bNodeLink *, internal_link, &node.internal_links) {
+ if (internal_link->fromsock == old_socket_with_same_identifier) {
+ internal_link->fromsock = new_socket;
+ }
+ else if (internal_link->tosock == old_socket_with_same_identifier) {
+ internal_link->tosock = new_socket;
+ }
+ }
}
}
}
@@ -301,8 +309,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
switch (type) {
case SOCK_FLOAT: {
- bNodeSocketValueFloat *dval = (bNodeSocketValueFloat *)MEM_callocN(
- sizeof(bNodeSocketValueFloat), "node socket value float");
+ bNodeSocketValueFloat *dval = MEM_cnew<bNodeSocketValueFloat>("node socket value float");
dval->subtype = subtype;
dval->value = 0.0f;
dval->min = -FLT_MAX;
@@ -312,8 +319,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
break;
}
case SOCK_INT: {
- bNodeSocketValueInt *dval = (bNodeSocketValueInt *)MEM_callocN(sizeof(bNodeSocketValueInt),
- "node socket value int");
+ bNodeSocketValueInt *dval = MEM_cnew<bNodeSocketValueInt>("node socket value int");
dval->subtype = subtype;
dval->value = 0;
dval->min = INT_MIN;
@@ -323,8 +329,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
break;
}
case SOCK_BOOLEAN: {
- bNodeSocketValueBoolean *dval = (bNodeSocketValueBoolean *)MEM_callocN(
- sizeof(bNodeSocketValueBoolean), "node socket value bool");
+ bNodeSocketValueBoolean *dval = MEM_cnew<bNodeSocketValueBoolean>("node socket value bool");
dval->value = false;
sock->default_value = dval;
@@ -332,8 +337,7 @@ void node_socket_init_default_value(bNodeSocket *sock)
}
case SOCK_VECTOR: {
static float default_value[] = {0.0f, 0.0f, 0.0f};
- bNodeSocketValueVector *dval = (bNodeSocketValueVector *)MEM_callocN(
- sizeof(bNodeSocketValueVector), "node socket value vector");
+ bNodeSocketValueVector *dval = MEM_cnew<bNodeSocketValueVector>("node socket value vector");
dval->subtype = subtype;
copy_v3_v3(dval->value, default_value);
dval->min = -FLT_MAX;
@@ -344,16 +348,14 @@ void node_socket_init_default_value(bNodeSocket *sock)
}
case SOCK_RGBA: {
static float default_value[] = {0.0f, 0.0f, 0.0f, 1.0f};
- bNodeSocketValueRGBA *dval = (bNodeSocketValueRGBA *)MEM_callocN(
- sizeof(bNodeSocketValueRGBA), "node socket value color");
+ bNodeSocketValueRGBA *dval = MEM_cnew<bNodeSocketValueRGBA>("node socket value color");
copy_v4_v4(dval->value, default_value);
sock->default_value = dval;
break;
}
case SOCK_STRING: {
- bNodeSocketValueString *dval = (bNodeSocketValueString *)MEM_callocN(
- sizeof(bNodeSocketValueString), "node socket value string");
+ bNodeSocketValueString *dval = MEM_cnew<bNodeSocketValueString>("node socket value string");
dval->subtype = subtype;
dval->value[0] = '\0';
@@ -361,40 +363,38 @@ void node_socket_init_default_value(bNodeSocket *sock)
break;
}
case SOCK_OBJECT: {
- bNodeSocketValueObject *dval = (bNodeSocketValueObject *)MEM_callocN(
- sizeof(bNodeSocketValueObject), "node socket value object");
+ bNodeSocketValueObject *dval = MEM_cnew<bNodeSocketValueObject>("node socket value object");
dval->value = nullptr;
sock->default_value = dval;
break;
}
case SOCK_IMAGE: {
- bNodeSocketValueImage *dval = (bNodeSocketValueImage *)MEM_callocN(
- sizeof(bNodeSocketValueImage), "node socket value image");
+ bNodeSocketValueImage *dval = MEM_cnew<bNodeSocketValueImage>("node socket value image");
dval->value = nullptr;
sock->default_value = dval;
break;
}
case SOCK_COLLECTION: {
- bNodeSocketValueCollection *dval = (bNodeSocketValueCollection *)MEM_callocN(
- sizeof(bNodeSocketValueCollection), "node socket value object");
+ bNodeSocketValueCollection *dval = MEM_cnew<bNodeSocketValueCollection>(
+ "node socket value object");
dval->value = nullptr;
sock->default_value = dval;
break;
}
case SOCK_TEXTURE: {
- bNodeSocketValueTexture *dval = (bNodeSocketValueTexture *)MEM_callocN(
- sizeof(bNodeSocketValueTexture), "node socket value texture");
+ bNodeSocketValueTexture *dval = MEM_cnew<bNodeSocketValueTexture>(
+ "node socket value texture");
dval->value = nullptr;
sock->default_value = dval;
break;
}
case SOCK_MATERIAL: {
- bNodeSocketValueMaterial *dval = (bNodeSocketValueMaterial *)MEM_callocN(
- sizeof(bNodeSocketValueMaterial), "node socket value material");
+ bNodeSocketValueMaterial *dval = MEM_cnew<bNodeSocketValueMaterial>(
+ "node socket value material");
dval->value = nullptr;
sock->default_value = dval;
@@ -629,7 +629,7 @@ static bNodeSocketType *make_standard_socket_type(int type, int subtype)
bNodeSocketType *stype;
StructRNA *srna;
- stype = (bNodeSocketType *)MEM_callocN(sizeof(bNodeSocketType), "node socket C type");
+ stype = MEM_cnew<bNodeSocketType>("node socket C type");
stype->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN;
BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname));
BLI_strncpy(stype->label, socket_label, sizeof(stype->label));
@@ -673,7 +673,7 @@ static bNodeSocketType *make_socket_type_virtual()
bNodeSocketType *stype;
StructRNA *srna;
- stype = (bNodeSocketType *)MEM_callocN(sizeof(bNodeSocketType), "node socket C type");
+ stype = MEM_cnew<bNodeSocketType>("node socket C type");
stype->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN;
BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname));
@@ -872,7 +872,7 @@ static bNodeSocketType *make_socket_type_material()
return socktype;
}
-void register_standard_node_socket_types(void)
+void register_standard_node_socket_types()
{
/* Draw callbacks are set in `drawnode.c` to avoid bad-level calls. */
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index 912d5e5322c..bc78533d45c 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -70,6 +70,8 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
break;
}
}
+ BLI_assert(internal_link.from_ != nullptr);
+ BLI_assert(internal_link.to_ != nullptr);
node.internal_links_.append(&internal_link);
}
@@ -115,6 +117,22 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree)
const bNodeType *nodetype = node->bnode_->typeinfo;
nodes_by_type_.add(nodetype, node);
}
+
+ const Span<const NodeRef *> group_output_nodes = this->nodes_by_type("NodeGroupOutput");
+ if (group_output_nodes.is_empty()) {
+ group_output_node_ = nullptr;
+ }
+ else if (group_output_nodes.size() == 1) {
+ group_output_node_ = group_output_nodes.first();
+ }
+ else {
+ for (const NodeRef *group_output : group_output_nodes) {
+ if (group_output->bnode_->flag & NODE_DO_OUTPUT) {
+ group_output_node_ = group_output;
+ break;
+ }
+ }
+ }
}
NodeTreeRef::~NodeTreeRef()
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c
index 7620c8fa1a8..5c2d84cf605 100644
--- a/source/blender/nodes/intern/node_util.c
+++ b/source/blender/nodes/intern/node_util.c
@@ -35,6 +35,7 @@
#include "BKE_colortools.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "RNA_access.h"
#include "RNA_enum_types.h"
@@ -340,188 +341,6 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Internal Links (mute and disconnect)
- * \{ */
-
-/**
- * Common datatype priorities, works for compositor, shader and texture nodes alike
- * defines priority of datatype connection based on output type (to):
- * `< 0`: never connect these types.
- * `>= 0`: priority of connection (higher values chosen first).
- */
-static int node_datatype_priority(const bNodeSocketType *from, const bNodeSocketType *to)
-{
- switch (to->type) {
- case SOCK_RGBA:
- switch (from->type) {
- case SOCK_RGBA:
- return 4;
- case SOCK_FLOAT:
- return 3;
- case SOCK_INT:
- return 2;
- case SOCK_BOOLEAN:
- return 1;
- }
- return -1;
- case SOCK_VECTOR:
- switch (from->type) {
- case SOCK_VECTOR:
- return 4;
- case SOCK_FLOAT:
- return 3;
- case SOCK_INT:
- return 2;
- case SOCK_BOOLEAN:
- return 1;
- }
- return -1;
- case SOCK_FLOAT:
- switch (from->type) {
- case SOCK_FLOAT:
- return 5;
- case SOCK_INT:
- return 4;
- case SOCK_BOOLEAN:
- return 3;
- case SOCK_RGBA:
- return 2;
- case SOCK_VECTOR:
- return 1;
- }
- return -1;
- case SOCK_INT:
- switch (from->type) {
- case SOCK_INT:
- return 5;
- case SOCK_FLOAT:
- return 4;
- case SOCK_BOOLEAN:
- return 3;
- case SOCK_RGBA:
- return 2;
- case SOCK_VECTOR:
- return 1;
- }
- return -1;
- case SOCK_BOOLEAN:
- switch (from->type) {
- case SOCK_BOOLEAN:
- return 5;
- case SOCK_INT:
- return 4;
- case SOCK_FLOAT:
- return 3;
- case SOCK_RGBA:
- return 2;
- case SOCK_VECTOR:
- return 1;
- }
- return -1;
- }
-
- /* The rest of the socket types only allow an internal link if both the input and output socket
- * have the same type. If the sockets are custom, we check the idname instead. */
- if (to->type == from->type && (to->type != SOCK_CUSTOM || STREQ(to->idname, from->idname))) {
- return 1;
- }
-
- return -1;
-}
-
-/* select a suitable input socket for an output */
-static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output)
-{
- if (node->type == NODE_REROUTE) {
- return node->inputs.first;
- }
-
- bNodeSocket *selected = NULL, *input;
- int i;
- int sel_priority = -1;
- bool sel_is_linked = false;
-
- for (input = node->inputs.first, i = 0; input; input = input->next, i++) {
- int priority = node_datatype_priority(input->typeinfo, output->typeinfo);
- bool is_linked = (input->link != NULL);
- bool preferred;
-
- if (nodeSocketIsHidden(input) || /* ignore hidden sockets */
- input->flag &
- SOCK_NO_INTERNAL_LINK || /* ignore if input is not allowed for internal connections */
- priority < 0 || /* ignore incompatible types */
- priority < sel_priority) /* ignore if we already found a higher priority input */
- {
- continue;
- }
-
- /* determine if this input is preferred over the currently selected */
- preferred = (priority > sel_priority) || /* prefer higher datatype priority */
- (is_linked && !sel_is_linked); /* prefer linked over unlinked */
-
- if (preferred) {
- selected = input;
- sel_is_linked = is_linked;
- sel_priority = priority;
- }
- }
-
- return selected;
-}
-
-void node_internal_links_create(bNodeTree *ntree, bNode *node)
-{
- bNodeLink *link;
- bNodeSocket *output, *input;
-
- /* sanity check */
- if (!ntree) {
- return;
- }
-
- /* use link pointer as a tag for handled sockets (for outputs is unused anyway) */
- for (output = node->outputs.first; output; output = output->next) {
- output->link = NULL;
- }
-
- for (link = ntree->links.first; link; link = link->next) {
- if (nodeLinkIsHidden(link)) {
- continue;
- }
-
- output = link->fromsock;
- if (link->fromnode != node || output->link) {
- continue;
- }
- if (nodeSocketIsHidden(output) || output->flag & SOCK_NO_INTERNAL_LINK) {
- continue;
- }
- output->link = link; /* not really used, just for tagging handled sockets */
-
- /* look for suitable input */
- input = select_internal_link_input(node, output);
-
- if (input) {
- bNodeLink *ilink = MEM_callocN(sizeof(bNodeLink), "internal node link");
- ilink->fromnode = node;
- ilink->fromsock = input;
- ilink->tonode = node;
- ilink->tosock = output;
- /* internal link is always valid */
- ilink->flag |= NODE_LINK_VALID;
- BLI_addtail(&node->internal_links, ilink);
- }
- }
-
- /* clean up */
- for (output = node->outputs.first; output; output = output->next) {
- output->link = NULL;
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Default value RNA access
* \{ */
diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt
index 7d99c233197..9878ebe3162 100644
--- a/source/blender/nodes/shader/CMakeLists.txt
+++ b/source/blender/nodes/shader/CMakeLists.txt
@@ -26,6 +26,7 @@ set(INC
../../blenlib
../../blentranslation
../../depsgraph
+ ../../editors/include
../../functions
../../gpu
../../imbuf
@@ -39,101 +40,102 @@ set(INC
set(SRC
- nodes/node_shader_add_shader.c
- nodes/node_shader_ambient_occlusion.c
- nodes/node_shader_attribute.c
- nodes/node_shader_background.c
- nodes/node_shader_bevel.c
- nodes/node_shader_blackbody.c
- nodes/node_shader_brightness.c
- nodes/node_shader_bsdf_anisotropic.c
- nodes/node_shader_bsdf_diffuse.c
- nodes/node_shader_bsdf_glass.c
- nodes/node_shader_bsdf_glossy.c
- nodes/node_shader_bsdf_hair.c
- nodes/node_shader_bsdf_hair_principled.c
- nodes/node_shader_bsdf_principled.c
- nodes/node_shader_bsdf_refraction.c
- nodes/node_shader_bsdf_toon.c
- nodes/node_shader_bsdf_translucent.c
- nodes/node_shader_bsdf_transparent.c
- nodes/node_shader_bsdf_velvet.c
- nodes/node_shader_bump.c
- nodes/node_shader_camera.c
+ nodes/node_shader_add_shader.cc
+ nodes/node_shader_ambient_occlusion.cc
+ nodes/node_shader_attribute.cc
+ nodes/node_shader_background.cc
+ nodes/node_shader_bevel.cc
+ nodes/node_shader_blackbody.cc
+ nodes/node_shader_brightness.cc
+ nodes/node_shader_bsdf_anisotropic.cc
+ nodes/node_shader_bsdf_diffuse.cc
+ nodes/node_shader_bsdf_glass.cc
+ nodes/node_shader_bsdf_glossy.cc
+ nodes/node_shader_bsdf_hair.cc
+ nodes/node_shader_bsdf_hair_principled.cc
+ nodes/node_shader_bsdf_principled.cc
+ nodes/node_shader_bsdf_refraction.cc
+ nodes/node_shader_bsdf_toon.cc
+ nodes/node_shader_bsdf_translucent.cc
+ nodes/node_shader_bsdf_transparent.cc
+ nodes/node_shader_bsdf_velvet.cc
+ nodes/node_shader_bump.cc
+ nodes/node_shader_camera.cc
nodes/node_shader_clamp.cc
- nodes/node_shader_common.c
+ nodes/node_shader_color_ramp.cc
+ nodes/node_shader_common.cc
nodes/node_shader_curves.cc
- nodes/node_shader_displacement.c
- nodes/node_shader_eevee_specular.c
- nodes/node_shader_emission.c
- nodes/node_shader_fresnel.c
- nodes/node_shader_gamma.c
- nodes/node_shader_geometry.c
- nodes/node_shader_hair_info.c
- nodes/node_shader_holdout.c
- nodes/node_shader_hueSatVal.c
- nodes/node_shader_ies_light.c
- nodes/node_shader_invert.c
- nodes/node_shader_layer_weight.c
- nodes/node_shader_light_falloff.c
- nodes/node_shader_light_path.c
+ nodes/node_shader_displacement.cc
+ nodes/node_shader_eevee_specular.cc
+ nodes/node_shader_emission.cc
+ nodes/node_shader_fresnel.cc
+ nodes/node_shader_gamma.cc
+ nodes/node_shader_geometry.cc
+ nodes/node_shader_hair_info.cc
+ nodes/node_shader_holdout.cc
+ nodes/node_shader_hueSatVal.cc
+ nodes/node_shader_ies_light.cc
+ nodes/node_shader_invert.cc
+ nodes/node_shader_layer_weight.cc
+ nodes/node_shader_light_falloff.cc
+ nodes/node_shader_light_path.cc
nodes/node_shader_map_range.cc
- nodes/node_shader_mapping.c
+ nodes/node_shader_mapping.cc
nodes/node_shader_math.cc
nodes/node_shader_mix_rgb.cc
- nodes/node_shader_mix_shader.c
- nodes/node_shader_normal.c
- nodes/node_shader_normal_map.c
- nodes/node_shader_object_info.c
- nodes/node_shader_output_aov.c
- nodes/node_shader_output_light.c
- nodes/node_shader_output_linestyle.c
- nodes/node_shader_output_material.c
- nodes/node_shader_output_world.c
- nodes/node_shader_particle_info.c
+ nodes/node_shader_mix_shader.cc
+ nodes/node_shader_normal.cc
+ nodes/node_shader_normal_map.cc
+ nodes/node_shader_object_info.cc
+ nodes/node_shader_output_aov.cc
+ nodes/node_shader_output_light.cc
+ nodes/node_shader_output_linestyle.cc
+ nodes/node_shader_output_material.cc
+ nodes/node_shader_output_world.cc
+ nodes/node_shader_particle_info.cc
nodes/node_shader_rgb_to_bw.cc
- nodes/node_shader_rgb.c
- nodes/node_shader_script.c
- nodes/node_shader_sepcomb_hsv.c
+ nodes/node_shader_rgb.cc
+ nodes/node_shader_script.cc
+ nodes/node_shader_sepcomb_hsv.cc
nodes/node_shader_sepcomb_rgb.cc
nodes/node_shader_sepcomb_xyz.cc
- nodes/node_shader_shader_to_rgb.c
- nodes/node_shader_squeeze.c
- nodes/node_shader_subsurface_scattering.c
- nodes/node_shader_tangent.c
+ nodes/node_shader_shader_to_rgb.cc
+ nodes/node_shader_squeeze.cc
+ nodes/node_shader_subsurface_scattering.cc
+ nodes/node_shader_tangent.cc
nodes/node_shader_tex_brick.cc
nodes/node_shader_tex_checker.cc
- nodes/node_shader_tex_coord.c
- nodes/node_shader_tex_environment.c
+ nodes/node_shader_tex_coord.cc
+ nodes/node_shader_tex_environment.cc
nodes/node_shader_tex_gradient.cc
nodes/node_shader_tex_image.cc
nodes/node_shader_tex_magic.cc
nodes/node_shader_tex_musgrave.cc
nodes/node_shader_tex_noise.cc
- nodes/node_shader_tex_pointdensity.c
- nodes/node_shader_tex_sky.c
+ nodes/node_shader_tex_pointdensity.cc
+ nodes/node_shader_tex_sky.cc
nodes/node_shader_tex_voronoi.cc
nodes/node_shader_tex_wave.cc
nodes/node_shader_tex_white_noise.cc
- nodes/node_shader_uv_along_stroke.c
- nodes/node_shader_uvmap.c
+ nodes/node_shader_uv_along_stroke.cc
+ nodes/node_shader_uvmap.cc
nodes/node_shader_value.cc
- nodes/node_shader_vector_displacement.c
+ nodes/node_shader_vector_displacement.cc
nodes/node_shader_vector_math.cc
nodes/node_shader_vector_rotate.cc
- nodes/node_shader_vector_transform.c
- nodes/node_shader_vertex_color.c
- nodes/node_shader_volume_absorption.c
- nodes/node_shader_volume_info.c
- nodes/node_shader_volume_principled.c
- nodes/node_shader_volume_scatter.c
- nodes/node_shader_wavelength.c
- nodes/node_shader_wireframe.c
+ nodes/node_shader_vector_transform.cc
+ nodes/node_shader_vertex_color.cc
+ nodes/node_shader_volume_absorption.cc
+ nodes/node_shader_volume_info.cc
+ nodes/node_shader_volume_principled.cc
+ nodes/node_shader_volume_scatter.cc
+ nodes/node_shader_wavelength.cc
+ nodes/node_shader_wireframe.cc
- node_shader_tree.c
+ node_shader_tree.cc
node_shader_util.cc
- node_shader_util.h
+ node_shader_util.hh
)
set(LIB
@@ -164,3 +166,8 @@ if(WITH_FREESTYLE)
endif()
blender_add_lib(bf_nodes_shader "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+if(WITH_UNITY_BUILD)
+ set_target_properties(bf_nodes_shader PROPERTIES UNITY_BUILD ON)
+ set_target_properties(bf_nodes_shader PROPERTIES UNITY_BUILD_BATCH_SIZE 10)
+endif()
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.cc
index c3b5236373c..1552ed9f19c 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.cc
@@ -21,7 +21,7 @@
* \ingroup nodes
*/
-#include <string.h>
+#include <cstring>
#include "DNA_light_types.h"
#include "DNA_linestyle_types.h"
@@ -44,6 +44,7 @@
#include "BKE_lib_id.h"
#include "BKE_linestyle.h"
#include "BKE_node.h"
+#include "BKE_node_tree_update.h"
#include "BKE_scene.h"
#include "RNA_access.h"
@@ -52,16 +53,18 @@
#include "RE_texture.h"
+#include "UI_resources.h"
+
#include "NOD_common.h"
#include "node_common.h"
#include "node_exec.h"
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
#include "node_util.h"
-typedef struct nTreeTags {
+struct nTreeTags {
float ssr_id, sss_id;
-} nTreeTags;
+};
static void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tags);
@@ -91,7 +94,7 @@ static void shader_get_from_context(const bContext *C,
if (ob) {
*r_from = &ob->id;
if (ob->type == OB_LAMP) {
- *r_id = ob->data;
+ *r_id = static_cast<ID *>(ob->data);
*r_ntree = ((Light *)ob->data)->nodetree;
}
else {
@@ -107,7 +110,7 @@ static void shader_get_from_context(const bContext *C,
else if (snode->shaderfrom == SNODE_SHADER_LINESTYLE) {
FreestyleLineStyle *linestyle = BKE_linestyle_active_from_view_layer(view_layer);
if (linestyle) {
- *r_from = NULL;
+ *r_from = nullptr;
*r_id = &linestyle->id;
*r_ntree = linestyle->nodetree;
}
@@ -115,7 +118,7 @@ static void shader_get_from_context(const bContext *C,
#endif
else { /* SNODE_SHADER_WORLD */
if (scene->world) {
- *r_from = NULL;
+ *r_from = nullptr;
*r_id = &scene->world->id;
*r_ntree = scene->world->nodetree;
}
@@ -148,26 +151,11 @@ static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree))
}
}
-static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_sync_tree(ntree, localtree);
-}
-
-static void local_merge(Main *UNUSED(bmain), bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_merge_tree(ntree, localtree, true);
-}
-
static void update(bNodeTree *ntree)
{
ntreeSetOutput(ntree);
ntree_update_reroute_nodes(ntree);
-
- if (ntree->update & NTREE_UPDATE_NODES) {
- /* clean up preview cache, in case nodes have been removed */
- BKE_node_preview_remove_unused(ntree);
- }
}
static bool shader_validate_link(eNodeSocketDatatype from, eNodeSocketDatatype to)
@@ -189,21 +177,18 @@ static bool shader_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
bNodeTreeType *ntreeType_Shader;
-void register_node_tree_type_sh(void)
+void register_node_tree_type_sh()
{
- bNodeTreeType *tt = ntreeType_Shader = MEM_callocN(sizeof(bNodeTreeType),
- "shader node tree type");
+ bNodeTreeType *tt = ntreeType_Shader = MEM_cnew<bNodeTreeType>("shader node tree type");
tt->type = NTREE_SHADER;
strcpy(tt->idname, "ShaderNodeTree");
strcpy(tt->ui_name, N_("Shader Editor"));
- tt->ui_icon = 0; /* Defined in `drawnode.c`. */
+ tt->ui_icon = ICON_NODE_MATERIAL;
strcpy(tt->ui_description, N_("Shader nodes"));
tt->foreach_nodeclass = foreach_nodeclass;
tt->localize = localize;
- tt->local_sync = local_sync;
- tt->local_merge = local_merge;
tt->update = update;
tt->poll = shader_tree_poll;
tt->get_from_context = shader_get_from_context;
@@ -224,7 +209,7 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
/* Find output node that matches type and target. If there are
* multiple, we prefer exact target match and active nodes. */
- bNode *output_node = NULL;
+ bNode *output_node = nullptr;
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (!ELEM(node->type, SH_NODE_OUTPUT_MATERIAL, SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LIGHT)) {
@@ -232,7 +217,7 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
}
if (node->custom1 == SHD_OUTPUT_ALL) {
- if (output_node == NULL) {
+ if (output_node == nullptr) {
output_node = node;
}
else if (output_node->custom1 == SHD_OUTPUT_ALL) {
@@ -242,7 +227,7 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
}
}
else if (node->custom1 == target) {
- if (output_node == NULL) {
+ if (output_node == nullptr) {
output_node = node;
}
else if (output_node->custom1 == SHD_OUTPUT_ALL) {
@@ -260,12 +245,12 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target)
/* Find socket with a specified identifier. */
static bNodeSocket *ntree_shader_node_find_socket(ListBase *sockets, const char *identifier)
{
- for (bNodeSocket *sock = sockets->first; sock != NULL; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, sockets) {
if (STREQ(sock->identifier, identifier)) {
return sock;
}
}
- return NULL;
+ return nullptr;
}
/* Find input socket with a specified identifier. */
@@ -294,37 +279,37 @@ static bool ntree_shader_expand_socket_default(bNodeTree *localtree,
switch (socket->type) {
case SOCK_VECTOR:
- value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_RGB);
+ value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_RGB);
value_socket = ntree_shader_node_find_output(value_node, "Color");
- BLI_assert(value_socket != NULL);
- src_vector = socket->default_value;
- dst_rgba = value_socket->default_value;
+ BLI_assert(value_socket != nullptr);
+ src_vector = static_cast<bNodeSocketValueVector *>(socket->default_value);
+ dst_rgba = static_cast<bNodeSocketValueRGBA *>(value_socket->default_value);
copy_v3_v3(dst_rgba->value, src_vector->value);
dst_rgba->value[3] = 1.0f; /* should never be read */
break;
case SOCK_RGBA:
- value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_RGB);
+ value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_RGB);
value_socket = ntree_shader_node_find_output(value_node, "Color");
- BLI_assert(value_socket != NULL);
- src_rgba = socket->default_value;
- dst_rgba = value_socket->default_value;
+ BLI_assert(value_socket != nullptr);
+ src_rgba = static_cast<bNodeSocketValueRGBA *>(socket->default_value);
+ dst_rgba = static_cast<bNodeSocketValueRGBA *>(value_socket->default_value);
copy_v4_v4(dst_rgba->value, src_rgba->value);
break;
case SOCK_INT:
/* HACK: Support as float. */
- value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_VALUE);
+ value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_VALUE);
value_socket = ntree_shader_node_find_output(value_node, "Value");
- BLI_assert(value_socket != NULL);
- src_int = socket->default_value;
- dst_float = value_socket->default_value;
+ BLI_assert(value_socket != nullptr);
+ src_int = static_cast<bNodeSocketValueInt *>(socket->default_value);
+ dst_float = static_cast<bNodeSocketValueFloat *>(value_socket->default_value);
dst_float->value = (float)(src_int->value);
break;
case SOCK_FLOAT:
- value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_VALUE);
+ value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_VALUE);
value_socket = ntree_shader_node_find_output(value_node, "Value");
- BLI_assert(value_socket != NULL);
- src_float = socket->default_value;
- dst_float = value_socket->default_value;
+ BLI_assert(value_socket != nullptr);
+ src_float = static_cast<bNodeSocketValueFloat *>(socket->default_value);
+ dst_float = static_cast<bNodeSocketValueFloat *>(value_socket->default_value);
dst_float->value = src_float->value;
break;
default:
@@ -337,11 +322,10 @@ static bool ntree_shader_expand_socket_default(bNodeTree *localtree,
static void ntree_shader_unlink_hidden_value_sockets(bNode *group_node, bNodeSocket *isock)
{
bNodeTree *group_ntree = (bNodeTree *)group_node->id;
- bNode *node;
bool removed_link = false;
- for (node = group_ntree->nodes.first; node; node = node->next) {
- const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != NULL);
+ LISTBASE_FOREACH (bNode *, node, &group_ntree->nodes) {
+ const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != nullptr);
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (!is_group && (sock->flag & SOCK_HIDE_VALUE) == 0) {
@@ -364,7 +348,7 @@ static void ntree_shader_unlink_hidden_value_sockets(bNode *group_node, bNodeSoc
}
if (removed_link) {
- ntreeUpdateTree(G.main, group_ntree);
+ BKE_ntree_update_main_tree(G.main, group_ntree, nullptr);
}
}
@@ -375,7 +359,7 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
bool link_added = false;
LISTBASE_FOREACH (bNode *, node, &localtree->nodes) {
- const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != NULL);
+ const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != nullptr);
const bool is_group_output = node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT);
if (is_group) {
@@ -385,25 +369,32 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
if (is_group || is_group_output) {
LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
- if (socket->link != NULL && !(socket->link->flag & NODE_LINK_MUTED)) {
+ if (socket->link != nullptr && !(socket->link->flag & NODE_LINK_MUTED)) {
bNodeLink *link = socket->link;
/* Fix the case where the socket is actually converting the data. (see T71374)
* We only do the case of lossy conversion to float. */
if ((socket->type == SOCK_FLOAT) && (link->fromsock->type != link->tosock->type)) {
if (link->fromsock->type == SOCK_RGBA) {
- bNode *tmp = nodeAddStaticNode(NULL, localtree, SH_NODE_RGBTOBW);
- nodeAddLink(localtree, link->fromnode, link->fromsock, tmp, tmp->inputs.first);
- nodeAddLink(localtree, tmp, tmp->outputs.first, node, socket);
+ bNode *tmp = nodeAddStaticNode(nullptr, localtree, SH_NODE_RGBTOBW);
+ nodeAddLink(localtree,
+ link->fromnode,
+ link->fromsock,
+ tmp,
+ static_cast<bNodeSocket *>(tmp->inputs.first));
+ nodeAddLink(
+ localtree, tmp, static_cast<bNodeSocket *>(tmp->outputs.first), node, socket);
}
else if (link->fromsock->type == SOCK_VECTOR) {
- bNode *tmp = nodeAddStaticNode(NULL, localtree, SH_NODE_VECTOR_MATH);
+ bNode *tmp = nodeAddStaticNode(nullptr, localtree, SH_NODE_VECTOR_MATH);
tmp->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT;
- bNodeSocket *dot_input1 = tmp->inputs.first;
- bNodeSocket *dot_input2 = dot_input1->next;
- bNodeSocketValueVector *input2_socket_value = dot_input2->default_value;
+ bNodeSocket *dot_input1 = static_cast<bNodeSocket *>(tmp->inputs.first);
+ bNodeSocket *dot_input2 = static_cast<bNodeSocket *>(dot_input1->next);
+ bNodeSocketValueVector *input2_socket_value = static_cast<bNodeSocketValueVector *>(
+ dot_input2->default_value);
copy_v3_fl(input2_socket_value->value, 1.0f / 3.0f);
nodeAddLink(localtree, link->fromnode, link->fromsock, tmp, dot_input1);
- nodeAddLink(localtree, tmp, tmp->outputs.last, node, socket);
+ nodeAddLink(
+ localtree, tmp, static_cast<bNodeSocket *>(tmp->outputs.last), node, socket);
}
}
continue;
@@ -423,22 +414,17 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree)
}
if (link_added) {
- ntreeUpdateTree(G.main, localtree);
+ BKE_ntree_update_main_tree(G.main, localtree, nullptr);
}
}
static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
{
- bNodeLink *link, *linkn, *tlink;
- bNode *node, *nextnode;
- bNodeTree *ngroup;
- LinkNode *group_interface_nodes = NULL;
-
- ngroup = (bNodeTree *)gnode->id;
+ LinkNode *group_interface_nodes = nullptr;
+ bNodeTree *ngroup = (bNodeTree *)gnode->id;
/* Add the nodes into the ntree */
- for (node = ngroup->nodes.first; node; node = nextnode) {
- nextnode = node->next;
+ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup->nodes) {
/* Remove interface nodes.
* This also removes remaining links to and from interface nodes.
* We must delay removal since sockets will reference this node. see: T52092 */
@@ -454,25 +440,26 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
}
/* Save first and last link to iterate over flattened group links. */
- bNodeLink *glinks_first = ntree->links.last;
+ bNodeLink *glinks_first = static_cast<bNodeLink *>(ntree->links.last);
/* Add internal links to the ntree */
- for (link = ngroup->links.first; link; link = linkn) {
- linkn = link->next;
+ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ngroup->links) {
BLI_remlink(&ngroup->links, link);
BLI_addtail(&ntree->links, link);
}
- bNodeLink *glinks_last = ntree->links.last;
+ bNodeLink *glinks_last = static_cast<bNodeLink *>(ntree->links.last);
/* restore external links to and from the gnode */
- if (glinks_first != NULL) {
+ if (glinks_first != nullptr) {
/* input links */
- for (link = glinks_first->next; link != glinks_last->next; link = link->next) {
+ for (bNodeLink *link = glinks_first->next; link != glinks_last->next; link = link->next) {
if (link->fromnode->type == NODE_GROUP_INPUT) {
const char *identifier = link->fromsock->identifier;
/* find external links to this input */
- for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) {
+ for (bNodeLink *tlink = static_cast<bNodeLink *>(ntree->links.first);
+ tlink != glinks_first->next;
+ tlink = tlink->next) {
if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) {
nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock);
}
@@ -480,13 +467,15 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
}
}
/* Also iterate over the new links to cover passthrough links. */
- glinks_last = ntree->links.last;
+ glinks_last = static_cast<bNodeLink *>(ntree->links.last);
/* output links */
- for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) {
+ for (bNodeLink *tlink = static_cast<bNodeLink *>(ntree->links.first);
+ tlink != glinks_first->next;
+ tlink = tlink->next) {
if (tlink->fromnode == gnode) {
const char *identifier = tlink->fromsock->identifier;
/* find internal links to this output */
- for (link = glinks_first->next; link != glinks_last->next; link = link->next) {
+ for (bNodeLink *link = glinks_first->next; link != glinks_last->next; link = link->next) {
/* only use active output node */
if (link->tonode->type == NODE_GROUP_OUTPUT && (link->tonode->flag & NODE_DO_OUTPUT)) {
if (STREQ(link->tosock->identifier, identifier)) {
@@ -499,11 +488,11 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode)
}
while (group_interface_nodes) {
- node = BLI_linklist_pop(&group_interface_nodes);
+ bNode *node = static_cast<bNode *>(BLI_linklist_pop(&group_interface_nodes));
ntreeFreeLocalNode(ntree, node);
}
- ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
+ BKE_ntree_update_tag_all(ntree);
}
/* Flatten group to only have a simple single tree */
@@ -511,8 +500,9 @@ static void ntree_shader_groups_flatten(bNodeTree *localtree)
{
/* This is effectively recursive as the flattened groups will add
* nodes at the end of the list, which will also get evaluated. */
- for (bNode *node = localtree->nodes.first, *node_next; node; node = node_next) {
- if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != NULL) {
+ for (bNode *node = static_cast<bNode *>(localtree->nodes.first), *node_next; node;
+ node = node_next) {
+ if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != nullptr) {
flatten_group_do(localtree, node);
/* Continue even on new flattened nodes. */
node_next = node->next;
@@ -528,7 +518,7 @@ static void ntree_shader_groups_flatten(bNodeTree *localtree)
}
}
- ntreeUpdateTree(G.main, localtree);
+ BKE_ntree_update_main_tree(G.main, localtree, nullptr);
}
/* Check whether shader has a displacement.
@@ -543,20 +533,20 @@ static bool ntree_shader_has_displacement(bNodeTree *ntree,
bNodeSocket **r_socket,
bNodeLink **r_link)
{
- if (output_node == NULL) {
+ if (output_node == nullptr) {
/* We can't have displacement without output node, apparently. */
return false;
}
/* Make sure sockets links pointers are correct. */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
bNodeSocket *displacement = ntree_shader_node_find_input(output_node, "Displacement");
- if (displacement == NULL) {
+ if (displacement == nullptr) {
/* Non-cycles node is used as an output. */
return false;
}
- if ((displacement->link != NULL) && !(displacement->link->flag & NODE_LINK_MUTED)) {
+ if ((displacement->link != nullptr) && !(displacement->link->flag & NODE_LINK_MUTED)) {
*r_node = displacement->link->fromnode;
*r_socket = displacement->link->fromsock;
*r_link = displacement->link;
@@ -574,7 +564,7 @@ static void ntree_shader_relink_node_normal(bNodeTree *ntree,
* matching?
*/
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
- if (STREQ(sock->identifier, "Normal") && sock->link == NULL) {
+ if (STREQ(sock->identifier, "Normal") && sock->link == nullptr) {
/* It's a normal input and nothing is connected to it. */
nodeAddLink(ntree, node_from, socket_from, node, sock);
}
@@ -594,7 +584,7 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree,
bNode *node_from,
bNodeSocket *socket_from)
{
- for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node == node_from) {
/* Don't connect node itself! */
continue;
@@ -619,7 +609,7 @@ static void ntree_shader_bypass_bump_link(bNodeTree *ntree, bNode *bump_node, bN
fromnode = bump_normal_input->link->fromnode;
}
else {
- fromnode = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY);
+ fromnode = nodeAddStaticNode(nullptr, ntree, SH_NODE_NEW_GEOMETRY);
fromsock = ntree_shader_node_find_output(fromnode, "Normal");
}
/* Bypass the bump node by creating a link between the previous and next node. */
@@ -637,7 +627,7 @@ static void ntree_shader_bypass_tagged_bump_nodes(bNodeTree *ntree)
ntree_shader_bypass_bump_link(ntree, node, link);
}
}
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
}
static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, bNode *tonode, void *userdata)
@@ -671,19 +661,19 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree,
int node_count = 1;
nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count, 1);
/* Make a full copy of the branch */
- bNode **nodes_copy = MEM_mallocN(sizeof(bNode *) * node_count, __func__);
+ bNode **nodes_copy = static_cast<bNode **>(MEM_mallocN(sizeof(bNode *) * node_count, __func__));
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->tmp_flag >= 0) {
int id = node->tmp_flag;
- nodes_copy[id] = BKE_node_copy_ex(
+ nodes_copy[id] = BKE_node_copy(
ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN, false);
nodes_copy[id]->tmp_flag = -2; /* Copy */
/* Make sure to clear all sockets links as they are invalid. */
LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->inputs) {
- sock->link = NULL;
+ sock->link = nullptr;
}
LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->outputs) {
- sock->link = NULL;
+ sock->link = nullptr;
}
}
}
@@ -716,13 +706,13 @@ static void ntree_shader_copy_branch_displacement(bNodeTree *ntree,
/* Replace displacement socket/node/link. */
bNode *tonode = displacement_link->tonode;
bNodeSocket *tosock = displacement_link->tosock;
- displacement_node = ntree_shader_copy_branch(ntree, displacement_node, NULL, 0);
+ displacement_node = ntree_shader_copy_branch(ntree, displacement_node, nullptr, 0);
displacement_socket = ntree_shader_node_find_output(displacement_node,
displacement_socket->identifier);
nodeRemLink(ntree, displacement_link);
nodeAddLink(ntree, displacement_node, displacement_socket, tonode, tosock);
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
}
/* Re-link displacement output to unconnected normal sockets via bump node.
@@ -756,11 +746,11 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
nodeRemLink(ntree, displacement_link);
/* Convert displacement vector to bump height. */
- bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
- bNode *geo_node = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY);
+ bNode *dot_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_VECTOR_MATH);
+ bNode *geo_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_NEW_GEOMETRY);
bNodeSocket *normal_socket = ntree_shader_node_find_output(geo_node, "Normal");
- bNodeSocket *dot_input1 = dot_node->inputs.first;
- bNodeSocket *dot_input2 = dot_input1->next;
+ bNodeSocket *dot_input1 = static_cast<bNodeSocket *>(dot_node->inputs.first);
+ bNodeSocket *dot_input2 = static_cast<bNodeSocket *>(dot_input1->next);
dot_node->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT;
nodeAddLink(ntree, displacement_node, displacement_socket, dot_node, dot_input1);
@@ -771,11 +761,11 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
/* We can't connect displacement to normal directly, use bump node for that
* and hope that it gives good enough approximation.
*/
- bNode *bump_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BUMP);
+ bNode *bump_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_BUMP);
bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height");
bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal");
- BLI_assert(bump_input_socket != NULL);
- BLI_assert(bump_output_socket != NULL);
+ BLI_assert(bump_input_socket != nullptr);
+ BLI_assert(bump_output_socket != nullptr);
/* Connect bump node to where displacement output was originally
* connected to.
*/
@@ -786,12 +776,12 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
geo_node->tmp_flag = -2;
bump_node->tmp_flag = -2;
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
/* Connect all free-standing Normal inputs and relink geometry/coordinate nodes. */
ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket);
/* We modified the tree, it needs to be updated now. */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
}
static void node_tag_branch_as_derivative(bNode *node, int dx)
@@ -867,11 +857,11 @@ static bool ntree_tag_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *user
*/
void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tags)
{
- if (output_node == NULL) {
+ if (output_node == nullptr) {
return;
}
/* Make sure sockets links pointers are correct. */
- ntreeUpdateTree(G.main, ntree);
+ BKE_ntree_update_main_tree(G.main, ntree, nullptr);
nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags, 0);
}
@@ -889,7 +879,7 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
ntree_shader_groups_flatten(localtree);
- if (output == NULL) {
+ if (output == nullptr) {
/* Search again, now including flattened nodes. */
output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE);
}
@@ -905,19 +895,17 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
LISTBASE_FOREACH (bNode *, node, &localtree->nodes) {
if (node->type == SH_NODE_OUTPUT_AOV) {
nodeChainIterBackwards(localtree, node, ntree_shader_bump_branches, localtree, 0);
- nTreeTags tags = {
- .ssr_id = 1.0,
- .sss_id = 1.0,
- };
+ nTreeTags tags = {};
+ tags.ssr_id = 1.0;
+ tags.sss_id = 1.0;
ntree_shader_tag_nodes(localtree, node, &tags);
}
}
/* TODO(fclem): consider moving this to the gpu shader tree evaluation. */
- nTreeTags tags = {
- .ssr_id = 1.0,
- .sss_id = 1.0,
- };
+ nTreeTags tags = {};
+ tags.ssr_id = 1.0;
+ tags.sss_id = 1.0;
ntree_shader_tag_nodes(localtree, output, &tags);
exec = ntreeShaderBeginExecTree(localtree);
@@ -933,15 +921,15 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree,
*has_surface_output = false;
*has_volume_output = false;
- if (output != NULL) {
+ if (output != nullptr) {
bNodeSocket *surface_sock = ntree_shader_node_find_input(output, "Surface");
bNodeSocket *volume_sock = ntree_shader_node_find_input(output, "Volume");
- if (surface_sock != NULL) {
+ if (surface_sock != nullptr) {
*has_surface_output = (nodeCountSocketLinks(localtree, surface_sock) > 0);
}
- if (volume_sock != NULL) {
+ if (volume_sock != nullptr) {
*has_volume_output = (nodeCountSocketLinks(localtree, volume_sock) > 0);
}
}
@@ -951,19 +939,17 @@ bNodeTreeExec *ntreeShaderBeginExecTree_internal(bNodeExecContext *context,
bNodeTree *ntree,
bNodeInstanceKey parent_key)
{
- bNodeTreeExec *exec;
- bNode *node;
-
/* ensures only a single output node is enabled */
ntreeSetOutput(ntree);
/* common base initialization */
- exec = ntree_exec_begin(context, ntree, parent_key);
+ bNodeTreeExec *exec = ntree_exec_begin(context, ntree, parent_key);
/* allocate the thread stack listbase array */
- exec->threadstack = MEM_callocN(BLENDER_MAX_THREADS * sizeof(ListBase), "thread stack array");
+ exec->threadstack = static_cast<ListBase *>(
+ MEM_callocN(BLENDER_MAX_THREADS * sizeof(ListBase), "thread stack array"));
- for (node = exec->nodetree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &exec->nodetree->nodes) {
node->need_exec = 1;
}
@@ -996,12 +982,9 @@ bNodeTreeExec *ntreeShaderBeginExecTree(bNodeTree *ntree)
void ntreeShaderEndExecTree_internal(bNodeTreeExec *exec)
{
- bNodeThreadStack *nts;
- int a;
-
if (exec->threadstack) {
- for (a = 0; a < BLENDER_MAX_THREADS; a++) {
- for (nts = exec->threadstack[a].first; nts; nts = nts->next) {
+ for (int a = 0; a < BLENDER_MAX_THREADS; a++) {
+ LISTBASE_FOREACH (bNodeThreadStack *, nts, &exec->threadstack[a]) {
if (nts->stack) {
MEM_freeN(nts->stack);
}
@@ -1010,7 +993,7 @@ void ntreeShaderEndExecTree_internal(bNodeTreeExec *exec)
}
MEM_freeN(exec->threadstack);
- exec->threadstack = NULL;
+ exec->threadstack = nullptr;
}
ntree_exec_end(exec);
@@ -1024,6 +1007,6 @@ void ntreeShaderEndExecTree(bNodeTreeExec *exec)
ntreeShaderEndExecTree_internal(exec);
/* XXX clear nodetree backpointer to exec data, same problem as noted in ntreeBeginExecTree */
- ntree->execdata = NULL;
+ ntree->execdata = nullptr;
}
}
diff --git a/source/blender/nodes/shader/node_shader_util.cc b/source/blender/nodes/shader/node_shader_util.cc
index f2464d4c1b4..722daa1e4f9 100644
--- a/source/blender/nodes/shader/node_shader_util.cc
+++ b/source/blender/nodes/shader/node_shader_util.cc
@@ -23,7 +23,7 @@
#include "DNA_node_types.h"
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
#include "NOD_socket_search_link.hh"
@@ -49,19 +49,18 @@ static bool sh_fn_poll_default(bNodeType *UNUSED(ntype),
return true;
}
-void sh_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = sh_node_poll_default;
ntype->insert_link = node_insert_link_default;
ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
-void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
{
- sh_node_type_base(ntype, type, name, nclass, flag);
+ sh_node_type_base(ntype, type, name, nclass);
ntype->poll = sh_fn_poll_default;
ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node;
}
diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.hh
index c647b86a19a..e66ab9c285b 100644
--- a/source/blender/nodes/shader/node_shader_util.h
+++ b/source/blender/nodes/shader/node_shader_util.hh
@@ -23,29 +23,21 @@
#pragma once
-#include <float.h>
-#include <math.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_ID.h"
-#include "DNA_color_types.h"
-#include "DNA_customdata_types.h"
-#include "DNA_image_types.h"
-#include "DNA_material_types.h"
-#include "DNA_node_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_texture_types.h"
+#include <cfloat>
+#include <cmath>
+#include <cstring>
#include "BLI_blenlib.h"
+#include "BLI_color.hh"
+#include "BLI_float3.hh"
#include "BLI_math.h"
#include "BLI_math_base_safe.h"
#include "BLI_rand.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLT_translation.h"
+
#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_global.h"
@@ -55,51 +47,51 @@
#include "BKE_node.h"
#include "BKE_texture.h"
-#include "NOD_shader.h"
-#include "node_util.h"
-
-#include "BLT_translation.h"
-
-#include "IMB_colormanagement.h"
+#include "DNA_ID.h"
+#include "DNA_color_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_image_types.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
-#include "RE_pipeline.h"
-#include "RE_texture.h"
+#include "FN_multi_function_builder.hh"
#include "GPU_material.h"
#include "GPU_texture.h"
#include "GPU_uniform_buffer.h"
-#ifdef __cplusplus
-# include "FN_multi_function_builder.hh"
+#include "IMB_colormanagement.h"
-# include "NOD_multi_function.hh"
-# include "NOD_socket_declarations.hh"
+#include "MEM_guardedalloc.h"
-# include "BLI_color.hh"
-# include "BLI_float3.hh"
+#include "NOD_multi_function.hh"
+#include "NOD_shader.h"
+#include "NOD_socket_declarations.hh"
+#include "node_util.h"
-extern "C" {
-#endif
+#include "RE_pipeline.h"
+#include "RE_texture.h"
bool sh_node_poll_default(struct bNodeType *ntype,
struct bNodeTree *ntree,
const char **r_disabled_hint);
-void sh_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
-void sh_fn_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
+void sh_fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
/* ********* exec data struct, remains internal *********** */
-typedef struct ShaderCallData {
+struct ShaderCallData {
/* Empty for now, may be reused if we convert shader to texture nodes. */
int dummy;
-} ShaderCallData;
+};
-typedef struct XYZ_to_RGB /* Transposed #imbuf_xyz_to_rgb, passed as 3x vec3. */
+struct XYZ_to_RGB /* Transposed #imbuf_xyz_to_rgb, passed as 3x vec3. */
{
float r[3], g[3], b[3];
-} XYZ_to_RGB;
+};
void nodestack_get_vec(float *in, short type_in, bNodeStack *ns);
@@ -120,7 +112,3 @@ void ntreeExecGPUNodes(struct bNodeTreeExec *exec,
struct GPUMaterial *mat,
struct bNode *output_node);
void get_XYZ_to_RGB_for_gpu(XYZ_to_RGB *data);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/nodes/shader/nodes/node_shader_add_shader.c b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc
index 12c138ac9d5..73d5c12ce96 100644
--- a/source/blender/nodes/shader/nodes/node_shader_add_shader.c
+++ b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc
@@ -17,20 +17,16 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_add_shader_cc {
-static bNodeSocketTemplate sh_node_add_shader_in[] = {
- {SOCK_SHADER, N_("Shader")},
- {SOCK_SHADER, N_("Shader")},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_add_shader_out[] = {
- {SOCK_SHADER, N_("Shader")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Shader>(N_("Shader"));
+ b.add_input<decl::Shader>(N_("Shader"), "Shader_001");
+ b.add_output<decl::Shader>(N_("Shader"));
+}
static int node_shader_gpu_add_shader(GPUMaterial *mat,
bNode *node,
@@ -41,16 +37,18 @@ static int node_shader_gpu_add_shader(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_add_shader", in, out);
}
+} // namespace blender::nodes::node_shader_add_shader_cc
+
/* node type definition */
-void register_node_type_sh_add_shader(void)
+void register_node_type_sh_add_shader()
{
+ namespace file_ns = blender::nodes::node_shader_add_shader_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_ADD_SHADER, "Add Shader", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_add_shader_in, sh_node_add_shader_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_add_shader);
+ sh_node_type_base(&ntype, SH_NODE_ADD_SHADER, "Add Shader", NODE_CLASS_SHADER);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_add_shader);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc
index abe80ebcefb..73f0e515a46 100644
--- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c
+++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc
@@ -17,22 +17,18 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** OUTPUT ******************** */
+namespace blender::nodes::node_shader_ambient_occlusion_cc {
-static bNodeSocketTemplate sh_node_ambient_occlusion_in[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""},
-};
-
-static bNodeSocketTemplate sh_node_ambient_occlusion_out[] = {
- {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
- {SOCK_FLOAT, N_("AO"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
+ b.add_input<decl::Float>(N_("Distance")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Vector>(N_("Normal")).min(-1.0f).max(1.0f).hide_value();
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("AO"));
+}
static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat,
bNode *node,
@@ -64,16 +60,19 @@ static void node_shader_init_ambient_occlusion(bNodeTree *UNUSED(ntree), bNode *
node->custom2 = 0;
}
+} // namespace blender::nodes::node_shader_ambient_occlusion_cc
+
/* node type definition */
-void register_node_type_sh_ambient_occlusion(void)
+void register_node_type_sh_ambient_occlusion()
{
+ namespace file_ns = blender::nodes::node_shader_ambient_occlusion_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_AMBIENT_OCCLUSION, "Ambient Occlusion", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_ambient_occlusion_in, sh_node_ambient_occlusion_out);
- node_type_init(&ntype, node_shader_init_ambient_occlusion);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_ambient_occlusion);
+ sh_node_type_base(&ntype, SH_NODE_AMBIENT_OCCLUSION, "Ambient Occlusion", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_ambient_occlusion);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_ambient_occlusion);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.cc
index 9b3122e38e0..780d0a72ef8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_attribute.c
+++ b/source/blender/nodes/shader/nodes/node_shader_attribute.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_attribute_cc {
/* **************** OUTPUT ******************** */
@@ -31,7 +33,7 @@ static bNodeSocketTemplate sh_node_attribute_out[] = {
static void node_shader_init_attribute(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderAttribute *attr = MEM_callocN(sizeof(NodeShaderAttribute), "NodeShaderAttribute");
+ NodeShaderAttribute *attr = MEM_cnew<NodeShaderAttribute>("NodeShaderAttribute");
node->storage = attr;
}
@@ -41,7 +43,7 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- NodeShaderAttribute *attr = node->storage;
+ NodeShaderAttribute *attr = static_cast<NodeShaderAttribute *>(node->storage);
bool is_varying = attr->type == SHD_ATTRIBUTE_GEOMETRY;
if (GPU_material_is_volume_shader(mat) && is_varying) {
@@ -81,17 +83,21 @@ static int node_shader_gpu_attribute(GPUMaterial *mat,
return 1;
}
+} // namespace blender::nodes::node_shader_attribute_cc
+
/* node type definition */
-void register_node_type_sh_attribute(void)
+void register_node_type_sh_attribute()
{
+ namespace file_ns = blender::nodes::node_shader_attribute_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_ATTRIBUTE, "Attribute", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_attribute_out);
- node_type_init(&ntype, node_shader_init_attribute);
+ sh_node_type_base(&ntype, SH_NODE_ATTRIBUTE, "Attribute", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_attribute_out);
+ node_type_init(&ntype, file_ns::node_shader_init_attribute);
node_type_storage(
&ntype, "NodeShaderAttribute", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_attribute);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_attribute);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_background.c b/source/blender/nodes/shader/nodes/node_shader_background.cc
index 5281a9fecb1..39858e36fd1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_background.c
+++ b/source/blender/nodes/shader/nodes/node_shader_background.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_background_cc {
/* **************** OUTPUT ******************** */
@@ -41,16 +43,19 @@ static int node_shader_gpu_background(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_background", in, out);
}
+} // namespace blender::nodes::node_shader_background_cc
+
/* node type definition */
-void register_node_type_sh_background(void)
+void register_node_type_sh_background()
{
+ namespace file_ns = blender::nodes::node_shader_background_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BACKGROUND, "Background", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_background_in, sh_node_background_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_background);
+ sh_node_type_base(&ntype, SH_NODE_BACKGROUND, "Background", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_background_in, file_ns::sh_node_background_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_background);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bevel.c b/source/blender/nodes/shader/nodes/node_shader_bevel.cc
index 347d82c5506..a3063358556 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bevel.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bevel.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_bevel_cc {
/* **************** OUTPUT ******************** */
@@ -54,16 +56,19 @@ static int gpu_shader_bevel(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bevel", in, out);
}
+} // namespace blender::nodes::node_shader_bevel_cc
+
/* node type definition */
-void register_node_type_sh_bevel(void)
+void register_node_type_sh_bevel()
{
+ namespace file_ns = blender::nodes::node_shader_bevel_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BEVEL, "Bevel", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_bevel_in, sh_node_bevel_out);
- node_type_init(&ntype, node_shader_init_bevel);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_bevel);
+ sh_node_type_base(&ntype, SH_NODE_BEVEL, "Bevel", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, file_ns::sh_node_bevel_in, file_ns::sh_node_bevel_out);
+ node_type_init(&ntype, file_ns::node_shader_init_bevel);
+ node_type_gpu(&ntype, file_ns::gpu_shader_bevel);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_blackbody.c b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc
index 95c35affc27..85e2ed08403 100644
--- a/source/blender/nodes/shader/nodes/node_shader_blackbody.c
+++ b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc
@@ -17,18 +17,15 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Blackbody ******************** */
-static bNodeSocketTemplate sh_node_blackbody_in[] = {
- {SOCK_FLOAT, N_("Temperature"), 1500.0f, 0.0f, 0.0f, 0.0f, 800.0f, 12000.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_blackbody_cc {
-static bNodeSocketTemplate sh_node_blackbody_out[] = {
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Temperature")).default_value(1500.0f).min(800.0f).max(12000.0f);
+ b.add_output<decl::Color>(N_("Color"));
+}
static int node_shader_gpu_blackbody(GPUMaterial *mat,
bNode *node,
@@ -37,7 +34,7 @@ static int node_shader_gpu_blackbody(GPUMaterial *mat,
GPUNodeStack *out)
{
const int size = CM_TABLE + 1;
- float *data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
+ float *data = static_cast<float *>(MEM_mallocN(sizeof(float) * size * 4, "blackbody texture"));
blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
@@ -47,17 +44,19 @@ static int node_shader_gpu_blackbody(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_blackbody", in, out, ramp_texture, GPU_constant(&layer));
}
+} // namespace blender::nodes::node_shader_blackbody_cc
+
/* node type definition */
-void register_node_type_sh_blackbody(void)
+void register_node_type_sh_blackbody()
{
+ namespace file_ns = blender::nodes::node_shader_blackbody_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BLACKBODY, "Blackbody", NODE_CLASS_CONVERTER, 0);
+ sh_node_type_base(&ntype, SH_NODE_BLACKBODY, "Blackbody", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_socket_templates(&ntype, sh_node_blackbody_in, sh_node_blackbody_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_blackbody);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_blackbody);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.cc
index 4f375c666de..e6328c4972a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_brightness.c
+++ b/source/blender/nodes/shader/nodes/node_shader_brightness.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_brightness_cc {
/* **************** Bright and contrast ******************** */
@@ -42,15 +44,18 @@ static int gpu_shader_brightcontrast(GPUMaterial *mat,
return GPU_stack_link(mat, node, "brightness_contrast", in, out);
}
-void register_node_type_sh_brightcontrast(void)
+} // namespace blender::nodes::node_shader_brightness_cc
+
+void register_node_type_sh_brightcontrast()
{
+ namespace file_ns = blender::nodes::node_shader_brightness_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_brightcontrast_in, sh_node_brightcontrast_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_brightcontrast);
+ sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_brightcontrast_in, file_ns::sh_node_brightcontrast_out);
+ node_type_gpu(&ntype, file_ns::gpu_shader_brightcontrast);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc
index 499f62da683..2e698aeb4d7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_bsdf_anisotropic_cc {
/* **************** OUTPUT ******************** */
@@ -64,17 +66,21 @@ static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat,
GPU_constant(&node->ssr_id));
}
+} // namespace blender::nodes::node_shader_bsdf_anisotropic_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_anisotropic(void)
+void register_node_type_sh_bsdf_anisotropic()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_anisotropic_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_ANISOTROPIC, "Anisotropic BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_anisotropic_in, sh_node_bsdf_anisotropic_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_ANISOTROPIC, "Anisotropic BSDF", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_bsdf_anisotropic_in, file_ns::sh_node_bsdf_anisotropic_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_anisotropic);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_anisotropic);
+ node_type_init(&ntype, file_ns::node_shader_init_anisotropic);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_anisotropic);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc
index f4f1d274826..3719227f46c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_bsdf_diffuse_cc {
/* **************** OUTPUT ******************** */
@@ -48,17 +50,20 @@ static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_diffuse", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_diffuse_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_diffuse(void)
+void register_node_type_sh_bsdf_diffuse()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_diffuse_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_DIFFUSE, "Diffuse BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_diffuse_in, sh_node_bsdf_diffuse_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_DIFFUSE, "Diffuse BSDF", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_bsdf_diffuse_in, file_ns::sh_node_bsdf_diffuse_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_diffuse);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_diffuse);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc
index 5fc946e3509..2cea42146fd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_bsdf_glass_cc {
/* **************** OUTPUT ******************** */
@@ -53,7 +55,7 @@ static int node_shader_gpu_bsdf_glass(GPUMaterial *mat,
GPU_link(mat, "set_value_zero", &in[1].link);
}
- GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT);
+ GPU_material_flag_set(mat, (eGPUMatFlag)(GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT));
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
@@ -66,17 +68,21 @@ static int node_shader_gpu_bsdf_glass(GPUMaterial *mat,
GPU_constant(&node->ssr_id));
}
+} // namespace blender::nodes::node_shader_bsdf_glass_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_glass(void)
+void register_node_type_sh_bsdf_glass()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_glass_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_GLASS, "Glass BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_glass_in, sh_node_bsdf_glass_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_GLASS, "Glass BSDF", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_bsdf_glass_in, file_ns::sh_node_bsdf_glass_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_glass);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_glass);
+ node_type_init(&ntype, file_ns::node_shader_init_glass);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_glass);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc
index 13b1b21c7fc..1227d79af93 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_bsdf_glossy_cc {
/* **************** OUTPUT ******************** */
@@ -65,17 +67,21 @@ static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat,
GPU_constant(&node->ssr_id));
}
+} // namespace blender::nodes::node_shader_bsdf_glossy_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_glossy(void)
+void register_node_type_sh_bsdf_glossy()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_glossy_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_GLOSSY, "Glossy BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_glossy_in, sh_node_bsdf_glossy_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_GLOSSY, "Glossy BSDF", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_bsdf_glossy_in, file_ns::sh_node_bsdf_glossy_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_glossy);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_glossy);
+ node_type_init(&ntype, file_ns::node_shader_init_glossy);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_glossy);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc
index fb2decec5f4..56282d1c991 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_bsdf_hair_cc {
/* **************** OUTPUT ******************** */
@@ -44,17 +46,20 @@ static int node_shader_gpu_bsdf_hair(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_hair", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_hair_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_hair(void)
+void register_node_type_sh_bsdf_hair()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_hair_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR, "Hair BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_hair_in, sh_node_bsdf_hair_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR, "Hair BSDF", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_bsdf_hair_in, file_ns::sh_node_bsdf_hair_out);
node_type_size(&ntype, 150, 60, 200);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_hair);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_hair);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc
index d2b40a7ec39..16d48144578 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_bsdf_hair_principled_cc {
/* **************** OUTPUT ******************** */
@@ -61,10 +63,9 @@ static void node_shader_init_hair_principled(bNodeTree *UNUSED(ntree), bNode *no
/* Triggers (in)visibility of some sockets when changing Parametrization. */
static void node_shader_update_hair_principled(bNodeTree *ntree, bNode *node)
{
- bNodeSocket *sock;
int parametrization = node->custom1;
- for (sock = node->inputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (STREQ(sock->name, "Color")) {
nodeSetSocketAvailability(ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_REFLECTANCE);
}
@@ -91,19 +92,22 @@ static void node_shader_update_hair_principled(bNodeTree *ntree, bNode *node)
}
}
+} // namespace blender::nodes::node_shader_bsdf_hair_principled_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_hair_principled(void)
+void register_node_type_sh_bsdf_hair_principled()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_hair_principled_cc;
+
static bNodeType ntype;
sh_node_type_base(
- &ntype, SH_NODE_BSDF_HAIR_PRINCIPLED, "Principled Hair BSDF", NODE_CLASS_SHADER, 0);
+ &ntype, SH_NODE_BSDF_HAIR_PRINCIPLED, "Principled Hair BSDF", NODE_CLASS_SHADER);
node_type_socket_templates(
- &ntype, sh_node_bsdf_hair_principled_in, sh_node_bsdf_hair_principled_out);
+ &ntype, file_ns::sh_node_bsdf_hair_principled_in, file_ns::sh_node_bsdf_hair_principled_out);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_init(&ntype, node_shader_init_hair_principled);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_update(&ntype, node_shader_update_hair_principled);
+ node_type_init(&ntype, file_ns::node_shader_init_hair_principled);
+ node_type_update(&ntype, file_ns::node_shader_update_hair_principled);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc
index b9f4106c79a..72b2c278635 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_bsdf_principled_cc {
/* **************** OUTPUT ******************** */
@@ -122,8 +124,8 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
/* SSS Profile */
if (use_subsurf) {
- bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
- bNodeSocketValueRGBA *socket_data = socket->default_value;
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2);
+ bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value;
/* For some reason it seems that the socket value is in ARGB format. */
GPU_material_sss_profile_create(mat, &socket_data->value[1]);
}
@@ -151,7 +153,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat,
float f_use_refraction = use_refract ? 1.0f : 0.0f;
float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f;
- GPU_material_flag_set(mat, flag);
+ GPU_material_flag_set(mat, (eGPUMatFlag)flag);
return GPU_stack_link(mat,
node,
@@ -172,7 +174,7 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
const int distribution = node->custom1;
const int sss_method = node->custom2;
- for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (STREQ(sock->name, "Transmission Roughness")) {
nodeSetSocketAvailability(ntree, sock, distribution == SHD_GLOSSY_GGX);
}
@@ -183,18 +185,22 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node)
}
}
+} // namespace blender::nodes::node_shader_bsdf_principled_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_principled(void)
+void register_node_type_sh_bsdf_principled()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_principled_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_principled_in, sh_node_bsdf_principled_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_bsdf_principled_in, file_ns::sh_node_bsdf_principled_out);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_init(&ntype, node_shader_init_principled);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_principled);
- node_type_update(&ntype, node_shader_update_principled);
+ node_type_init(&ntype, file_ns::node_shader_init_principled);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_principled);
+ node_type_update(&ntype, file_ns::node_shader_update_principled);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc
index ff33b3456db..63bca201898 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_bsdf_refraction_cc {
/* **************** OUTPUT ******************** */
@@ -58,17 +60,21 @@ static int node_shader_gpu_bsdf_refraction(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_refraction", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_refraction_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_refraction(void)
+void register_node_type_sh_bsdf_refraction()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_refraction_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_REFRACTION, "Refraction BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_refraction_in, sh_node_bsdf_refraction_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_REFRACTION, "Refraction BSDF", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_bsdf_refraction_in, file_ns::sh_node_bsdf_refraction_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_refraction);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_refraction);
+ node_type_init(&ntype, file_ns::node_shader_init_refraction);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_refraction);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc
index 2d04fcee40c..270288c3ce0 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_bsdf_toon_cc {
/* **************** OUTPUT ******************** */
@@ -49,17 +51,20 @@ static int node_shader_gpu_bsdf_toon(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_toon", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_toon_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_toon(void)
+void register_node_type_sh_bsdf_toon()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_toon_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_TOON, "Toon BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_toon_in, sh_node_bsdf_toon_out);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_TOON, "Toon BSDF", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_bsdf_toon_in, file_ns::sh_node_bsdf_toon_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_toon);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_toon);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc
index d2e1a276645..421c7c16032 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_bsdf_translucent_cc {
/* **************** OUTPUT ******************** */
@@ -47,16 +49,19 @@ static int node_shader_gpu_bsdf_translucent(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_translucent", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_translucent_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_translucent(void)
+void register_node_type_sh_bsdf_translucent()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_translucent_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSLUCENT, "Translucent BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_translucent_in, sh_node_bsdf_translucent_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_translucent);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSLUCENT, "Translucent BSDF", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_bsdf_translucent_in, file_ns::sh_node_bsdf_translucent_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_translucent);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc
index 45f8ebf1d52..d1dc1856863 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_bsdf_transparent_cc {
/* **************** OUTPUT ******************** */
@@ -40,16 +42,19 @@ static int node_shader_gpu_bsdf_transparent(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_transparent", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_transparent_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_transparent(void)
+void register_node_type_sh_bsdf_transparent()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_transparent_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSPARENT, "Transparent BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_transparent_in, sh_node_bsdf_transparent_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_transparent);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSPARENT, "Transparent BSDF", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_bsdf_transparent_in, file_ns::sh_node_bsdf_transparent_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_transparent);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc
index 59e8bbd3c63..6293f38d792 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_bsdf_velvet_cc {
/* **************** OUTPUT ******************** */
@@ -48,16 +50,19 @@ static int node_shader_gpu_bsdf_velvet(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_bsdf_velvet", in, out);
}
+} // namespace blender::nodes::node_shader_bsdf_velvet_cc
+
/* node type definition */
-void register_node_type_sh_bsdf_velvet(void)
+void register_node_type_sh_bsdf_velvet()
{
+ namespace file_ns = blender::nodes::node_shader_bsdf_velvet_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BSDF_VELVET, "Velvet BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_bsdf_velvet_in, sh_node_bsdf_velvet_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_bsdf_velvet);
+ sh_node_type_base(&ntype, SH_NODE_BSDF_VELVET, "Velvet BSDF", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_bsdf_velvet_in, file_ns::sh_node_bsdf_velvet_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_velvet);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.cc
index 7444ea3952a..7718b21af52 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bump.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bump.cc
@@ -21,22 +21,30 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
/* **************** BUMP ******************** */
-/* clang-format off */
-static bNodeSocketTemplate sh_node_bump_in[] = {
- {SOCK_FLOAT, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_FLOAT, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_FLOAT, N_("Height"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {SOCK_FLOAT, N_("Height_dx"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_UNAVAIL},
- {SOCK_FLOAT, N_("Height_dy"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_UNAVAIL},
- {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
- {-1, ""}
-};
-/* clang-format on */
-static bNodeSocketTemplate sh_node_bump_out[] = {{SOCK_VECTOR, "Normal"}, {-1, ""}};
+namespace blender::nodes::node_shader_bump_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Strength"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .subtype(PROP_FACTOR);
+ b.add_input<decl::Float>(N_("Distance")).default_value(1.0f).min(0.0f).max(1000.0f);
+ b.add_input<decl::Float>(N_("Height"))
+ .default_value(1.0f)
+ .min(-1000.0f)
+ .max(1000.0f)
+ .hide_value();
+ b.add_input<decl::Float>(N_("Height_dx")).default_value(1.0f).unavailable();
+ b.add_input<decl::Float>(N_("Height_dy")).default_value(1.0f).unavailable();
+ b.add_input<decl::Vector>(N_("Normal")).min(-1.0f).max(1.0f).hide_value();
+ b.add_output<decl::Vector>(N_("Normal"));
+}
static int gpu_shader_bump(GPUMaterial *mat,
bNode *node,
@@ -54,15 +62,18 @@ static int gpu_shader_bump(GPUMaterial *mat,
mat, node, "node_bump", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_constant(&invert));
}
+} // namespace blender::nodes::node_shader_bump_cc
+
/* node type definition */
-void register_node_type_sh_bump(void)
+void register_node_type_sh_bump()
{
+ namespace file_ns = blender::nodes::node_shader_bump_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_BUMP, "Bump", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_bump_in, sh_node_bump_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_bump);
+ sh_node_type_base(&ntype, SH_NODE_BUMP, "Bump", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_bump);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.c b/source/blender/nodes/shader/nodes/node_shader_camera.cc
index 5148104700a..ab8a98f47fd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_camera.c
+++ b/source/blender/nodes/shader/nodes/node_shader_camera.cc
@@ -21,7 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_camera_cc {
/* **************** CAMERA INFO ******************** */
static bNodeSocketTemplate sh_node_camera_out[] = {
@@ -44,14 +46,17 @@ static int gpu_shader_camera(GPUMaterial *mat,
return GPU_stack_link(mat, node, "camera", in, out, viewvec);
}
-void register_node_type_sh_camera(void)
+} // namespace blender::nodes::node_shader_camera_cc
+
+void register_node_type_sh_camera()
{
+ namespace file_ns = blender::nodes::node_shader_camera_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_CAMERA, "Camera Data", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_camera_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_camera);
+ sh_node_type_base(&ntype, SH_NODE_CAMERA, "Camera Data", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_camera_out);
+ node_type_gpu(&ntype, file_ns::gpu_shader_camera);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
index 6c3457151e5..f4c72f0616f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc
@@ -21,21 +21,19 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_clamp_cc {
static void sh_node_clamp_declare(NodeDeclarationBuilder &b)
{
b.is_function_node();
- b.add_input<decl::Float>(N_("Value")).min(0.0f).max(1.0f).default_value(1.0f);
+ b.add_input<decl::Float>(N_("Value")).default_value(1.0f);
b.add_input<decl::Float>(N_("Min")).default_value(0.0f).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_output<decl::Float>(N_("Result"));
};
-} // namespace blender::nodes
-
static void node_shader_init_clamp(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = NODE_CLAMP_MINMAX; /* clamp type */
@@ -75,15 +73,19 @@ static void sh_node_clamp_build_multi_function(blender::nodes::NodeMultiFunction
}
}
+} // namespace blender::nodes::node_shader_clamp_cc
+
void register_node_type_sh_clamp()
{
+ namespace file_ns = blender::nodes::node_shader_clamp_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_clamp_declare;
- node_type_init(&ntype, node_shader_init_clamp);
- node_type_gpu(&ntype, gpu_shader_clamp);
- ntype.build_multi_function = sh_node_clamp_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_clamp_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_clamp);
+ node_type_gpu(&ntype, file_ns::gpu_shader_clamp);
+ ntype.build_multi_function = file_ns::sh_node_clamp_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc
new file mode 100644
index 00000000000..ff43885741b
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc
@@ -0,0 +1,189 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "DNA_texture_types.h"
+
+#include "BLI_color.hh"
+
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_color_ramp_cc {
+
+static void sh_node_valtorgb_declare(NodeDeclarationBuilder &b)
+{
+ b.is_function_node();
+ b.add_input<decl::Float>(N_("Fac")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
+ b.add_output<decl::Color>(N_("Color"));
+ b.add_output<decl::Float>(N_("Alpha"));
+};
+
+static void node_shader_exec_valtorgb(void *UNUSED(data),
+ int UNUSED(thread),
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ bNodeStack **in,
+ bNodeStack **out)
+{
+ /* stack order in: fac */
+ /* stack order out: col, alpha */
+
+ if (node->storage) {
+ float fac;
+ nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
+
+ BKE_colorband_evaluate((ColorBand *)node->storage, fac, out[0]->vec);
+ out[1]->vec[0] = out[0]->vec[3];
+ }
+}
+
+static void node_shader_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->storage = BKE_colorband_add(true);
+}
+
+static int gpu_shader_valtorgb(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ struct ColorBand *coba = (ColorBand *)node->storage;
+ float *array, layer;
+ int size;
+
+ /* Common / easy case optimization. */
+ if ((coba->tot <= 2) && (coba->color_mode == COLBAND_BLEND_RGB)) {
+ float mul_bias[2];
+ switch (coba->ipotype) {
+ case COLBAND_INTERP_LINEAR:
+ mul_bias[0] = 1.0f / (coba->data[1].pos - coba->data[0].pos);
+ mul_bias[1] = -mul_bias[0] * coba->data[0].pos;
+ return GPU_stack_link(mat,
+ node,
+ "valtorgb_opti_linear",
+ in,
+ out,
+ GPU_uniform(mul_bias),
+ GPU_uniform(&coba->data[0].r),
+ GPU_uniform(&coba->data[1].r));
+ case COLBAND_INTERP_CONSTANT:
+ mul_bias[1] = max_ff(coba->data[0].pos, coba->data[1].pos);
+ return GPU_stack_link(mat,
+ node,
+ "valtorgb_opti_constant",
+ in,
+ out,
+ GPU_uniform(&mul_bias[1]),
+ GPU_uniform(&coba->data[0].r),
+ GPU_uniform(&coba->data[1].r));
+ case COLBAND_INTERP_EASE:
+ mul_bias[0] = 1.0f / (coba->data[1].pos - coba->data[0].pos);
+ mul_bias[1] = -mul_bias[0] * coba->data[0].pos;
+ return GPU_stack_link(mat,
+ node,
+ "valtorgb_opti_ease",
+ in,
+ out,
+ GPU_uniform(mul_bias),
+ GPU_uniform(&coba->data[0].r),
+ GPU_uniform(&coba->data[1].r));
+ default:
+ break;
+ }
+ }
+
+ BKE_colorband_evaluate_table_rgba(coba, &array, &size);
+ GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
+
+ if (coba->ipotype == COLBAND_INTERP_CONSTANT) {
+ return GPU_stack_link(mat, node, "valtorgb_nearest", in, out, tex, GPU_constant(&layer));
+ }
+
+ return GPU_stack_link(mat, node, "valtorgb", in, out, tex, GPU_constant(&layer));
+}
+
+class ColorBandFunction : public blender::fn::MultiFunction {
+ private:
+ const ColorBand &color_band_;
+
+ public:
+ ColorBandFunction(const ColorBand &color_band) : color_band_(color_band)
+ {
+ static blender::fn::MFSignature signature = create_signature();
+ this->set_signature(&signature);
+ }
+
+ static blender::fn::MFSignature create_signature()
+ {
+ blender::fn::MFSignatureBuilder signature{"Color Band"};
+ signature.single_input<float>("Value");
+ signature.single_output<blender::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
+ {
+ 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");
+
+ for (int64_t i : mask) {
+ blender::ColorGeometry4f color;
+ BKE_colorband_evaluate(&color_band_, values[i], color);
+ colors[i] = color;
+ alphas[i] = color.a;
+ }
+ }
+};
+
+static void sh_node_valtorgb_build_multi_function(
+ blender::nodes::NodeMultiFunctionBuilder &builder)
+{
+ bNode &bnode = builder.node();
+ const ColorBand *color_band = (const ColorBand *)bnode.storage;
+ builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band);
+}
+
+} // namespace blender::nodes::node_shader_color_ramp_cc
+
+void register_node_type_sh_valtorgb()
+{
+ namespace file_ns = blender::nodes::node_shader_color_ramp_cc;
+
+ static bNodeType ntype;
+
+ sh_fn_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_valtorgb_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_valtorgb);
+ node_type_size_preset(&ntype, NODE_SIZE_LARGE);
+ node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage);
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_valtorgb);
+ node_type_gpu(&ntype, file_ns::gpu_shader_valtorgb);
+ ntype.build_multi_function = file_ns::sh_node_valtorgb_build_multi_function;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.cc
index 190e0cfad4c..b5c908c410b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_common.c
+++ b/source/blender/nodes/shader/nodes/node_shader_common.cc
@@ -31,7 +31,7 @@
#include "NOD_common.h"
#include "node_common.h"
#include "node_exec.h"
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
#include "RNA_access.h"
@@ -55,7 +55,7 @@ static void move_stack(bNodeStack *to, bNodeStack *from)
to->datatype = from->datatype;
to->is_copy = from->is_copy;
- from->data = NULL;
+ from->data = nullptr;
from->is_copy = 0;
}
}
@@ -68,7 +68,7 @@ static void *group_initexec(bNodeExecContext *context, bNode *node, bNodeInstanc
bNodeTreeExec *exec;
if (!ngroup) {
- return NULL;
+ return nullptr;
}
/* initialize the internal node tree execution */
@@ -91,15 +91,12 @@ static void group_freeexec(void *nodedata)
static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack)
{
bNodeTree *ngroup = (bNodeTree *)gnode->id;
- bNode *node;
- bNodeSocket *sock;
- bNodeStack *ns;
- int a;
- for (node = ngroup->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
if (node->type == NODE_GROUP_INPUT) {
- for (sock = node->outputs.first, a = 0; sock; sock = sock->next, a++) {
- ns = node_get_socket_stack(gstack, sock);
+ int a;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, a) {
+ bNodeStack *ns = node_get_socket_stack(gstack, sock);
if (ns) {
copy_stack(ns, in[a]);
}
@@ -113,15 +110,12 @@ static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack)
static void group_move_outputs(bNode *gnode, bNodeStack **out, bNodeStack *gstack)
{
bNodeTree *ngroup = (bNodeTree *)gnode->id;
- bNode *node;
- bNodeSocket *sock;
- bNodeStack *ns;
- int a;
- for (node = ngroup->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
- for (sock = node->inputs.first, a = 0; sock; sock = sock->next, a++) {
- ns = node_get_socket_stack(gstack, sock);
+ int a;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->inputs, a) {
+ bNodeStack *ns = node_get_socket_stack(gstack, sock);
if (ns) {
move_stack(out[a], ns);
}
@@ -138,8 +132,7 @@ static void group_execute(void *data,
struct bNodeStack **in,
struct bNodeStack **out)
{
- bNodeTreeExec *exec = execdata->data;
- bNodeThreadStack *nts;
+ bNodeTreeExec *exec = static_cast<bNodeTreeExec *>(execdata->data);
if (!exec) {
return;
@@ -149,13 +142,12 @@ static void group_execute(void *data,
* it's stupid, but just makes it work. compo redesign will do this better.
*/
{
- bNode *inode;
- for (inode = exec->nodetree->nodes.first; inode; inode = inode->next) {
+ LISTBASE_FOREACH (bNode *, inode, &exec->nodetree->nodes) {
inode->need_exec = 1;
}
}
- nts = ntreeGetThreadStack(exec, thread);
+ bNodeThreadStack *nts = ntreeGetThreadStack(exec, thread);
group_copy_inputs(node, in, nts->stack);
ntreeExecThreadNodes(exec, nts, data, thread);
@@ -167,15 +159,12 @@ static void group_execute(void *data,
static void group_gpu_copy_inputs(bNode *gnode, GPUNodeStack *in, bNodeStack *gstack)
{
bNodeTree *ngroup = (bNodeTree *)gnode->id;
- bNode *node;
- bNodeSocket *sock;
- bNodeStack *ns;
- int a;
- for (node = ngroup->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
if (node->type == NODE_GROUP_INPUT) {
- for (sock = node->outputs.first, a = 0; sock; sock = sock->next, a++) {
- ns = node_get_socket_stack(gstack, sock);
+ int a;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, a) {
+ bNodeStack *ns = node_get_socket_stack(gstack, sock);
if (ns) {
/* convert the external gpu stack back to internal node stack data */
node_data_from_gpu_stack(ns, &in[a]);
@@ -190,15 +179,12 @@ static void group_gpu_copy_inputs(bNode *gnode, GPUNodeStack *in, bNodeStack *gs
static void group_gpu_move_outputs(bNode *gnode, GPUNodeStack *out, bNodeStack *gstack)
{
bNodeTree *ngroup = (bNodeTree *)gnode->id;
- bNode *node;
- bNodeSocket *sock;
- bNodeStack *ns;
- int a;
- for (node = ngroup->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) {
if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) {
- for (sock = node->inputs.first, a = 0; sock; sock = sock->next, a++) {
- ns = node_get_socket_stack(gstack, sock);
+ int a;
+ LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->inputs, a) {
+ bNodeStack *ns = node_get_socket_stack(gstack, sock);
if (ns) {
/* convert the node stack data result back to gpu stack */
node_gpu_stack_from_data(&out[a], sock->type, ns);
@@ -212,36 +198,36 @@ static void group_gpu_move_outputs(bNode *gnode, GPUNodeStack *out, bNodeStack *
static int gpu_group_execute(
GPUMaterial *mat, bNode *node, bNodeExecData *execdata, GPUNodeStack *in, GPUNodeStack *out)
{
- bNodeTreeExec *exec = execdata->data;
+ bNodeTreeExec *exec = static_cast<bNodeTreeExec *>(execdata->data);
if (!node->id) {
return 0;
}
group_gpu_copy_inputs(node, in, exec->stack);
- ntreeExecGPUNodes(exec, mat, NULL);
+ ntreeExecGPUNodes(exec, mat, nullptr);
group_gpu_move_outputs(node, out, exec->stack);
return 1;
}
-void register_node_type_sh_group(void)
+void register_node_type_sh_group()
{
static bNodeType ntype;
/* NOTE: cannot use #sh_node_type_base for node group, because it would map the node type
* to the shared #NODE_GROUP integer type id. */
- node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP, 0);
+ node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP);
ntype.type = NODE_GROUP;
ntype.poll = sh_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
ntype.insert_link = node_insert_link_default;
ntype.rna_ext.srna = RNA_struct_find("ShaderNodeGroup");
- BLI_assert(ntype.rna_ext.srna != NULL);
+ BLI_assert(ntype.rna_ext.srna != nullptr);
RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
- node_type_socket_templates(&ntype, NULL, NULL);
+ node_type_socket_templates(&ntype, nullptr, nullptr);
node_type_size(&ntype, 140, 60, 400);
ntype.labelfunc = node_group_label;
node_type_group_update(&ntype, node_group_update);
@@ -254,10 +240,10 @@ void register_node_type_sh_group(void)
void register_node_type_sh_custom_group(bNodeType *ntype)
{
/* These methods can be overridden but need a default implementation otherwise. */
- if (ntype->poll == NULL) {
+ if (ntype->poll == nullptr) {
ntype->poll = sh_node_poll_default;
}
- if (ntype->insert_link == NULL) {
+ if (ntype->insert_link == nullptr) {
ntype->insert_link = node_insert_link_default;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc
index 09bbf3d851c..12ac83f35a2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_curves.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc
@@ -21,9 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_curves_cc {
static void sh_node_curve_vec_declare(NodeDeclarationBuilder &b)
{
@@ -33,8 +33,6 @@ static void sh_node_curve_vec_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Vector"));
};
-} // namespace blender::nodes
-
static void node_shader_exec_curve_vec(void *UNUSED(data),
int UNUSED(thread),
bNode *node,
@@ -152,25 +150,29 @@ static void sh_node_curve_vec_build_multi_function(
builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap);
}
+} // namespace blender::nodes::node_shader_curves_cc
+
void register_node_type_sh_curve_vec()
{
+ namespace file_ns = blender::nodes::node_shader_curves_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR, 0);
- ntype.declare = blender::nodes::sh_node_curve_vec_declare;
- node_type_init(&ntype, node_shader_init_curve_vec);
+ sh_fn_node_type_base(&ntype, SH_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::sh_node_curve_vec_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_curve_vec);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
- node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_vec);
- node_type_gpu(&ntype, gpu_shader_curve_vec);
- ntype.build_multi_function = sh_node_curve_vec_build_multi_function;
+ node_type_exec(&ntype, node_initexec_curves, nullptr, file_ns::node_shader_exec_curve_vec);
+ node_type_gpu(&ntype, file_ns::gpu_shader_curve_vec);
+ ntype.build_multi_function = file_ns::sh_node_curve_vec_build_multi_function;
nodeRegisterType(&ntype);
}
/* **************** CURVE RGB ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_shader_curves_cc {
static void sh_node_curve_rgb_declare(NodeDeclarationBuilder &b)
{
@@ -180,8 +182,6 @@ static void sh_node_curve_rgb_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Color"));
};
-} // namespace blender::nodes
-
static void node_shader_exec_curve_rgb(void *UNUSED(data),
int UNUSED(thread),
bNode *node,
@@ -329,25 +329,29 @@ static void sh_node_curve_rgb_build_multi_function(
builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap);
}
+} // namespace blender::nodes::node_shader_curves_cc
+
void register_node_type_sh_curve_rgb()
{
+ namespace file_ns = blender::nodes::node_shader_curves_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::sh_node_curve_rgb_declare;
- node_type_init(&ntype, node_shader_init_curve_rgb);
+ sh_fn_node_type_base(&ntype, SH_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::sh_node_curve_rgb_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_curve_rgb);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
- node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_rgb);
- node_type_gpu(&ntype, gpu_shader_curve_rgb);
- ntype.build_multi_function = sh_node_curve_rgb_build_multi_function;
+ node_type_exec(&ntype, node_initexec_curves, nullptr, file_ns::node_shader_exec_curve_rgb);
+ node_type_gpu(&ntype, file_ns::gpu_shader_curve_rgb);
+ ntype.build_multi_function = file_ns::sh_node_curve_rgb_build_multi_function;
nodeRegisterType(&ntype);
}
/* **************** CURVE FLOAT ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_shader_curves_cc {
static void sh_node_curve_float_declare(NodeDeclarationBuilder &b)
{
@@ -361,8 +365,6 @@ static void sh_node_curve_float_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Value"));
};
-} // namespace blender::nodes
-
static void node_shader_exec_curve_float(void *UNUSED(data),
int UNUSED(thread),
bNode *node,
@@ -473,18 +475,22 @@ static void sh_node_curve_float_build_multi_function(
builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap);
}
+} // namespace blender::nodes::node_shader_curves_cc
+
void register_node_type_sh_curve_float()
{
+ namespace file_ns = blender::nodes::node_shader_curves_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_CURVE_FLOAT, "Float Curve", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_curve_float_declare;
- node_type_init(&ntype, node_shader_init_curve_float);
+ sh_fn_node_type_base(&ntype, SH_NODE_CURVE_FLOAT, "Float Curve", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_curve_float_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_curve_float);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves);
- node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_float);
- node_type_gpu(&ntype, gpu_shader_curve_float);
- ntype.build_multi_function = sh_node_curve_float_build_multi_function;
+ node_type_exec(&ntype, node_initexec_curves, nullptr, file_ns::node_shader_exec_curve_float);
+ node_type_gpu(&ntype, file_ns::gpu_shader_curve_float);
+ ntype.build_multi_function = file_ns::sh_node_curve_float_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_displacement.c b/source/blender/nodes/shader/nodes/node_shader_displacement.cc
index e7deef23428..ef79e6d5c7e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_displacement.c
+++ b/source/blender/nodes/shader/nodes/node_shader_displacement.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_displacement_cc {
/* **************** OUTPUT ******************** */
@@ -68,16 +70,20 @@ static int gpu_shader_displacement(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_displacement_world", in, out);
}
+} // namespace blender::nodes::node_shader_displacement_cc
+
/* node type definition */
-void register_node_type_sh_displacement(void)
+void register_node_type_sh_displacement()
{
+ namespace file_ns = blender::nodes::node_shader_displacement_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_DISPLACEMENT, "Displacement", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_displacement_in, sh_node_displacement_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_init(&ntype, node_shader_init_displacement);
- node_type_gpu(&ntype, gpu_shader_displacement);
+ sh_node_type_base(&ntype, SH_NODE_DISPLACEMENT, "Displacement", NODE_CLASS_OP_VECTOR);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_displacement_in, file_ns::sh_node_displacement_out);
+ node_type_init(&ntype, file_ns::node_shader_init_displacement);
+ node_type_gpu(&ntype, file_ns::gpu_shader_displacement);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc
index 015af19abb2..aa34ba225a2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c
+++ b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_eevee_specular_cc {
/* **************** OUTPUT ******************** */
@@ -81,21 +83,24 @@ static int node_shader_gpu_eevee_specular(GPUMaterial *mat,
GPU_link(mat, "set_value", GPU_constant(&one), &in[9].link);
}
- GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY);
+ GPU_material_flag_set(mat, static_cast<eGPUMatFlag>(GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY));
return GPU_stack_link(mat, node, "node_eevee_specular", in, out, GPU_constant(&node->ssr_id));
}
+} // namespace blender::nodes::node_shader_eevee_specular_cc
+
/* node type definition */
-void register_node_type_sh_eevee_specular(void)
+void register_node_type_sh_eevee_specular()
{
+ namespace file_ns = blender::nodes::node_shader_eevee_specular_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_EEVEE_SPECULAR, "Specular BSDF", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_eevee_specular_in, sh_node_eevee_specular_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_eevee_specular);
+ sh_node_type_base(&ntype, SH_NODE_EEVEE_SPECULAR, "Specular BSDF", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_eevee_specular_in, file_ns::sh_node_eevee_specular_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_eevee_specular);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_emission.c b/source/blender/nodes/shader/nodes/node_shader_emission.cc
index 13f040fca48..47e4d3ad399 100644
--- a/source/blender/nodes/shader/nodes/node_shader_emission.c
+++ b/source/blender/nodes/shader/nodes/node_shader_emission.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_emission_cc {
/* **************** OUTPUT ******************** */
@@ -41,16 +43,18 @@ static int node_shader_gpu_emission(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_emission", in, out, GPU_builtin(GPU_VIEW_NORMAL));
}
+} // namespace blender::nodes::node_shader_emission_cc
+
/* node type definition */
-void register_node_type_sh_emission(void)
+void register_node_type_sh_emission()
{
+ namespace file_ns = blender::nodes::node_shader_emission_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_EMISSION, "Emission", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_emission_in, sh_node_emission_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_emission);
+ sh_node_type_base(&ntype, SH_NODE_EMISSION, "Emission", NODE_CLASS_SHADER);
+ node_type_socket_templates(&ntype, file_ns::sh_node_emission_in, file_ns::sh_node_emission_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_emission);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.cc
index 0af4e4ff5fb..4aa615e539e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c
+++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_fresnel_cc {
/* **************** Fresnel ******************** */
static bNodeSocketTemplate sh_node_fresnel_in[] = {
@@ -57,17 +59,19 @@ static void node_shader_exec_fresnel(void *UNUSED(data),
{
}
+} // namespace blender::nodes::node_shader_fresnel_cc
+
/* node type definition */
-void register_node_type_sh_fresnel(void)
+void register_node_type_sh_fresnel()
{
+ namespace file_ns = blender::nodes::node_shader_fresnel_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_FRESNEL, "Fresnel", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_fresnel_in, sh_node_fresnel_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_fresnel);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_fresnel);
+ sh_node_type_base(&ntype, SH_NODE_FRESNEL, "Fresnel", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, file_ns::sh_node_fresnel_in, file_ns::sh_node_fresnel_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_fresnel);
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_fresnel);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.cc
index b48838e5f56..2c2ef0e5ef8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_gamma.c
+++ b/source/blender/nodes/shader/nodes/node_shader_gamma.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_gamma_cc {
/* **************** Gamma Tools ******************** */
@@ -58,16 +60,18 @@ static int node_shader_gpu_gamma(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_gamma", in, out);
}
-void register_node_type_sh_gamma(void)
+} // namespace blender::nodes::node_shader_gamma_cc
+
+void register_node_type_sh_gamma()
{
+ namespace file_ns = blender::nodes::node_shader_gamma_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_gamma_in, sh_node_gamma_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_gamma);
- node_type_gpu(&ntype, node_shader_gpu_gamma);
+ sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR);
+ node_type_socket_templates(&ntype, file_ns::sh_node_gamma_in, file_ns::sh_node_gamma_out);
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_gamma);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_gamma);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.cc
index f66633e64c8..175be15c6e3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geometry.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geometry.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_geometry_cc {
/* **************** OUTPUT ******************** */
@@ -79,23 +81,25 @@ static int node_shader_gpu_geometry(GPUMaterial *mat,
out[i].link,
out[i].link,
&out[i].link,
- NULL);
+ nullptr);
}
}
return success;
}
+} // namespace blender::nodes::node_shader_geometry_cc
+
/* node type definition */
-void register_node_type_sh_geometry(void)
+void register_node_type_sh_geometry()
{
+ namespace file_ns = blender::nodes::node_shader_geometry_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_NEW_GEOMETRY, "Geometry", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_geometry_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_geometry);
+ sh_node_type_base(&ntype, SH_NODE_NEW_GEOMETRY, "Geometry", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_geometry_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_geometry);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_hair_info.c b/source/blender/nodes/shader/nodes/node_shader_hair_info.cc
index c721fb9c77a..c5af7e16201 100644
--- a/source/blender/nodes/shader/nodes/node_shader_hair_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_hair_info.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_hair_info_cc {
static bNodeSocketTemplate outputs[] = {
{SOCK_FLOAT, N_("Is Strand"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
@@ -43,16 +45,18 @@ static int node_shader_gpu_hair_info(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_hair_info", in, out, length_link);
}
+} // namespace blender::nodes::node_shader_hair_info_cc
+
/* node type definition */
-void register_node_type_sh_hair_info(void)
+void register_node_type_sh_hair_info()
{
+ namespace file_ns = blender::nodes::node_shader_hair_info_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_HAIR_INFO, "Hair Info", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, outputs);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_hair_info);
+ sh_node_type_base(&ntype, SH_NODE_HAIR_INFO, "Hair Info", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, nullptr, file_ns::outputs);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_hair_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_holdout.c b/source/blender/nodes/shader/nodes/node_shader_holdout.cc
index b58f86c1fc0..5a939d0b4f3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_holdout.c
+++ b/source/blender/nodes/shader/nodes/node_shader_holdout.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_holdout_cc {
/* **************** OUTPUT ******************** */
@@ -39,16 +41,18 @@ static int gpu_shader_rgb(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_holdout", in, out);
}
+} // namespace blender::nodes::node_shader_holdout_cc
+
/* node type definition */
-void register_node_type_sh_holdout(void)
+void register_node_type_sh_holdout()
{
+ namespace file_ns = blender::nodes::node_shader_holdout_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_HOLDOUT, "Holdout", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_holdout_in, sh_node_holdout_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, gpu_shader_rgb);
+ sh_node_type_base(&ntype, SH_NODE_HOLDOUT, "Holdout", NODE_CLASS_SHADER);
+ node_type_socket_templates(&ntype, file_ns::sh_node_holdout_in, file_ns::sh_node_holdout_out);
+ node_type_gpu(&ntype, file_ns::gpu_shader_rgb);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc
index 50eb5bf32c9..d63d664045b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc
@@ -21,7 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_hueSatVal_cc {
/* **************** Hue Saturation ******************** */
static bNodeSocketTemplate sh_node_hue_sat_in[] = {
@@ -85,15 +87,19 @@ static int gpu_shader_hue_sat(GPUMaterial *mat,
return GPU_stack_link(mat, node, "hue_sat", in, out);
}
-void register_node_type_sh_hue_sat(void)
+} // namespace blender::nodes::node_shader_hueSatVal_cc
+
+void register_node_type_sh_hue_sat()
{
+ namespace file_ns = blender::nodes::node_shader_hueSatVal_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_hue_sat_in, sh_node_hue_sat_out);
+ sh_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR);
+ node_type_socket_templates(&ntype, file_ns::sh_node_hue_sat_in, file_ns::sh_node_hue_sat_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_hue_sat);
- node_type_gpu(&ntype, gpu_shader_hue_sat);
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_hue_sat);
+ node_type_gpu(&ntype, file_ns::gpu_shader_hue_sat);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_ies_light.c b/source/blender/nodes/shader/nodes/node_shader_ies_light.cc
index 9cc5fd46181..a107fd83b0e 100644
--- a/source/blender/nodes/shader/nodes/node_shader_ies_light.c
+++ b/source/blender/nodes/shader/nodes/node_shader_ies_light.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_ies_light_cc {
/* **************** IES Light ******************** */
@@ -34,18 +36,22 @@ static bNodeSocketTemplate sh_node_tex_ies_out[] = {
static void node_shader_init_tex_ies(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderTexIES *tex = MEM_callocN(sizeof(NodeShaderTexIES), "NodeShaderIESLight");
+ NodeShaderTexIES *tex = MEM_cnew<NodeShaderTexIES>("NodeShaderIESLight");
node->storage = tex;
}
+} // namespace blender::nodes::node_shader_ies_light_cc
+
/* node type definition */
-void register_node_type_sh_tex_ies(void)
+void register_node_type_sh_tex_ies()
{
+ namespace file_ns = blender::nodes::node_shader_ies_light_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_IES, "IES Texture", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_ies_in, sh_node_tex_ies_out);
- node_type_init(&ntype, node_shader_init_tex_ies);
+ sh_node_type_base(&ntype, SH_NODE_TEX_IES, "IES Texture", NODE_CLASS_TEXTURE);
+ node_type_socket_templates(&ntype, file_ns::sh_node_tex_ies_in, file_ns::sh_node_tex_ies_out);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_ies);
node_type_storage(
&ntype, "NodeShaderTexIES", node_free_standard_storage, node_copy_standard_storage);
diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.c b/source/blender/nodes/shader/nodes/node_shader_invert.cc
index 0d6709a1968..e85985ce444 100644
--- a/source/blender/nodes/shader/nodes/node_shader_invert.c
+++ b/source/blender/nodes/shader/nodes/node_shader_invert.cc
@@ -21,7 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_invert_cc {
/* **************** INVERT ******************** */
static bNodeSocketTemplate sh_node_invert_in[] = {
@@ -65,14 +67,18 @@ static int gpu_shader_invert(GPUMaterial *mat,
return GPU_stack_link(mat, node, "invert", in, out);
}
-void register_node_type_sh_invert(void)
+} // namespace blender::nodes::node_shader_invert_cc
+
+void register_node_type_sh_invert()
{
+ namespace file_ns = blender::nodes::node_shader_invert_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_invert_in, sh_node_invert_out);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_invert);
- node_type_gpu(&ntype, gpu_shader_invert);
+ sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR);
+ node_type_socket_templates(&ntype, file_ns::sh_node_invert_in, file_ns::sh_node_invert_out);
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_invert);
+ node_type_gpu(&ntype, file_ns::gpu_shader_invert);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c b/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc
index c26b40b081c..de262e20644 100644
--- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c
+++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_layer_weight_cc {
/* **************** Layer Weight ******************** */
@@ -59,17 +61,20 @@ static void node_shader_exec_layer_weight(void *UNUSED(data),
{
}
+} // namespace blender::nodes::node_shader_layer_weight_cc
+
/* node type definition */
-void register_node_type_sh_layer_weight(void)
+void register_node_type_sh_layer_weight()
{
+ namespace file_ns = blender::nodes::node_shader_layer_weight_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_LAYER_WEIGHT, "Layer Weight", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_layer_weight_in, sh_node_layer_weight_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_layer_weight);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_layer_weight);
+ sh_node_type_base(&ntype, SH_NODE_LAYER_WEIGHT, "Layer Weight", NODE_CLASS_INPUT);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_layer_weight_in, file_ns::sh_node_layer_weight_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_layer_weight);
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_layer_weight);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_light_falloff.c b/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc
index 22172221f77..6c2baa01e54 100644
--- a/source/blender/nodes/shader/nodes/node_shader_light_falloff.c
+++ b/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_light_falloff_cc {
/* **************** INPUT ********************* */
@@ -45,17 +47,20 @@ static int node_shader_gpu_light_falloff(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_light_falloff", in, out);
}
+} // namespace blender::nodes::node_shader_light_falloff_cc
+
/* node type definition */
-void register_node_type_sh_light_falloff(void)
+void register_node_type_sh_light_falloff()
{
+ namespace file_ns = blender::nodes::node_shader_light_falloff_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_LIGHT_FALLOFF, "Light Falloff", NODE_CLASS_OP_COLOR, 0);
- node_type_socket_templates(&ntype, sh_node_light_falloff_in, sh_node_light_falloff_out);
+ sh_node_type_base(&ntype, SH_NODE_LIGHT_FALLOFF, "Light Falloff", NODE_CLASS_OP_COLOR);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_light_falloff_in, file_ns::sh_node_light_falloff_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_light_falloff);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_light_falloff);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.c b/source/blender/nodes/shader/nodes/node_shader_light_path.cc
index 45ad2133ee8..9f8e6502ce5 100644
--- a/source/blender/nodes/shader/nodes/node_shader_light_path.c
+++ b/source/blender/nodes/shader/nodes/node_shader_light_path.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_light_path_cc {
/* **************** OUTPUT ******************** */
@@ -47,16 +49,18 @@ static int node_shader_gpu_light_path(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_light_path", in, out);
}
+} // namespace blender::nodes::node_shader_light_path_cc
+
/* node type definition */
-void register_node_type_sh_light_path(void)
+void register_node_type_sh_light_path()
{
+ namespace file_ns = blender::nodes::node_shader_light_path_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_LIGHT_PATH, "Light Path", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_light_path_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_light_path);
+ sh_node_type_base(&ntype, SH_NODE_LIGHT_PATH, "Light Path", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_light_path_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_light_path);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
index 615ae276eb4..c4527fd3420 100644
--- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc
@@ -23,13 +23,15 @@
#include <algorithm>
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_math_base_safe.h"
-NODE_STORAGE_FUNCS(NodeMapRange)
+#include "NOD_socket_search_link.hh"
+
+namespace blender::nodes::node_shader_map_range_cc {
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeMapRange)
static void sh_node_map_range_declare(NodeDeclarationBuilder &b)
{
@@ -50,8 +52,6 @@ static void sh_node_map_range_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Vector"));
};
-} // namespace blender::nodes
-
static void node_shader_update_map_range(bNodeTree *ntree, bNode *node)
{
const NodeMapRange &storage = node_storage(*node);
@@ -80,7 +80,7 @@ static void node_shader_update_map_range(bNodeTree *ntree, bNode *node)
static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeMapRange *data = (NodeMapRange *)MEM_callocN(sizeof(NodeMapRange), __func__);
+ NodeMapRange *data = MEM_cnew<NodeMapRange>(__func__);
data->clamp = 1;
data->data_type = CD_PROP_FLOAT;
data->interpolation_type = NODE_MAP_RANGE_LINEAR;
@@ -89,6 +89,66 @@ static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = data;
}
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ CustomDataType data_type;
+ int interpolation_type = NODE_MAP_RANGE_LINEAR;
+
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("ShaderNodeMapRange");
+ node_storage(node).data_type = data_type;
+ node_storage(node).interpolation_type = interpolation_type;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
+static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket)
+{
+ switch (socket.type) {
+ case SOCK_FLOAT:
+ case SOCK_BOOLEAN:
+ case SOCK_INT:
+ return CD_PROP_FLOAT;
+ case SOCK_VECTOR:
+ case SOCK_RGBA:
+ return CD_PROP_FLOAT3;
+ default:
+ return {};
+ }
+}
+
+static void node_map_range_gather_link_searches(GatherLinkSearchOpParams &params)
+{
+ const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket());
+ if (!type) {
+ return;
+ }
+
+ if (params.in_out() == SOCK_IN) {
+ if (*type == CD_PROP_FLOAT3) {
+ params.add_item(IFACE_("Vector"), SocketSearchOp{"Vector", *type}, 0);
+ }
+ else {
+ params.add_item(IFACE_("Value"), SocketSearchOp{"Value", *type}, 0);
+ }
+ params.add_item(IFACE_("From Min"), SocketSearchOp{"From Min", *type}, -1);
+ params.add_item(IFACE_("From Max"), SocketSearchOp{"From Max", *type}, -1);
+ params.add_item(IFACE_("To Min"), SocketSearchOp{"To Min", *type}, -2);
+ params.add_item(IFACE_("To Max"), SocketSearchOp{"To Max", *type}, -2);
+ params.add_item(IFACE_("Steps"), SocketSearchOp{"Steps", *type, NODE_MAP_RANGE_STEPPED}, -3);
+ }
+ else {
+ if (*type == CD_PROP_FLOAT3) {
+ params.add_item(IFACE_("Vector"), SocketSearchOp{"Vector", *type});
+ }
+ else {
+ params.add_item(IFACE_("Result"), SocketSearchOp{"Result", *type});
+ }
+ }
+}
+
static const char *gpu_shader_get_name(int mode, bool use_vector)
{
if (use_vector) {
@@ -143,8 +203,6 @@ static int gpu_shader_map_range(GPUMaterial *mat,
return ret;
}
-namespace blender::nodes {
-
static inline float clamp_range(const float value, const float min, const float max)
{
return (min > max) ? std::clamp(value, max, min) : std::clamp(value, min, max);
@@ -582,20 +640,22 @@ static void sh_node_map_range_build_multi_function(
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_map_range_cc
void register_node_type_sh_map_range()
{
+ namespace file_ns = blender::nodes::node_shader_map_range_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_map_range_declare;
- node_type_init(&ntype, node_shader_init_map_range);
+ sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_map_range_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_map_range);
node_type_storage(
&ntype, "NodeMapRange", node_free_standard_storage, node_copy_standard_storage);
- node_type_update(&ntype, node_shader_update_map_range);
- node_type_gpu(&ntype, gpu_shader_map_range);
- ntype.build_multi_function = blender::nodes::sh_node_map_range_build_multi_function;
-
+ node_type_update(&ntype, file_ns::node_shader_update_map_range);
+ node_type_gpu(&ntype, file_ns::gpu_shader_map_range);
+ ntype.build_multi_function = file_ns::sh_node_map_range_build_multi_function;
+ ntype.gather_link_search_ops = file_ns::node_map_range_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.cc
index cabfecdb6ee..758b675f9d6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mapping.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mapping.cc
@@ -21,7 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_mapping_cc {
/* **************** MAPPING ******************** */
static bNodeSocketTemplate sh_node_mapping_in[] = {
@@ -37,21 +39,29 @@ static bNodeSocketTemplate sh_node_mapping_out[] = {
{-1, ""},
};
+static const char *gpu_shader_get_name(int mode)
+{
+ switch (mode) {
+ case NODE_MAPPING_TYPE_POINT:
+ return "mapping_point";
+ case NODE_MAPPING_TYPE_TEXTURE:
+ return "mapping_texture";
+ case NODE_MAPPING_TYPE_VECTOR:
+ return "mapping_vector";
+ case NODE_MAPPING_TYPE_NORMAL:
+ return "mapping_normal";
+ }
+ return nullptr;
+}
+
static int gpu_shader_mapping(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
GPUNodeStack *out)
{
- static const char *names[] = {
- [NODE_MAPPING_TYPE_POINT] = "mapping_point",
- [NODE_MAPPING_TYPE_TEXTURE] = "mapping_texture",
- [NODE_MAPPING_TYPE_VECTOR] = "mapping_vector",
- [NODE_MAPPING_TYPE_NORMAL] = "mapping_normal",
- };
-
- if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) {
- return GPU_stack_link(mat, node, names[node->custom1], in, out);
+ if (gpu_shader_get_name(node->custom1)) {
+ return GPU_stack_link(mat, node, gpu_shader_get_name(node->custom1), in, out);
}
return 0;
@@ -64,14 +74,18 @@ static void node_shader_update_mapping(bNodeTree *ntree, bNode *node)
ntree, sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE));
}
-void register_node_type_sh_mapping(void)
+} // namespace blender::nodes::node_shader_mapping_cc
+
+void register_node_type_sh_mapping()
{
+ namespace file_ns = blender::nodes::node_shader_mapping_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_mapping_in, sh_node_mapping_out);
- node_type_gpu(&ntype, gpu_shader_mapping);
- node_type_update(&ntype, node_shader_update_mapping);
+ sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR);
+ node_type_socket_templates(&ntype, file_ns::sh_node_mapping_in, file_ns::sh_node_mapping_out);
+ node_type_gpu(&ntype, file_ns::gpu_shader_mapping);
+ node_type_update(&ntype, file_ns::node_shader_update_mapping);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc
index da237be273f..ca30b16f7ff 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_math.cc
@@ -21,14 +21,16 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
#include "NOD_math_functions.hh"
#include "NOD_socket_search_link.hh"
+#include "RNA_enum_types.h"
+
/* **************** SCALAR MATH ******************** */
-namespace blender::nodes {
+namespace blender::nodes::node_shader_math_cc {
static void sh_node_math_declare(NodeDeclarationBuilder &b)
{
@@ -45,19 +47,41 @@ static void sh_node_math_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Value"));
};
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ NodeMathOperation mode = NODE_MATH_ADD;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("ShaderNodeMath");
+ node.custom1 = mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
static void sh_node_math_gather_link_searches(GatherLinkSearchOpParams &params)
{
- /* For now, do something very basic (only exposing "Add", and a single "Value" socket). */
- if (params.node_tree().typeinfo->validate_link(
+ if (!params.node_tree().typeinfo->validate_link(
static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) {
- params.add_item(IFACE_("Value"), [](LinkSearchOpParams &params) {
- bNode &node = params.add_node("ShaderNodeMath");
- params.update_and_connect_available_socket(node, "Value");
- });
+ return;
}
-}
-} // namespace blender::nodes
+ const bool is_geometry_node_tree = params.node_tree().type == NTREE_GEOMETRY;
+ const int weight = ELEM(params.other_socket().type, SOCK_FLOAT, SOCK_BOOLEAN, SOCK_INT) ? 0 : -1;
+
+ for (const EnumPropertyItem *item = rna_enum_node_math_items; item->identifier != nullptr;
+ item++) {
+ if (item->name != nullptr && item->identifier[0] != '\0') {
+ const int gn_weight =
+ (is_geometry_node_tree &&
+ ELEM(item->value, NODE_MATH_COMPARE, NODE_MATH_GREATER_THAN, NODE_MATH_LESS_THAN)) ?
+ -1 :
+ weight;
+ params.add_item(
+ IFACE_(item->name), SocketSearchOp{"Value", (NodeMathOperation)item->value}, gn_weight);
+ }
+ }
+}
static const char *gpu_shader_get_name(int mode)
{
@@ -174,17 +198,21 @@ static void sh_node_math_build_multi_function(blender::nodes::NodeMultiFunctionB
}
}
+} // namespace blender::nodes::node_shader_math_cc
+
void register_node_type_sh_math()
{
+ namespace file_ns = blender::nodes::node_shader_math_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_math_declare;
+ sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_math_declare;
ntype.labelfunc = node_math_label;
- node_type_gpu(&ntype, gpu_shader_math);
+ node_type_gpu(&ntype, file_ns::gpu_shader_math);
node_type_update(&ntype, node_math_update);
- ntype.build_multi_function = sh_node_math_build_multi_function;
- ntype.gather_link_search_ops = blender::nodes::sh_node_math_gather_link_searches;
+ ntype.build_multi_function = file_ns::sh_node_math_build_multi_function;
+ ntype.gather_link_search_ops = file_ns::sh_node_math_gather_link_searches;
nodeRegisterType(&ntype);
}
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 b89e0527eed..680c0be0fe8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc
@@ -21,9 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_mix_rgb_cc {
static void sh_node_mix_rgb_declare(NodeDeclarationBuilder &b)
{
@@ -34,8 +34,6 @@ static void sh_node_mix_rgb_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Color"));
};
-} // namespace blender::nodes
-
static void node_shader_exec_mix_rgb(void *UNUSED(data),
int UNUSED(thread),
bNode *node,
@@ -183,16 +181,20 @@ static void sh_node_mix_rgb_build_multi_function(blender::nodes::NodeMultiFuncti
builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type);
}
+} // namespace blender::nodes::node_shader_mix_rgb_cc
+
void register_node_type_sh_mix_rgb()
{
+ namespace file_ns = blender::nodes::node_shader_mix_rgb_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
- ntype.declare = blender::nodes::sh_node_mix_rgb_declare;
+ sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR);
+ ntype.declare = file_ns::sh_node_mix_rgb_declare;
ntype.labelfunc = node_blend_label;
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_mix_rgb);
- node_type_gpu(&ntype, gpu_shader_mix_rgb);
- ntype.build_multi_function = sh_node_mix_rgb_build_multi_function;
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_mix_rgb);
+ node_type_gpu(&ntype, file_ns::gpu_shader_mix_rgb);
+ ntype.build_multi_function = file_ns::sh_node_mix_rgb_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_shader.c b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc
index 33cbf34543c..d18ae46fc47 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mix_shader.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_mix_shader_cc {
/* **************** OUTPUT ******************** */
@@ -42,16 +44,19 @@ static int node_shader_gpu_mix_shader(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_mix_shader", in, out);
}
+} // namespace blender::nodes::node_shader_mix_shader_cc
+
/* node type definition */
-void register_node_type_sh_mix_shader(void)
+void register_node_type_sh_mix_shader()
{
+ namespace file_ns = blender::nodes::node_shader_mix_shader_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_MIX_SHADER, "Mix Shader", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_mix_shader_in, sh_node_mix_shader_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_mix_shader);
+ sh_node_type_base(&ntype, SH_NODE_MIX_SHADER, "Mix Shader", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_mix_shader_in, file_ns::sh_node_mix_shader_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_mix_shader);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal.c b/source/blender/nodes/shader/nodes/node_shader_normal.cc
index 83d5abcba67..9e6085e978a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal.cc
@@ -21,7 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_normal_cc {
/* **************** NORMAL ******************** */
static bNodeSocketTemplate sh_node_normal_in[] = {
@@ -64,14 +66,18 @@ static int gpu_shader_normal(GPUMaterial *mat,
return GPU_stack_link(mat, node, "normal_new_shading", in, out, vec);
}
-void register_node_type_sh_normal(void)
+} // namespace blender::nodes::node_shader_normal_cc
+
+void register_node_type_sh_normal()
{
+ namespace file_ns = blender::nodes::node_shader_normal_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_normal_in, sh_node_normal_out);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_normal);
- node_type_gpu(&ntype, gpu_shader_normal);
+ sh_node_type_base(&ntype, SH_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR);
+ node_type_socket_templates(&ntype, file_ns::sh_node_normal_in, file_ns::sh_node_normal_out);
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_normal);
+ node_type_gpu(&ntype, file_ns::gpu_shader_normal);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc
index 493acb06963..0c9932e3190 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_normal_map_cc {
/* **************** OUTPUT ******************** */
@@ -34,7 +36,7 @@ static bNodeSocketTemplate sh_node_normal_map_out[] = {
static void node_shader_init_normal_map(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderNormalMap *attr = MEM_callocN(sizeof(NodeShaderNormalMap), "NodeShaderNormalMap");
+ NodeShaderNormalMap *attr = MEM_cnew<NodeShaderNormalMap>("NodeShaderNormalMap");
node->storage = attr;
}
@@ -53,15 +55,16 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- NodeShaderNormalMap *nm = node->storage;
+ NodeShaderNormalMap *nm = static_cast<NodeShaderNormalMap *>(node->storage);
GPUNodeLink *strength;
if (in[0].link) {
strength = in[0].link;
}
else if (node->original) {
- bNodeSocket *socket = BLI_findlink(&node->original->inputs, 0);
- bNodeSocketValueFloat *socket_data = socket->default_value;
+ bNodeSocket *socket = static_cast<bNodeSocket *>(BLI_findlink(&node->original->inputs, 0));
+ bNodeSocketValueFloat *socket_data = static_cast<bNodeSocketValueFloat *>(
+ socket->default_value);
strength = GPU_uniform(&socket_data->value);
}
else {
@@ -73,8 +76,8 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
newnormal = in[1].link;
}
else if (node->original) {
- bNodeSocket *socket = BLI_findlink(&node->original->inputs, 1);
- bNodeSocketValueRGBA *socket_data = socket->default_value;
+ bNodeSocket *socket = static_cast<bNodeSocket *>(BLI_findlink(&node->original->inputs, 1));
+ bNodeSocketValueRGBA *socket_data = static_cast<bNodeSocketValueRGBA *>(socket->default_value);
newnormal = GPU_uniform(socket_data->value);
}
else {
@@ -114,19 +117,24 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
return true;
}
+} // namespace blender::nodes::node_shader_normal_map_cc
+
/* node type definition */
-void register_node_type_sh_normal_map(void)
+void register_node_type_sh_normal_map()
{
+ namespace file_ns = blender::nodes::node_shader_normal_map_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_NORMAL_MAP, "Normal Map", NODE_CLASS_OP_VECTOR, 0);
- node_type_socket_templates(&ntype, sh_node_normal_map_in, sh_node_normal_map_out);
+ sh_node_type_base(&ntype, SH_NODE_NORMAL_MAP, "Normal Map", NODE_CLASS_OP_VECTOR);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_normal_map_in, file_ns::sh_node_normal_map_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_normal_map);
+ node_type_init(&ntype, file_ns::node_shader_init_normal_map);
node_type_storage(
&ntype, "NodeShaderNormalMap", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, gpu_shader_normal_map);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_normal_map);
+ node_type_gpu(&ntype, file_ns::gpu_shader_normal_map);
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_normal_map);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.c b/source/blender/nodes/shader/nodes/node_shader_object_info.cc
index 47040954c9e..bbc4bd0015c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_object_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_object_info.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_object_info_cc {
/* **************** OUTPUT ******************** */
@@ -49,13 +51,17 @@ static int node_shader_gpu_object_info(GPUMaterial *mat,
GPU_constant(&index));
}
-void register_node_type_sh_object_info(void)
+} // namespace blender::nodes::node_shader_object_info_cc
+
+void register_node_type_sh_object_info()
{
+ namespace file_ns = blender::nodes::node_shader_object_info_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_object_info_out);
- node_type_gpu(&ntype, node_shader_gpu_object_info);
+ sh_node_type_base(&ntype, SH_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_object_info_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_object_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_aov.c b/source/blender/nodes/shader/nodes/node_shader_output_aov.cc
index 32765b459ca..200ccef7404 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_aov.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_aov.cc
@@ -17,10 +17,12 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_hash.h"
+namespace blender::nodes::node_shader_output_aov_cc {
+
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_output_aov_in[] = {
@@ -31,7 +33,7 @@ static bNodeSocketTemplate sh_node_output_aov_in[] = {
static void node_shader_init_output_aov(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderOutputAOV *aov = MEM_callocN(sizeof(NodeShaderOutputAOV), "NodeShaderOutputAOV");
+ NodeShaderOutputAOV *aov = MEM_cnew<NodeShaderOutputAOV>("NodeShaderOutputAOV");
node->storage = aov;
}
@@ -52,17 +54,21 @@ static int node_shader_gpu_output_aov(GPUMaterial *mat,
return true;
}
+} // namespace blender::nodes::node_shader_output_aov_cc
+
/* node type definition */
-void register_node_type_sh_output_aov(void)
+void register_node_type_sh_output_aov()
{
+ namespace file_ns = blender::nodes::node_shader_output_aov_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_AOV, "AOV Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_aov_in, NULL);
- node_type_init(&ntype, node_shader_init_output_aov);
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_AOV, "AOV Output", NODE_CLASS_OUTPUT);
+ node_type_socket_templates(&ntype, file_ns::sh_node_output_aov_in, nullptr);
+ node_type_init(&ntype, file_ns::node_shader_init_output_aov);
node_type_storage(
&ntype, "NodeShaderOutputAOV", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_output_aov);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_output_aov);
ntype.no_muting = true;
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_light.c b/source/blender/nodes/shader/nodes/node_shader_output_light.cc
index 6c4837f3c6f..88006563db2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_light.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_light.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_output_light_cc {
/* **************** OUTPUT ******************** */
@@ -26,15 +28,17 @@ static bNodeSocketTemplate sh_node_output_light_in[] = {
{-1, ""},
};
+} // namespace blender::nodes::node_shader_output_light_cc
+
/* node type definition */
-void register_node_type_sh_output_light(void)
+void register_node_type_sh_output_light()
{
+ namespace file_ns = blender::nodes::node_shader_output_light_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_LIGHT, "Light Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_light_in, NULL);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_LIGHT, "Light Output", NODE_CLASS_OUTPUT);
+ node_type_socket_templates(&ntype, file_ns::sh_node_output_light_in, nullptr);
ntype.no_muting = true;
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc
index 07e253383e2..ee80962d35a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_output_linestyle_cc {
/* **************** OUTPUT ******************** */
@@ -29,14 +31,17 @@ static bNodeSocketTemplate sh_node_output_linestyle_in[] = {
{-1, ""},
};
+} // namespace blender::nodes::node_shader_output_linestyle_cc
+
/* node type definition */
-void register_node_type_sh_output_linestyle(void)
+void register_node_type_sh_output_linestyle()
{
+ namespace file_ns = blender::nodes::node_shader_output_linestyle_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_LINESTYLE, "Line Style Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_linestyle_in, NULL);
- node_type_init(&ntype, NULL);
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_LINESTYLE, "Line Style Output", NODE_CLASS_OUTPUT);
+ node_type_socket_templates(&ntype, file_ns::sh_node_output_linestyle_in, nullptr);
ntype.no_muting = true;
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.cc
index 41932cca6a3..c8bb39ffa04 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_material.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_material.cc
@@ -17,10 +17,12 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BKE_scene.h"
+namespace blender::nodes::node_shader_output_material_cc {
+
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_output_material_in[] = {
@@ -73,16 +75,18 @@ static int node_shader_gpu_output_material(GPUMaterial *mat,
return true;
}
+} // namespace blender::nodes::node_shader_output_material_cc
+
/* node type definition */
-void register_node_type_sh_output_material(void)
+void register_node_type_sh_output_material()
{
+ namespace file_ns = blender::nodes::node_shader_output_material_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_MATERIAL, "Material Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_material_in, NULL);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_output_material);
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_MATERIAL, "Material Output", NODE_CLASS_OUTPUT);
+ node_type_socket_templates(&ntype, file_ns::sh_node_output_material_in, nullptr);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_output_material);
ntype.no_muting = true;
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.c b/source/blender/nodes/shader/nodes/node_shader_output_world.cc
index 09eca7f712e..b2382b08d9a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_output_world.c
+++ b/source/blender/nodes/shader/nodes/node_shader_output_world.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_output_world_cc {
/* **************** OUTPUT ******************** */
@@ -41,16 +43,18 @@ static int node_shader_gpu_output_world(GPUMaterial *mat,
return true;
}
+} // namespace blender::nodes::node_shader_output_world_cc
+
/* node type definition */
-void register_node_type_sh_output_world(void)
+void register_node_type_sh_output_world()
{
+ namespace file_ns = blender::nodes::node_shader_output_world_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_OUTPUT_WORLD, "World Output", NODE_CLASS_OUTPUT, 0);
- node_type_socket_templates(&ntype, sh_node_output_world_in, NULL);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_output_world);
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_WORLD, "World Output", NODE_CLASS_OUTPUT);
+ node_type_socket_templates(&ntype, file_ns::sh_node_output_world_in, nullptr);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_output_world);
ntype.no_muting = true;
diff --git a/source/blender/nodes/shader/nodes/node_shader_particle_info.c b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc
index c6eabc3b2cb..444738f81b3 100644
--- a/source/blender/nodes/shader/nodes/node_shader_particle_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc
@@ -17,9 +17,12 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
#include "RE_texture.h"
+namespace blender::nodes::node_shader_particle_info_cc {
+
static bNodeSocketTemplate outputs[] = {
{SOCK_FLOAT, "Index"},
{SOCK_FLOAT, "Random"},
@@ -61,15 +64,19 @@ static int gpu_shader_particle_info(GPUMaterial *mat,
GPU_builtin(GPU_PARTICLE_ANG_VELOCITY));
}
+} // namespace blender::nodes::node_shader_particle_info_cc
+
/* node type definition */
-void register_node_type_sh_particle_info(void)
+void register_node_type_sh_particle_info()
{
+ namespace file_ns = blender::nodes::node_shader_particle_info_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_PARTICLE_INFO, "Particle Info", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, outputs);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_particle_info);
- node_type_gpu(&ntype, gpu_shader_particle_info);
+ sh_node_type_base(&ntype, SH_NODE_PARTICLE_INFO, "Particle Info", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, nullptr, file_ns::outputs);
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_particle_info);
+ node_type_gpu(&ntype, file_ns::gpu_shader_particle_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb.c b/source/blender/nodes/shader/nodes/node_shader_rgb.cc
index 0bdef9a2a17..f3b83b72232 100644
--- a/source/blender/nodes/shader/nodes/node_shader_rgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_rgb.cc
@@ -21,13 +21,14 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** RGB ******************** */
-static bNodeSocketTemplate sh_node_rgb_out[] = {
- {SOCK_RGBA, N_("Color"), 0.5f, 0.5f, 0.5f, 1.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_rgb_cc {
+
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_output<decl::Color>(N_("Color")).default_value({0.5f, 0.5f, 0.5f, 1.0f});
+}
static int gpu_shader_rgb(GPUMaterial *mat,
bNode *node,
@@ -39,13 +40,17 @@ static int gpu_shader_rgb(GPUMaterial *mat,
return GPU_stack_link(mat, node, "set_rgba", in, out, link);
}
-void register_node_type_sh_rgb(void)
+} // namespace blender::nodes::node_shader_rgb_cc
+
+void register_node_type_sh_rgb()
{
+ namespace file_ns = blender::nodes::node_shader_rgb_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_RGB, "RGB", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_rgb_out);
- node_type_gpu(&ntype, gpu_shader_rgb);
+ sh_node_type_base(&ntype, SH_NODE_RGB, "RGB", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::node_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_rgb);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc
index e3808985c0e..8efdae091a7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc
@@ -23,172 +23,9 @@
#include "IMB_colormanagement.h"
-#include "DNA_texture_types.h"
+#include "node_shader_util.hh"
-#include "BLI_color.hh"
-
-#include "node_shader_util.h"
-
-namespace blender::nodes {
-
-static void sh_node_valtorgb_declare(NodeDeclarationBuilder &b)
-{
- b.is_function_node();
- b.add_input<decl::Float>(N_("Fac")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR);
- b.add_output<decl::Color>(N_("Color"));
- b.add_output<decl::Float>(N_("Alpha"));
-};
-
-} // namespace blender::nodes
-
-static void node_shader_exec_valtorgb(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- /* stack order in: fac */
- /* stack order out: col, alpha */
-
- if (node->storage) {
- float fac;
- nodestack_get_vec(&fac, SOCK_FLOAT, in[0]);
-
- BKE_colorband_evaluate((ColorBand *)node->storage, fac, out[0]->vec);
- out[1]->vec[0] = out[0]->vec[3];
- }
-}
-
-static void node_shader_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node)
-{
- node->storage = BKE_colorband_add(true);
-}
-
-static int gpu_shader_valtorgb(GPUMaterial *mat,
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- GPUNodeStack *in,
- GPUNodeStack *out)
-{
- struct ColorBand *coba = (ColorBand *)node->storage;
- float *array, layer;
- int size;
-
- /* Common / easy case optimization. */
- if ((coba->tot <= 2) && (coba->color_mode == COLBAND_BLEND_RGB)) {
- float mul_bias[2];
- switch (coba->ipotype) {
- case COLBAND_INTERP_LINEAR:
- mul_bias[0] = 1.0f / (coba->data[1].pos - coba->data[0].pos);
- mul_bias[1] = -mul_bias[0] * coba->data[0].pos;
- return GPU_stack_link(mat,
- node,
- "valtorgb_opti_linear",
- in,
- out,
- GPU_uniform(mul_bias),
- GPU_uniform(&coba->data[0].r),
- GPU_uniform(&coba->data[1].r));
- case COLBAND_INTERP_CONSTANT:
- mul_bias[1] = max_ff(coba->data[0].pos, coba->data[1].pos);
- return GPU_stack_link(mat,
- node,
- "valtorgb_opti_constant",
- in,
- out,
- GPU_uniform(&mul_bias[1]),
- GPU_uniform(&coba->data[0].r),
- GPU_uniform(&coba->data[1].r));
- case COLBAND_INTERP_EASE:
- mul_bias[0] = 1.0f / (coba->data[1].pos - coba->data[0].pos);
- mul_bias[1] = -mul_bias[0] * coba->data[0].pos;
- return GPU_stack_link(mat,
- node,
- "valtorgb_opti_ease",
- in,
- out,
- GPU_uniform(mul_bias),
- GPU_uniform(&coba->data[0].r),
- GPU_uniform(&coba->data[1].r));
- default:
- break;
- }
- }
-
- BKE_colorband_evaluate_table_rgba(coba, &array, &size);
- GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer);
-
- if (coba->ipotype == COLBAND_INTERP_CONSTANT) {
- return GPU_stack_link(mat, node, "valtorgb_nearest", in, out, tex, GPU_constant(&layer));
- }
-
- return GPU_stack_link(mat, node, "valtorgb", in, out, tex, GPU_constant(&layer));
-}
-
-class ColorBandFunction : public blender::fn::MultiFunction {
- private:
- const ColorBand &color_band_;
-
- public:
- ColorBandFunction(const ColorBand &color_band) : color_band_(color_band)
- {
- static blender::fn::MFSignature signature = create_signature();
- this->set_signature(&signature);
- }
-
- static blender::fn::MFSignature create_signature()
- {
- blender::fn::MFSignatureBuilder signature{"Color Band"};
- signature.single_input<float>("Value");
- signature.single_output<blender::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
- {
- 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");
-
- for (int64_t i : mask) {
- blender::ColorGeometry4f color;
- BKE_colorband_evaluate(&color_band_, values[i], color);
- colors[i] = color;
- alphas[i] = color.a;
- }
- }
-};
-
-static void sh_node_valtorgb_build_multi_function(
- blender::nodes::NodeMultiFunctionBuilder &builder)
-{
- bNode &bnode = builder.node();
- const ColorBand *color_band = (const ColorBand *)bnode.storage;
- builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band);
-}
-
-void register_node_type_sh_valtorgb()
-{
- static bNodeType ntype;
-
- sh_fn_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_valtorgb_declare;
- node_type_init(&ntype, node_shader_init_valtorgb);
- node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage);
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_valtorgb);
- node_type_gpu(&ntype, gpu_shader_valtorgb);
- ntype.build_multi_function = sh_node_valtorgb_build_multi_function;
-
- nodeRegisterType(&ntype);
-}
-
-namespace blender::nodes {
+namespace blender::nodes::node_shader_rgb_to_bw_cc {
static void sh_node_rgbtobw_declare(NodeDeclarationBuilder &b)
{
@@ -196,8 +33,6 @@ static void sh_node_rgbtobw_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Val"));
};
-} // namespace blender::nodes
-
static void node_shader_exec_rgbtobw(void *UNUSED(data),
int UNUSED(thread),
bNode *UNUSED(node),
@@ -222,14 +57,18 @@ static int gpu_shader_rgbtobw(GPUMaterial *mat,
return GPU_stack_link(mat, node, "rgbtobw", in, out);
}
+} // namespace blender::nodes::node_shader_rgb_to_bw_cc
+
void register_node_type_sh_rgbtobw()
{
+ namespace file_ns = blender::nodes::node_shader_rgb_to_bw_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_rgbtobw_declare;
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_rgbtobw);
- node_type_gpu(&ntype, gpu_shader_rgbtobw);
+ sh_node_type_base(&ntype, SH_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_rgbtobw_declare;
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_rgbtobw);
+ node_type_gpu(&ntype, file_ns::gpu_shader_rgbtobw);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_script.c b/source/blender/nodes/shader/nodes/node_shader_script.cc
index 42ab272de0e..6c6578cf6c1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_script.c
+++ b/source/blender/nodes/shader/nodes/node_shader_script.cc
@@ -21,19 +21,21 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_script_cc {
/* **************** Script ******************** */
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderScript *nss = MEM_callocN(sizeof(NodeShaderScript), "shader script node");
+ NodeShaderScript *nss = MEM_cnew<NodeShaderScript>("shader script node");
node->storage = nss;
}
static void node_free_script(bNode *node)
{
- NodeShaderScript *nss = node->storage;
+ NodeShaderScript *nss = static_cast<NodeShaderScript *>(node->storage);
if (nss) {
if (nss->bytecode) {
@@ -48,23 +50,28 @@ static void node_copy_script(bNodeTree *UNUSED(dest_ntree),
bNode *dest_node,
const bNode *src_node)
{
- NodeShaderScript *src_nss = src_node->storage;
- NodeShaderScript *dest_nss = MEM_dupallocN(src_nss);
+ NodeShaderScript *src_nss = static_cast<NodeShaderScript *>(src_node->storage);
+ NodeShaderScript *dest_nss = static_cast<NodeShaderScript *>(MEM_dupallocN(src_nss));
if (src_nss->bytecode) {
- dest_nss->bytecode = MEM_dupallocN(src_nss->bytecode);
+ dest_nss->bytecode = static_cast<char *>(MEM_dupallocN(src_nss->bytecode));
}
dest_node->storage = dest_nss;
}
-void register_node_type_sh_script(void)
+} // namespace blender::nodes::node_shader_script_cc
+
+void register_node_type_sh_script()
{
+ namespace file_ns = blender::nodes::node_shader_script_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SCRIPT, "Script", NODE_CLASS_SCRIPT, 0);
- node_type_init(&ntype, init);
- node_type_storage(&ntype, "NodeShaderScript", node_free_script, node_copy_script);
+ sh_node_type_base(&ntype, SH_NODE_SCRIPT, "Script", NODE_CLASS_SCRIPT);
+ node_type_init(&ntype, file_ns::init);
+ node_type_storage(
+ &ntype, "NodeShaderScript", file_ns::node_free_script, file_ns::node_copy_script);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
index dfecb830b35..901903a114c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc
@@ -21,7 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_sepcomb_hsv_cc {
/* **************** SEPARATE HSV ******************** */
static bNodeSocketTemplate sh_node_sephsv_in[] = {
@@ -57,18 +59,24 @@ static int gpu_shader_sephsv(GPUMaterial *mat,
return GPU_stack_link(mat, node, "separate_hsv", in, out);
}
-void register_node_type_sh_sephsv(void)
+} // namespace blender::nodes::node_shader_sepcomb_hsv_cc
+
+void register_node_type_sh_sephsv()
{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_hsv_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, sh_node_sephsv_in, sh_node_sephsv_out);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_sephsv);
- node_type_gpu(&ntype, gpu_shader_sephsv);
+ sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTER);
+ node_type_socket_templates(&ntype, file_ns::sh_node_sephsv_in, file_ns::sh_node_sephsv_out);
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_sephsv);
+ node_type_gpu(&ntype, file_ns::gpu_shader_sephsv);
nodeRegisterType(&ntype);
}
+namespace blender::nodes::node_shader_sepcomb_hsv_cc {
+
/* **************** COMBINE HSV ******************** */
static bNodeSocketTemplate sh_node_combhsv_in[] = {
{SOCK_FLOAT, N_("H"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
@@ -105,14 +113,18 @@ static int gpu_shader_combhsv(GPUMaterial *mat,
return GPU_stack_link(mat, node, "combine_hsv", in, out);
}
-void register_node_type_sh_combhsv(void)
+} // namespace blender::nodes::node_shader_sepcomb_hsv_cc
+
+void register_node_type_sh_combhsv()
{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_hsv_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, sh_node_combhsv_in, sh_node_combhsv_out);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_combhsv);
- node_type_gpu(&ntype, gpu_shader_combhsv);
+ sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTER);
+ node_type_socket_templates(&ntype, file_ns::sh_node_combhsv_in, file_ns::sh_node_combhsv_out);
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_combhsv);
+ node_type_gpu(&ntype, file_ns::gpu_shader_combhsv);
nodeRegisterType(&ntype);
}
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 4984a530d8b..71ba2561bc7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc
@@ -21,9 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_sepcomb_rgb_cc {
static void sh_node_seprgb_declare(NodeDeclarationBuilder &b)
{
@@ -34,8 +34,6 @@ static void sh_node_seprgb_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("B"));
};
-} // namespace blender::nodes
-
static void node_shader_exec_seprgb(void *UNUSED(data),
int UNUSED(thread),
bNode *UNUSED(node),
@@ -103,20 +101,24 @@ static void sh_node_seprgb_build_multi_function(blender::nodes::NodeMultiFunctio
builder.set_matching_fn(fn);
}
+} // namespace blender::nodes::node_shader_sepcomb_rgb_cc
+
void register_node_type_sh_seprgb()
{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_rgb_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_seprgb_declare;
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_seprgb);
- node_type_gpu(&ntype, gpu_shader_seprgb);
- ntype.build_multi_function = sh_node_seprgb_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_seprgb_declare;
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_seprgb);
+ node_type_gpu(&ntype, file_ns::gpu_shader_seprgb);
+ ntype.build_multi_function = file_ns::sh_node_seprgb_build_multi_function;
nodeRegisterType(&ntype);
}
-namespace blender::nodes {
+namespace blender::nodes::node_shader_sepcomb_rgb_cc {
static void sh_node_combrgb_declare(NodeDeclarationBuilder &b)
{
@@ -127,8 +129,6 @@ static void sh_node_combrgb_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Image"));
};
-} // namespace blender::nodes
-
static void node_shader_exec_combrgb(void *UNUSED(data),
int UNUSED(thread),
bNode *UNUSED(node),
@@ -163,15 +163,19 @@ static void sh_node_combrgb_build_multi_function(blender::nodes::NodeMultiFuncti
builder.set_matching_fn(fn);
}
+} // namespace blender::nodes::node_shader_sepcomb_rgb_cc
+
void register_node_type_sh_combrgb()
{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_rgb_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_combrgb_declare;
- node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_combrgb);
- node_type_gpu(&ntype, gpu_shader_combrgb);
- ntype.build_multi_function = sh_node_combrgb_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_combrgb_declare;
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_combrgb);
+ node_type_gpu(&ntype, file_ns::gpu_shader_combrgb);
+ ntype.build_multi_function = file_ns::sh_node_combrgb_build_multi_function;
nodeRegisterType(&ntype);
}
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 a414630829e..57eef716e88 100644
--- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc
@@ -21,9 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_sepcomb_xyz_cc {
static void sh_node_sepxyz_declare(NodeDeclarationBuilder &b)
{
@@ -34,8 +34,6 @@ static void sh_node_sepxyz_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Z"));
};
-} // namespace blender::nodes
-
static int gpu_shader_sepxyz(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
@@ -88,19 +86,23 @@ static void sh_node_sepxyz_build_multi_function(blender::nodes::NodeMultiFunctio
builder.set_matching_fn(separate_fn);
}
+} // namespace blender::nodes::node_shader_sepcomb_xyz_cc
+
void register_node_type_sh_sepxyz()
{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_sepxyz_declare;
- node_type_gpu(&ntype, gpu_shader_sepxyz);
- ntype.build_multi_function = sh_node_sepxyz_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_sepxyz_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_sepxyz);
+ ntype.build_multi_function = file_ns::sh_node_sepxyz_build_multi_function;
nodeRegisterType(&ntype);
}
-namespace blender::nodes {
+namespace blender::nodes::node_shader_sepcomb_xyz_cc {
static void sh_node_combxyz_declare(NodeDeclarationBuilder &b)
{
@@ -111,8 +113,6 @@ static void sh_node_combxyz_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Vector"));
};
-} // namespace blender::nodes
-
static int gpu_shader_combxyz(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
@@ -129,14 +129,18 @@ static void sh_node_combxyz_build_multi_function(blender::nodes::NodeMultiFuncti
builder.set_matching_fn(fn);
}
+} // namespace blender::nodes::node_shader_sepcomb_xyz_cc
+
void register_node_type_sh_combxyz()
{
+ namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTER, 0);
- ntype.declare = blender::nodes::sh_node_combxyz_declare;
- node_type_gpu(&ntype, gpu_shader_combxyz);
- ntype.build_multi_function = sh_node_combxyz_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::sh_node_combxyz_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_combxyz);
+ ntype.build_multi_function = file_ns::sh_node_combxyz_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc
index 25c30aa4081..f5e3787ca7c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c
+++ b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_shader_to_rgb_cc {
/* **************** OUTPUT ******************** */
@@ -45,16 +47,19 @@ static int node_shader_gpu_shadertorgb(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_shader_to_rgba", in, out);
}
+} // namespace blender::nodes::node_shader_shader_to_rgb_cc
+
/* node type definition */
-void register_node_type_sh_shadertorgb(void)
+void register_node_type_sh_shadertorgb()
{
+ namespace file_ns = blender::nodes::node_shader_shader_to_rgb_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SHADERTORGB, "Shader to RGB", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, sh_node_shadertorgb_in, sh_node_shadertorgb_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_shadertorgb);
+ sh_node_type_base(&ntype, SH_NODE_SHADERTORGB, "Shader to RGB", NODE_CLASS_CONVERTER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_shadertorgb_in, file_ns::sh_node_shadertorgb_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_shadertorgb);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_squeeze.c b/source/blender/nodes/shader/nodes/node_shader_squeeze.cc
index ca7bdf41df9..f41b692ff96 100644
--- a/source/blender/nodes/shader/nodes/node_shader_squeeze.c
+++ b/source/blender/nodes/shader/nodes/node_shader_squeeze.cc
@@ -21,7 +21,9 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_squeeze_cc {
/* **************** VALUE SQUEEZE ******************** */
static bNodeSocketTemplate sh_node_squeeze_in[] = {
@@ -57,15 +59,18 @@ static int gpu_shader_squeeze(GPUMaterial *mat,
return GPU_stack_link(mat, node, "squeeze", in, out);
}
-void register_node_type_sh_squeeze(void)
+} // namespace blender::nodes::node_shader_squeeze_cc
+
+void register_node_type_sh_squeeze()
{
+ namespace file_ns = blender::nodes::node_shader_squeeze_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_SQUEEZE, "Squeeze Value", NODE_CLASS_CONVERTER, 0);
- node_type_socket_templates(&ntype, sh_node_squeeze_in, sh_node_squeeze_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_squeeze);
- node_type_gpu(&ntype, gpu_shader_squeeze);
+ sh_node_type_base(&ntype, SH_NODE_SQUEEZE, "Squeeze Value", NODE_CLASS_CONVERTER);
+ node_type_socket_templates(&ntype, file_ns::sh_node_squeeze_in, file_ns::sh_node_squeeze_out);
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_squeeze);
+ node_type_gpu(&ntype, file_ns::gpu_shader_squeeze);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc
index 85a4a6aa425..a5820aef194 100644
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_subsurface_scattering_cc {
/* **************** OUTPUT ******************** */
@@ -53,14 +55,14 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat,
}
if (node->sss_id > 0) {
- bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
- bNodeSocketValueRGBA *socket_data = socket->default_value;
+ bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2);
+ bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value;
/* For some reason it seems that the socket value is in ARGB format. */
GPU_material_sss_profile_create(mat, &socket_data->value[1]);
/* sss_id is 0 only the node is not connected to any output.
* In this case flagging the material would trigger a bug (see T68736). */
- GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS);
+ GPU_material_flag_set(mat, (eGPUMatFlag)(GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS));
}
return GPU_stack_link(
@@ -71,27 +73,31 @@ static void node_shader_update_subsurface_scattering(bNodeTree *ntree, bNode *no
{
const int sss_method = node->custom1;
- for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (STR_ELEM(sock->name, "IOR", "Anisotropy")) {
nodeSetSocketAvailability(ntree, sock, sss_method != SHD_SUBSURFACE_BURLEY);
}
}
}
+} // namespace blender::nodes::node_shader_subsurface_scattering_cc
+
/* node type definition */
-void register_node_type_sh_subsurface_scattering(void)
+void register_node_type_sh_subsurface_scattering()
{
+ namespace file_ns = blender::nodes::node_shader_subsurface_scattering_cc;
+
static bNodeType ntype;
sh_node_type_base(
- &ntype, SH_NODE_SUBSURFACE_SCATTERING, "Subsurface Scattering", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(
- &ntype, sh_node_subsurface_scattering_in, sh_node_subsurface_scattering_out);
+ &ntype, SH_NODE_SUBSURFACE_SCATTERING, "Subsurface Scattering", NODE_CLASS_SHADER);
+ node_type_socket_templates(&ntype,
+ file_ns::sh_node_subsurface_scattering_in,
+ file_ns::sh_node_subsurface_scattering_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_subsurface_scattering);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_subsurface_scattering);
- node_type_update(&ntype, node_shader_update_subsurface_scattering);
+ node_type_init(&ntype, file_ns::node_shader_init_subsurface_scattering);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_subsurface_scattering);
+ node_type_update(&ntype, file_ns::node_shader_update_subsurface_scattering);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tangent.c b/source/blender/nodes/shader/nodes/node_shader_tangent.cc
index 2c12bf9bc01..9b1c4244604 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tangent.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tangent.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_tangent_cc {
/* **************** OUTPUT ******************** */
@@ -28,7 +30,7 @@ static bNodeSocketTemplate sh_node_tangent_out[] = {
static void node_shader_init_tangent(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderTangent *attr = MEM_callocN(sizeof(NodeShaderTangent), "NodeShaderTangent");
+ NodeShaderTangent *attr = MEM_cnew<NodeShaderTangent>("NodeShaderTangent");
attr->axis = SHD_TANGENT_AXIS_Z;
node->storage = attr;
}
@@ -39,7 +41,7 @@ static int node_shader_gpu_tangent(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- NodeShaderTangent *attr = node->storage;
+ NodeShaderTangent *attr = static_cast<NodeShaderTangent *>(node->storage);
if (attr->direction_type == SHD_TANGENT_UVMAP) {
return GPU_stack_link(
@@ -68,16 +70,20 @@ static int node_shader_gpu_tangent(GPUMaterial *mat,
GPU_builtin(GPU_OBJECT_MATRIX));
}
+} // namespace blender::nodes::node_shader_tangent_cc
+
/* node type definition */
-void register_node_type_sh_tangent(void)
+void register_node_type_sh_tangent()
{
+ namespace file_ns = blender::nodes::node_shader_tangent_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TANGENT, "Tangent", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_tangent_out);
+ sh_node_type_base(&ntype, SH_NODE_TANGENT, "Tangent", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_tangent_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tangent);
- node_type_gpu(&ntype, node_shader_gpu_tangent);
+ node_type_init(&ntype, file_ns::node_shader_init_tangent);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tangent);
node_type_storage(
&ntype, "NodeShaderTangent", node_free_standard_storage, node_copy_standard_storage);
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 7925c96db3d..6a4a131a315 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc
@@ -17,12 +17,12 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_float2.hh"
#include "BLI_float4.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_tex_brick_cc {
static void sh_node_tex_brick_declare(NodeDeclarationBuilder &b)
{
@@ -57,11 +57,9 @@ static void sh_node_tex_brick_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Fac"));
};
-} // namespace blender::nodes
-
static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexBrick *tex = (NodeTexBrick *)MEM_callocN(sizeof(NodeTexBrick), "NodeTexBrick");
+ NodeTexBrick *tex = MEM_cnew<NodeTexBrick>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
@@ -101,8 +99,6 @@ static int node_shader_gpu_tex_brick(GPUMaterial *mat,
GPU_constant(&squash_freq));
}
-namespace blender::nodes {
-
class BrickFunction : public fn::MultiFunction {
private:
const float offset_;
@@ -266,20 +262,22 @@ static void sh_node_brick_build_multi_function(blender::nodes::NodeMultiFunction
tex->offset, tex->offset_freq, tex->squash, tex->squash_freq);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_brick_cc
void register_node_type_sh_tex_brick()
{
+ namespace file_ns = blender::nodes::node_shader_tex_brick_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_BRICK, "Brick Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_brick_declare;
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_BRICK, "Brick Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_brick_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tex_brick);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_brick);
node_type_storage(
&ntype, "NodeTexBrick", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_brick);
- ntype.build_multi_function = blender::nodes::sh_node_brick_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_brick);
+ ntype.build_multi_function = file_ns::sh_node_brick_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
index 6d2d199aec8..f22af9f4963 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc
@@ -17,9 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_tex_checker_cc {
static void sh_node_tex_checker_declare(NodeDeclarationBuilder &b)
{
@@ -36,11 +36,9 @@ static void sh_node_tex_checker_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Fac"));
};
-} // namespace blender::nodes
-
static void node_shader_init_tex_checker(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexChecker *tex = (NodeTexChecker *)MEM_callocN(sizeof(NodeTexChecker), "NodeTexChecker");
+ NodeTexChecker *tex = MEM_cnew<NodeTexChecker>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
@@ -59,8 +57,6 @@ static int node_shader_gpu_tex_checker(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_tex_checker", in, out);
}
-namespace blender::nodes {
-
class NodeTexChecker : public fn::MultiFunction {
public:
NodeTexChecker()
@@ -121,19 +117,21 @@ static void sh_node_tex_checker_build_multi_function(
builder.set_matching_fn(fn);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_checker_cc
void register_node_type_sh_tex_checker()
{
+ namespace file_ns = blender::nodes::node_shader_tex_checker_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_CHECKER, "Checker Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_checker_declare;
- node_type_init(&ntype, node_shader_init_tex_checker);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_CHECKER, "Checker Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_checker_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_checker);
node_type_storage(
&ntype, "NodeTexChecker", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_checker);
- ntype.build_multi_function = blender::nodes::sh_node_tex_checker_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_checker);
+ ntype.build_multi_function = file_ns::sh_node_tex_checker_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc
index 4ce19bdc45e..9372d29456d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc
@@ -17,10 +17,12 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "DNA_customdata_types.h"
+namespace blender::nodes::node_shader_tex_coord_cc {
+
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_tex_coord_out[] = {
@@ -42,11 +44,12 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
{
Object *ob = (Object *)node->id;
- GPUNodeLink *inv_obmat = (ob != NULL) ? GPU_uniform(&ob->imat[0][0]) :
- GPU_builtin(GPU_INVERSE_OBJECT_MATRIX);
+ GPUNodeLink *inv_obmat = (ob != nullptr) ? GPU_uniform(&ob->imat[0][0]) :
+ GPU_builtin(GPU_INVERSE_OBJECT_MATRIX);
/* Opti: don't request orco if not needed. */
- GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant((float[4]){0.0f, 0.0f, 0.0f, 0.0f}) :
+ const float default_coords[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant(default_coords) :
GPU_attribute(mat, CD_ORCO, "");
GPUNodeLink *mtface = GPU_attribute(mat, CD_MTFACE, "");
GPUNodeLink *viewpos = GPU_builtin(GPU_VIEW_POSITION);
@@ -75,23 +78,25 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat,
out[i].link,
out[i].link,
&out[i].link,
- NULL);
+ nullptr);
}
}
return 1;
}
+} // namespace blender::nodes::node_shader_tex_coord_cc
+
/* node type definition */
-void register_node_type_sh_tex_coord(void)
+void register_node_type_sh_tex_coord()
{
+ namespace file_ns = blender::nodes::node_shader_tex_coord_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_COORD, "Texture Coordinate", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_tex_coord_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_tex_coord);
+ sh_node_type_base(&ntype, SH_NODE_TEX_COORD, "Texture Coordinate", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_tex_coord_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_coord);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc
index ff08961b3e9..aa96d075f7f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_tex_environment_cc {
/* **************** OUTPUT ******************** */
@@ -33,7 +35,7 @@ static bNodeSocketTemplate sh_node_tex_environment_out[] = {
static void node_shader_init_tex_environment(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexEnvironment *tex = MEM_callocN(sizeof(NodeTexEnvironment), "NodeTexEnvironment");
+ NodeTexEnvironment *tex = MEM_cnew<NodeTexEnvironment>("NodeTexEnvironment");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->projection = SHD_PROJ_EQUIRECTANGULAR;
@@ -49,12 +51,12 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
GPUNodeStack *out)
{
Image *ima = (Image *)node->id;
- NodeTexEnvironment *tex = node->storage;
+ NodeTexEnvironment *tex = (NodeTexEnvironment *)node->storage;
/* We get the image user from the original node, since GPU image keeps
* a pointer to it and the dependency refreshes the original. */
bNode *node_original = node->original ? node->original : node;
- NodeTexImage *tex_original = node_original->storage;
+ NodeTexImage *tex_original = (NodeTexImage *)node_original->storage;
ImageUser *iuser = &tex_original->iuser;
eGPUSamplerState sampler = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER;
/* TODO(fclem): For now assume mipmap is always enabled. */
@@ -132,17 +134,22 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
return true;
}
+} // namespace blender::nodes::node_shader_tex_environment_cc
+
/* node type definition */
-void register_node_type_sh_tex_environment(void)
+void register_node_type_sh_tex_environment()
{
+ namespace file_ns = blender::nodes::node_shader_tex_environment_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_ENVIRONMENT, "Environment Texture", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_environment_in, sh_node_tex_environment_out);
- node_type_init(&ntype, node_shader_init_tex_environment);
+ sh_node_type_base(&ntype, SH_NODE_TEX_ENVIRONMENT, "Environment Texture", NODE_CLASS_TEXTURE);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_tex_environment_in, file_ns::sh_node_tex_environment_out);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_environment);
node_type_storage(
&ntype, "NodeTexEnvironment", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_environment);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_environment);
ntype.labelfunc = node_image_label;
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
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 48199968547..2f47f214681 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc
@@ -17,9 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_tex_gradient_cc {
static void sh_node_tex_gradient_declare(NodeDeclarationBuilder &b)
{
@@ -29,12 +29,9 @@ static void sh_node_tex_gradient_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Fac")).no_muted_links();
};
-} // namespace blender::nodes
-
static void node_shader_init_tex_gradient(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexGradient *tex = (NodeTexGradient *)MEM_callocN(sizeof(NodeTexGradient),
- "NodeTexGradient");
+ NodeTexGradient *tex = MEM_cnew<NodeTexGradient>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->gradient_type = SHD_BLEND_LINEAR;
@@ -56,8 +53,6 @@ static int node_shader_gpu_tex_gradient(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_tex_gradient", in, out, GPU_constant(&gradient_type));
}
-namespace blender::nodes {
-
class GradientFunction : public fn::MultiFunction {
private:
int gradient_type_;
@@ -158,19 +153,21 @@ static void sh_node_gradient_tex_build_multi_function(
builder.construct_and_set_matching_fn<GradientFunction>(tex->gradient_type);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_gradient_cc
void register_node_type_sh_tex_gradient()
{
+ namespace file_ns = blender::nodes::node_shader_tex_gradient_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_GRADIENT, "Gradient Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_gradient_declare;
- node_type_init(&ntype, node_shader_init_tex_gradient);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_GRADIENT, "Gradient Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_gradient_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_gradient);
node_type_storage(
&ntype, "NodeTexGradient", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_gradient);
- ntype.build_multi_function = blender::nodes::sh_node_gradient_tex_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_gradient);
+ ntype.build_multi_function = file_ns::sh_node_gradient_tex_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
index d139707c6d7..745121691ac 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc
@@ -17,9 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_tex_image_cc {
static void sh_node_tex_image_declare(NodeDeclarationBuilder &b)
{
@@ -29,11 +29,9 @@ static void sh_node_tex_image_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Alpha")).no_muted_links();
};
-}; // namespace blender::nodes
-
static void node_shader_init_tex_image(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexImage *tex = (NodeTexImage *)MEM_callocN(sizeof(NodeTexImage), "NodeTexImage");
+ NodeTexImage *tex = MEM_cnew<NodeTexImage>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
BKE_imageuser_default(&tex->iuser);
@@ -173,17 +171,20 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
return true;
}
-/* node type definition */
+} // namespace blender::nodes::node_shader_tex_image_cc
+
void register_node_type_sh_tex_image()
{
+ namespace file_ns = blender::nodes::node_shader_tex_image_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_IMAGE, "Image Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_image_declare;
- node_type_init(&ntype, node_shader_init_tex_image);
+ sh_node_type_base(&ntype, SH_NODE_TEX_IMAGE, "Image Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_image_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_image);
node_type_storage(
&ntype, "NodeTexImage", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_image);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_image);
ntype.labelfunc = node_image_label;
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
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 9bd5c335cee..b388f1a3172 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc
@@ -17,9 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_tex_magic_cc {
static void sh_node_tex_magic_declare(NodeDeclarationBuilder &b)
{
@@ -31,11 +31,9 @@ static void sh_node_tex_magic_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Fac")).no_muted_links();
};
-} // namespace blender::nodes
-
static void node_shader_init_tex_magic(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexMagic *tex = (NodeTexMagic *)MEM_callocN(sizeof(NodeTexMagic), "NodeTexMagic");
+ NodeTexMagic *tex = MEM_cnew<NodeTexMagic>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->depth = 2;
@@ -58,8 +56,6 @@ static int node_shader_gpu_tex_magic(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_tex_magic", in, out, GPU_constant(&depth));
}
-namespace blender::nodes {
-
class MagicFunction : public fn::MultiFunction {
private:
int depth_;
@@ -179,19 +175,21 @@ static void sh_node_magic_tex_build_multi_function(
builder.construct_and_set_matching_fn<MagicFunction>(tex->depth);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_magic_cc
void register_node_type_sh_tex_magic()
{
+ namespace file_ns = blender::nodes::node_shader_tex_magic_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_MAGIC, "Magic Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_magic_declare;
- node_type_init(&ntype, node_shader_init_tex_magic);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_MAGIC, "Magic Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_magic_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_magic);
node_type_storage(
&ntype, "NodeTexMagic", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_magic);
- ntype.build_multi_function = blender::nodes::sh_node_magic_tex_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_magic);
+ ntype.build_multi_function = file_ns::sh_node_magic_tex_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
index 97ac199bc03..94713ad24ba 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc
@@ -17,13 +17,13 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_noise.hh"
-NODE_STORAGE_FUNCS(NodeTexMusgrave)
+namespace blender::nodes::node_shader_tex_musgrave_cc {
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeTexMusgrave)
static void sh_node_tex_musgrave_declare(NodeDeclarationBuilder &b)
{
@@ -42,12 +42,9 @@ static void sh_node_tex_musgrave_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Fac")).no_muted_links();
};
-} // namespace blender::nodes
-
static void node_shader_init_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexMusgrave *tex = (NodeTexMusgrave *)MEM_callocN(sizeof(NodeTexMusgrave),
- "NodeTexMusgrave");
+ NodeTexMusgrave *tex = MEM_cnew<NodeTexMusgrave>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->musgrave_type = SHD_MUSGRAVE_FBM;
@@ -133,8 +130,6 @@ static void node_shader_update_tex_musgrave(bNodeTree *ntree, bNode *node)
node_sock_label(outFacSock, "Height");
}
-namespace blender::nodes {
-
class MusgraveFunction : public fn::MultiFunction {
private:
const int dimensions_;
@@ -524,7 +519,7 @@ class MusgraveFunction : public fn::MultiFunction {
}
}
}
-}; // namespace blender::nodes
+};
static void sh_node_musgrave_build_multi_function(
blender::nodes::NodeMultiFunctionBuilder &builder)
@@ -534,21 +529,23 @@ static void sh_node_musgrave_build_multi_function(
builder.construct_and_set_matching_fn<MusgraveFunction>(tex->dimensions, tex->musgrave_type);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_musgrave_cc
void register_node_type_sh_tex_musgrave()
{
+ namespace file_ns = blender::nodes::node_shader_tex_musgrave_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_MUSGRAVE, "Musgrave Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_musgrave_declare;
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_MUSGRAVE, "Musgrave Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_musgrave_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tex_musgrave);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_musgrave);
node_type_storage(
&ntype, "NodeTexMusgrave", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_musgrave);
- node_type_update(&ntype, node_shader_update_tex_musgrave);
- ntype.build_multi_function = blender::nodes::sh_node_musgrave_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_musgrave);
+ node_type_update(&ntype, file_ns::node_shader_update_tex_musgrave);
+ ntype.build_multi_function = file_ns::sh_node_musgrave_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
index d7f21853a01..fe402675ec6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc
@@ -17,13 +17,13 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_noise.hh"
-NODE_STORAGE_FUNCS(NodeTexNoise)
+namespace blender::nodes::node_shader_tex_noise_cc {
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeTexNoise)
static void sh_node_tex_noise_declare(NodeDeclarationBuilder &b)
{
@@ -45,11 +45,9 @@ static void sh_node_tex_noise_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Color")).no_muted_links();
};
-} // namespace blender::nodes
-
static void node_shader_init_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexNoise *tex = (NodeTexNoise *)MEM_callocN(sizeof(NodeTexNoise), "NodeTexNoise");
+ NodeTexNoise *tex = MEM_cnew<NodeTexNoise>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->dimensions = 3;
@@ -91,8 +89,6 @@ static void node_shader_update_tex_noise(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, sockW, storage.dimensions == 1 || storage.dimensions == 4);
}
-namespace blender::nodes {
-
class NoiseFunction : public fn::MultiFunction {
private:
int dimensions_;
@@ -250,21 +246,22 @@ static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunction
builder.construct_and_set_matching_fn<NoiseFunction>(storage.dimensions);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_noise_cc
-/* node type definition */
void register_node_type_sh_tex_noise()
{
+ namespace file_ns = blender::nodes::node_shader_tex_noise_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_noise_declare;
- node_type_init(&ntype, node_shader_init_tex_noise);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_noise_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_noise);
node_type_storage(
&ntype, "NodeTexNoise", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_noise);
- node_type_update(&ntype, node_shader_update_tex_noise);
- ntype.build_multi_function = blender::nodes::sh_node_noise_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_noise);
+ node_type_update(&ntype, file_ns::node_shader_update_tex_noise);
+ ntype.build_multi_function = file_ns::sh_node_noise_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.cc
index 14cd1fd4c0c..31d14d09963 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.cc
@@ -17,10 +17,12 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "RE_texture.h"
+namespace blender::nodes::node_shader_tex_pointdensity_cc {
+
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_tex_pointdensity_in[] = {
@@ -36,8 +38,7 @@ static bNodeSocketTemplate sh_node_tex_pointdensity_out[] = {
static void node_shader_init_tex_pointdensity(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderTexPointDensity *point_density = MEM_callocN(sizeof(NodeShaderTexPointDensity),
- "new pd node");
+ NodeShaderTexPointDensity *point_density = MEM_cnew<NodeShaderTexPointDensity>("new pd node");
point_density->resolution = 100;
point_density->radius = 0.3f;
point_density->space = SHD_POINTDENSITY_SPACE_OBJECT;
@@ -47,7 +48,7 @@ static void node_shader_init_tex_pointdensity(bNodeTree *UNUSED(ntree), bNode *n
static void node_shader_free_tex_pointdensity(bNode *node)
{
- NodeShaderTexPointDensity *point_density = node->storage;
+ NodeShaderTexPointDensity *point_density = (NodeShaderTexPointDensity *)node->storage;
PointDensity *pd = &point_density->pd;
RE_point_density_free(pd);
BKE_texture_pointdensity_free_data(pd);
@@ -60,23 +61,28 @@ static void node_shader_copy_tex_pointdensity(bNodeTree *UNUSED(dest_ntree),
const bNode *src_node)
{
dest_node->storage = MEM_dupallocN(src_node->storage);
- NodeShaderTexPointDensity *point_density = dest_node->storage;
+ NodeShaderTexPointDensity *point_density = (NodeShaderTexPointDensity *)dest_node->storage;
PointDensity *pd = &point_density->pd;
memset(pd, 0, sizeof(*pd));
}
+} // namespace blender::nodes::node_shader_tex_pointdensity_cc
+
/* node type definition */
-void register_node_type_sh_tex_pointdensity(void)
+void register_node_type_sh_tex_pointdensity()
{
+ namespace file_ns = blender::nodes::node_shader_tex_pointdensity_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_POINTDENSITY, "Point Density", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_pointdensity_in, sh_node_tex_pointdensity_out);
- node_type_init(&ntype, node_shader_init_tex_pointdensity);
+ sh_node_type_base(&ntype, SH_NODE_TEX_POINTDENSITY, "Point Density", NODE_CLASS_TEXTURE);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_tex_pointdensity_in, file_ns::sh_node_tex_pointdensity_out);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_pointdensity);
node_type_storage(&ntype,
"NodeShaderTexPointDensity",
- node_shader_free_tex_pointdensity,
- node_shader_copy_tex_pointdensity);
+ file_ns::node_shader_free_tex_pointdensity,
+ file_ns::node_shader_copy_tex_pointdensity);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
index 5c581528c14..56e42708e93 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc
@@ -17,9 +17,11 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "sky_model.h"
+namespace blender::nodes::node_shader_tex_sky_cc {
+
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_tex_sky_in[] = {
@@ -34,7 +36,7 @@ static bNodeSocketTemplate sh_node_tex_sky_out[] = {
static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexSky *tex = MEM_callocN(sizeof(NodeTexSky), "NodeTexSky");
+ NodeTexSky *tex = MEM_cnew<NodeTexSky>("NodeTexSky");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->sun_direction[0] = 0.0f;
@@ -55,10 +57,10 @@ static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = tex;
}
-typedef struct SkyModelPreetham {
+struct SkyModelPreetham {
float config_Y[5], config_x[5], config_y[5]; /* named after xyY color space */
float radiance[3];
-} SkyModelPreetham;
+};
static float sky_perez_function(const float *lam, float theta, float gamma)
{
@@ -203,19 +205,23 @@ static void node_shader_update_sky(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1));
}
+} // namespace blender::nodes::node_shader_tex_sky_cc
+
/* node type definition */
-void register_node_type_sh_tex_sky(void)
+void register_node_type_sh_tex_sky()
{
+ namespace file_ns = blender::nodes::node_shader_tex_sky_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_TEX_SKY, "Sky Texture", NODE_CLASS_TEXTURE, 0);
- node_type_socket_templates(&ntype, sh_node_tex_sky_in, sh_node_tex_sky_out);
+ sh_node_type_base(&ntype, SH_NODE_TEX_SKY, "Sky Texture", NODE_CLASS_TEXTURE);
+ node_type_socket_templates(&ntype, file_ns::sh_node_tex_sky_in, file_ns::sh_node_tex_sky_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tex_sky);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_sky);
node_type_storage(&ntype, "NodeTexSky", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_sky);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_sky);
/* remove Vector input for Nishita */
- node_type_update(&ntype, node_shader_update_sky);
+ node_type_update(&ntype, file_ns::node_shader_update_sky);
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 8a1170de304..72f7fe08a15 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc
@@ -17,13 +17,13 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_noise.hh"
-NODE_STORAGE_FUNCS(NodeTexVoronoi)
+namespace blender::nodes::node_shader_tex_voronoi_cc {
-namespace blender::nodes {
+NODE_STORAGE_FUNCS(NodeTexVoronoi)
static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b)
{
@@ -62,11 +62,9 @@ static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b)
});
};
-} // namespace blender::nodes
-
static void node_shader_init_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexVoronoi *tex = (NodeTexVoronoi *)MEM_callocN(sizeof(NodeTexVoronoi), "NodeTexVoronoi");
+ NodeTexVoronoi *tex = MEM_cnew<NodeTexVoronoi>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->dimensions = 3;
@@ -181,8 +179,6 @@ static void node_shader_update_tex_voronoi(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, outRadiusSock, storage.feature == SHD_VORONOI_N_SPHERE_RADIUS);
}
-namespace blender::nodes {
-
static MultiFunction::ExecutionHints voronoi_execution_hints{50, false};
class VoronoiMinowskiFunction : public fn::MultiFunction {
@@ -1340,20 +1336,22 @@ static void sh_node_voronoi_build_multi_function(blender::nodes::NodeMultiFuncti
}
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_voronoi_cc
void register_node_type_sh_tex_voronoi()
{
+ namespace file_ns = blender::nodes::node_shader_tex_voronoi_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_VORONOI, "Voronoi Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_voronoi_declare;
- node_type_init(&ntype, node_shader_init_tex_voronoi);
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_VORONOI, "Voronoi Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_voronoi_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_voronoi);
node_type_storage(
&ntype, "NodeTexVoronoi", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_voronoi);
- node_type_update(&ntype, node_shader_update_tex_voronoi);
- ntype.build_multi_function = blender::nodes::sh_node_voronoi_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_voronoi);
+ node_type_update(&ntype, file_ns::node_shader_update_tex_voronoi);
+ ntype.build_multi_function = file_ns::sh_node_voronoi_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
index d3e25b533e5..9a3e214333b 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc
@@ -17,11 +17,11 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_noise.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_tex_wave_cc {
static void sh_node_tex_wave_declare(NodeDeclarationBuilder &b)
{
@@ -41,11 +41,9 @@ static void sh_node_tex_wave_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Fac")).no_muted_links();
};
-} // namespace blender::nodes
-
static void node_shader_init_tex_wave(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeTexWave *tex = (NodeTexWave *)MEM_callocN(sizeof(NodeTexWave), "NodeTexWave");
+ NodeTexWave *tex = MEM_cnew<NodeTexWave>(__func__);
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->wave_type = SHD_WAVE_BANDS;
@@ -81,8 +79,6 @@ static int node_shader_gpu_tex_wave(GPUMaterial *mat,
GPU_constant(&wave_profile));
}
-namespace blender::nodes {
-
class WaveFunction : public fn::MultiFunction {
private:
int wave_type_;
@@ -216,19 +212,21 @@ static void sh_node_wave_tex_build_multi_function(
tex->wave_type, tex->bands_direction, tex->rings_direction, tex->wave_profile);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_wave_cc
void register_node_type_sh_tex_wave()
{
+ namespace file_ns = blender::nodes::node_shader_tex_wave_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_TEX_WAVE, "Wave Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_wave_declare;
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_WAVE, "Wave Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_wave_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_tex_wave);
+ node_type_init(&ntype, file_ns::node_shader_init_tex_wave);
node_type_storage(&ntype, "NodeTexWave", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_tex_wave);
- ntype.build_multi_function = blender::nodes::sh_node_wave_tex_build_multi_function;
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_wave);
+ ntype.build_multi_function = file_ns::sh_node_wave_tex_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc
index 0e72cee38e7..96d45d7c53b 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
@@ -17,11 +17,11 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "BLI_noise.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_tex_white_noise_cc {
static void sh_node_tex_white_noise_declare(NodeDeclarationBuilder &b)
{
@@ -35,8 +35,6 @@ static void sh_node_tex_white_noise_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>(N_("Color"));
};
-} // namespace blender::nodes
-
static void node_shader_init_tex_white_noise(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = 3;
@@ -70,8 +68,6 @@ static void node_shader_update_tex_white_noise(bNodeTree *ntree, bNode *node)
nodeSetSocketAvailability(ntree, sockW, node->custom1 == 1 || node->custom1 == 4);
}
-namespace blender::nodes {
-
class WhiteNoiseFunction : public fn::MultiFunction {
private:
int dimensions_;
@@ -192,19 +188,20 @@ static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunction
builder.construct_and_set_matching_fn<WhiteNoiseFunction>((int)node.custom1);
}
-} // namespace blender::nodes
+} // namespace blender::nodes::node_shader_tex_white_noise_cc
void register_node_type_sh_tex_white_noise()
{
+ namespace file_ns = blender::nodes::node_shader_tex_white_noise_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(
- &ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE, 0);
- ntype.declare = blender::nodes::sh_node_tex_white_noise_declare;
- node_type_init(&ntype, node_shader_init_tex_white_noise);
- node_type_gpu(&ntype, gpu_shader_tex_white_noise);
- node_type_update(&ntype, node_shader_update_tex_white_noise);
- ntype.build_multi_function = blender::nodes::sh_node_noise_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE);
+ ntype.declare = file_ns::sh_node_tex_white_noise_declare;
+ node_type_init(&ntype, file_ns::node_shader_init_tex_white_noise);
+ node_type_gpu(&ntype, file_ns::gpu_shader_tex_white_noise);
+ node_type_update(&ntype, file_ns::node_shader_update_tex_white_noise);
+ ntype.build_multi_function = file_ns::sh_node_noise_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc
index 05c3248af65..1b9bc60b6ea 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c
+++ b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_uv_along_stroke_cc {
/* **************** OUTPUT ******************** */
@@ -26,14 +28,17 @@ static bNodeSocketTemplate sh_node_uvalongstroke_out[] = {
{-1, ""},
};
+} // namespace blender::nodes::node_shader_uv_along_stroke_cc
+
/* node type definition */
-void register_node_type_sh_uvalongstroke(void)
+void register_node_type_sh_uvalongstroke()
{
+ namespace file_ns = blender::nodes::node_shader_uv_along_stroke_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_UVALONGSTROKE, "UV Along Stroke", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_uvalongstroke_out);
- node_type_init(&ntype, NULL);
+ sh_node_type_base(&ntype, SH_NODE_UVALONGSTROKE, "UV Along Stroke", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_uvalongstroke_out);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.c b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc
index 775b8ffbc06..9d1e02ee919 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uvmap.c
+++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc
@@ -17,10 +17,12 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
#include "DNA_customdata_types.h"
+namespace blender::nodes::node_shader_uvmap_cc {
+
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_uvmap_out[] = {
@@ -30,7 +32,7 @@ static bNodeSocketTemplate sh_node_uvmap_out[] = {
static void node_shader_init_uvmap(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderUVMap *attr = MEM_callocN(sizeof(NodeShaderUVMap), "NodeShaderUVMap");
+ NodeShaderUVMap *attr = MEM_cnew<NodeShaderUVMap>("NodeShaderUVMap");
node->storage = attr;
}
@@ -40,7 +42,7 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
- NodeShaderUVMap *attr = node->storage;
+ NodeShaderUVMap *attr = static_cast<NodeShaderUVMap *>(node->storage);
GPUNodeLink *mtface = GPU_attribute(mat, CD_MTFACE, attr->uv_map);
GPU_stack_link(mat, node, "node_uvmap", in, out, mtface);
@@ -50,18 +52,22 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat,
return 1;
}
+} // namespace blender::nodes::node_shader_uvmap_cc
+
/* node type definition */
-void register_node_type_sh_uvmap(void)
+void register_node_type_sh_uvmap()
{
+ namespace file_ns = blender::nodes::node_shader_uvmap_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_UVMAP, "UV Map", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_uvmap_out);
+ sh_node_type_base(&ntype, SH_NODE_UVMAP, "UV Map", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_uvmap_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, node_shader_init_uvmap);
+ node_type_init(&ntype, file_ns::node_shader_init_uvmap);
node_type_storage(
&ntype, "NodeShaderUVMap", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_uvmap);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_uvmap);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc
index f0eb3ea9bee..21f2e072990 100644
--- a/source/blender/nodes/shader/nodes/node_shader_value.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_value.cc
@@ -21,17 +21,15 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_value_cc {
static void sh_node_value_declare(NodeDeclarationBuilder &b)
{
b.add_output<decl::Float>(N_("Value"));
};
-} // namespace blender::nodes
-
static int gpu_shader_value(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
@@ -49,14 +47,18 @@ static void sh_node_value_build_multi_function(blender::nodes::NodeMultiFunction
builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value);
}
+} // namespace blender::nodes::node_shader_value_cc
+
void register_node_type_sh_value()
{
+ namespace file_ns = blender::nodes::node_shader_value_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0);
- ntype.declare = blender::nodes::sh_node_value_declare;
- node_type_gpu(&ntype, gpu_shader_value);
- ntype.build_multi_function = sh_node_value_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT);
+ ntype.declare = file_ns::sh_node_value_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_value);
+ ntype.build_multi_function = file_ns::sh_node_value_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc
index 0e82f346529..fbdb7177a93 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_vector_displacement_cc {
/* **************** OUTPUT ******************** */
@@ -63,18 +65,21 @@ static int gpu_shader_vector_displacement(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_vector_displacement_world", in, out);
}
+} // namespace blender::nodes::node_shader_vector_displacement_cc
+
/* node type definition */
-void register_node_type_sh_vector_displacement(void)
+void register_node_type_sh_vector_displacement()
{
+ namespace file_ns = blender::nodes::node_shader_vector_displacement_cc;
+
static bNodeType ntype;
sh_node_type_base(
- &ntype, SH_NODE_VECTOR_DISPLACEMENT, "Vector Displacement", NODE_CLASS_OP_VECTOR, 0);
+ &ntype, SH_NODE_VECTOR_DISPLACEMENT, "Vector Displacement", NODE_CLASS_OP_VECTOR);
node_type_socket_templates(
- &ntype, sh_node_vector_displacement_in, sh_node_vector_displacement_out);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_init(&ntype, node_shader_init_vector_displacement);
- node_type_gpu(&ntype, gpu_shader_vector_displacement);
+ &ntype, file_ns::sh_node_vector_displacement_in, file_ns::sh_node_vector_displacement_out);
+ node_type_init(&ntype, file_ns::node_shader_init_vector_displacement);
+ node_type_gpu(&ntype, file_ns::gpu_shader_vector_displacement);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
index 5f5969de78c..1276592e2af 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc
@@ -21,12 +21,14 @@
* \ingroup shdnodes
*/
-#include "node_shader_util.h"
+#include "node_shader_util.hh"
#include "NOD_math_functions.hh"
#include "NOD_socket_search_link.hh"
-namespace blender::nodes {
+#include "RNA_enum_types.h"
+
+namespace blender::nodes::node_shader_vector_math_cc {
static void sh_node_vector_math_declare(NodeDeclarationBuilder &b)
{
@@ -39,19 +41,46 @@ static void sh_node_vector_math_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Float>(N_("Value"));
};
+class SocketSearchOp {
+ public:
+ std::string socket_name;
+ NodeVectorMathOperation mode = NODE_VECTOR_MATH_ADD;
+ void operator()(LinkSearchOpParams &params)
+ {
+ bNode &node = params.add_node("ShaderNodeVectorMath");
+ node.custom1 = mode;
+ params.update_and_connect_available_socket(node, socket_name);
+ }
+};
+
static void sh_node_vector_math_gather_link_searches(GatherLinkSearchOpParams &params)
{
- /* For now, do something very basic (only exposing "Add", and a single "Vector" socket). */
- if (params.node_tree().typeinfo->validate_link(
+ if (!params.node_tree().typeinfo->validate_link(
static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_VECTOR)) {
- params.add_item(IFACE_("Vector"), [](LinkSearchOpParams &params) {
- bNode &node = params.add_node("ShaderNodeVectorMath");
- params.update_and_connect_available_socket(node, "Vector");
- });
+ return;
}
-}
-} // namespace blender::nodes
+ const int weight = ELEM(params.other_socket().type, SOCK_VECTOR, SOCK_RGBA) ? 0 : -1;
+
+ for (const EnumPropertyItem *item = rna_enum_node_vec_math_items; item->identifier != nullptr;
+ item++) {
+ if (item->name != nullptr && item->identifier[0] != '\0') {
+ if ((params.in_out() == SOCK_OUT) && ELEM(item->value,
+ NODE_VECTOR_MATH_LENGTH,
+ NODE_VECTOR_MATH_DISTANCE,
+ NODE_VECTOR_MATH_DOT_PRODUCT)) {
+ params.add_item(IFACE_(item->name),
+ SocketSearchOp{"Value", (NodeVectorMathOperation)item->value},
+ weight);
+ }
+ else {
+ params.add_item(IFACE_(item->name),
+ SocketSearchOp{"Vector", (NodeVectorMathOperation)item->value},
+ weight);
+ }
+ }
+ }
+}
static const char *gpu_shader_get_name(int mode)
{
@@ -292,17 +321,21 @@ static void sh_node_vector_math_build_multi_function(
builder.set_matching_fn(fn);
}
+} // namespace blender::nodes::node_shader_vector_math_cc
+
void register_node_type_sh_vect_math()
{
+ namespace file_ns = blender::nodes::node_shader_vector_math_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR, 0);
- ntype.declare = blender::nodes::sh_node_vector_math_declare;
+ sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::sh_node_vector_math_declare;
ntype.labelfunc = node_vector_math_label;
- node_type_gpu(&ntype, gpu_shader_vector_math);
- node_type_update(&ntype, node_shader_update_vector_math);
- ntype.build_multi_function = sh_node_vector_math_build_multi_function;
- ntype.gather_link_search_ops = blender::nodes::sh_node_vector_math_gather_link_searches;
+ node_type_gpu(&ntype, file_ns::gpu_shader_vector_math);
+ node_type_update(&ntype, file_ns::node_shader_update_vector_math);
+ ntype.build_multi_function = file_ns::sh_node_vector_math_build_multi_function;
+ ntype.gather_link_search_ops = file_ns::sh_node_vector_math_gather_link_searches;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
index a3cb82f3245..bb7a81ef5d8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc
@@ -21,9 +21,9 @@
* \ingroup shdnodes
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-namespace blender::nodes {
+namespace blender::nodes::node_shader_vector_rotate_cc {
static void sh_node_vector_rotate_declare(NodeDeclarationBuilder &b)
{
@@ -36,8 +36,6 @@ static void sh_node_vector_rotate_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Vector>(N_("Vector"));
};
-} // namespace blender::nodes
-
static const char *gpu_shader_get_name(int mode)
{
switch (mode) {
@@ -205,15 +203,19 @@ static void node_shader_update_vector_rotate(bNodeTree *ntree, bNode *node)
ntree, sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ));
}
+} // namespace blender::nodes::node_shader_vector_rotate_cc
+
void register_node_type_sh_vector_rotate()
{
+ namespace file_ns = blender::nodes::node_shader_vector_rotate_cc;
+
static bNodeType ntype;
- sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR, 0);
- ntype.declare = blender::nodes::sh_node_vector_rotate_declare;
- node_type_gpu(&ntype, gpu_shader_vector_rotate);
- node_type_update(&ntype, node_shader_update_vector_rotate);
- ntype.build_multi_function = sh_node_vector_rotate_build_multi_function;
+ sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR);
+ ntype.declare = file_ns::sh_node_vector_rotate_declare;
+ node_type_gpu(&ntype, file_ns::gpu_shader_vector_rotate);
+ node_type_update(&ntype, file_ns::node_shader_update_vector_rotate);
+ ntype.build_multi_function = file_ns::sh_node_vector_rotate_build_multi_function;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_transform.c b/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc
index 7b08178f874..fc1c4c3abf7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vector_transform.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc
@@ -21,7 +21,9 @@
* \ingroup shdnodes
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_vector_transform_cc {
/* **************** Vector Transform ******************** */
static bNodeSocketTemplate sh_node_vect_transform_in[] = {
@@ -34,8 +36,7 @@ static bNodeSocketTemplate sh_node_vect_transform_out[] = {
static void node_shader_init_vect_transform(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderVectTransform *vect = MEM_callocN(sizeof(NodeShaderVectTransform),
- "NodeShaderVectTransform");
+ NodeShaderVectTransform *vect = MEM_cnew<NodeShaderVectTransform>("NodeShaderVectTransform");
/* Convert World into Object Space per default */
vect->convert_to = 1;
@@ -58,7 +59,7 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
switch (to) {
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
- return NULL;
+ return nullptr;
case SHD_VECT_TRANSFORM_SPACE_WORLD:
return GPU_builtin(GPU_OBJECT_MATRIX);
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
@@ -68,7 +69,7 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
case SHD_VECT_TRANSFORM_SPACE_WORLD:
switch (to) {
case SHD_VECT_TRANSFORM_SPACE_WORLD:
- return NULL;
+ return nullptr;
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
return GPU_builtin(GPU_VIEW_MATRIX);
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
@@ -78,7 +79,7 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
switch (to) {
case SHD_VECT_TRANSFORM_SPACE_CAMERA:
- return NULL;
+ return nullptr;
case SHD_VECT_TRANSFORM_SPACE_WORLD:
return GPU_builtin(GPU_INVERSE_VIEW_MATRIX);
case SHD_VECT_TRANSFORM_SPACE_OBJECT:
@@ -86,7 +87,7 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to)
}
break;
}
- return NULL;
+ return nullptr;
}
static int gpu_shader_vect_transform(GPUMaterial *mat,
bNode *node,
@@ -99,7 +100,7 @@ static int gpu_shader_vect_transform(GPUMaterial *mat,
const char *vtransform = "direction_transform_m4v3";
const char *ptransform = "point_transform_m4v3";
- const char *func_name = 0;
+ const char *func_name = nullptr;
NodeShaderVectTransform *nodeprop = (NodeShaderVectTransform *)node->storage;
@@ -137,17 +138,22 @@ static int gpu_shader_vect_transform(GPUMaterial *mat,
return true;
}
-void register_node_type_sh_vect_transform(void)
+} // namespace blender::nodes::node_shader_vector_transform_cc
+
+void register_node_type_sh_vect_transform()
{
+ namespace file_ns = blender::nodes::node_shader_vector_transform_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VECT_TRANSFORM, "Vector Transform", NODE_CLASS_OP_VECTOR, 0);
- node_type_init(&ntype, node_shader_init_vect_transform);
- node_type_socket_templates(&ntype, sh_node_vect_transform_in, sh_node_vect_transform_out);
+ sh_node_type_base(&ntype, SH_NODE_VECT_TRANSFORM, "Vector Transform", NODE_CLASS_OP_VECTOR);
+ node_type_init(&ntype, file_ns::node_shader_init_vect_transform);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_vect_transform_in, file_ns::sh_node_vect_transform_out);
node_type_storage(
&ntype, "NodeShaderVectTransform", node_free_standard_storage, node_copy_standard_storage);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_vect_transform);
- node_type_gpu(&ntype, gpu_shader_vect_transform);
+ node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_vect_transform);
+ node_type_gpu(&ntype, file_ns::gpu_shader_vect_transform);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vertex_color.c b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
index 40576b68dd5..849d2bf58bb 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vertex_color.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_vertex_color_cc {
static bNodeSocketTemplate sh_node_vertex_color_out[] = {
{SOCK_RGBA, N_("Color")},
@@ -27,8 +29,7 @@ static bNodeSocketTemplate sh_node_vertex_color_out[] = {
static void node_shader_init_vertex_color(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeShaderVertexColor *vertexColor = MEM_callocN(sizeof(NodeShaderVertexColor),
- "NodeShaderVertexColor");
+ NodeShaderVertexColor *vertexColor = MEM_cnew<NodeShaderVertexColor>("NodeShaderVertexColor");
node->storage = vertexColor;
}
@@ -47,16 +48,20 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
}
-void register_node_type_sh_vertex_color(void)
+} // namespace blender::nodes::node_shader_vertex_color_cc
+
+void register_node_type_sh_vertex_color()
{
+ namespace file_ns = blender::nodes::node_shader_vertex_color_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VERTEX_COLOR, "Vertex Color", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_vertex_color_out);
- node_type_init(&ntype, node_shader_init_vertex_color);
+ sh_node_type_base(&ntype, SH_NODE_VERTEX_COLOR, "Vertex Color", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_vertex_color_out);
+ node_type_init(&ntype, file_ns::node_shader_init_vertex_color);
node_type_storage(
&ntype, "NodeShaderVertexColor", node_free_standard_storage, node_copy_standard_storage);
- node_type_gpu(&ntype, node_shader_gpu_vertex_color);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_vertex_color);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc
index abf2e63e6d5..cd697c96d66 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_volume_absorption_cc {
/* **************** OUTPUT ******************** */
@@ -41,16 +43,19 @@ static int node_shader_gpu_volume_absorption(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_volume_absorption", in, out);
}
+} // namespace blender::nodes::node_shader_volume_absorption_cc
+
/* node type definition */
-void register_node_type_sh_volume_absorption(void)
+void register_node_type_sh_volume_absorption()
{
+ namespace file_ns = blender::nodes::node_shader_volume_absorption_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VOLUME_ABSORPTION, "Volume Absorption", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_volume_absorption_in, sh_node_volume_absorption_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_volume_absorption);
+ sh_node_type_base(&ntype, SH_NODE_VOLUME_ABSORPTION, "Volume Absorption", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_volume_absorption_in, file_ns::sh_node_volume_absorption_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_absorption);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_info.c b/source/blender/nodes/shader/nodes/node_shader_volume_info.cc
index 6cafc991e13..53458ed962c 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_info.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_volume_info_cc {
static bNodeSocketTemplate sh_node_volume_info_out[] = {
{SOCK_RGBA, N_("Color")},
@@ -49,13 +51,17 @@ static int node_shader_gpu_volume_info(GPUMaterial *mat,
return true;
}
-void register_node_type_sh_volume_info(void)
+} // namespace blender::nodes::node_shader_volume_info_cc
+
+void register_node_type_sh_volume_info()
{
+ namespace file_ns = blender::nodes::node_shader_volume_info_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VOLUME_INFO, "Volume Info", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, NULL, sh_node_volume_info_out);
- node_type_gpu(&ntype, node_shader_gpu_volume_info);
+ sh_node_type_base(&ntype, SH_NODE_VOLUME_INFO, "Volume Info", NODE_CLASS_INPUT);
+ node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_volume_info_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
index 1a25aec5cb8..3acf8c35ac1 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_volume_principled_cc {
/* **************** OUTPUT ******************** */
@@ -64,14 +66,14 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
bool use_blackbody = (in[8].link || in[8].vec[0] != 0.0f);
/* Get volume attributes. */
- GPUNodeLink *density = NULL, *color = NULL, *temperature = NULL;
+ GPUNodeLink *density = nullptr, *color = nullptr, *temperature = nullptr;
LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
if (sock->typeinfo->type != SOCK_STRING) {
continue;
}
- bNodeSocketValueString *value = sock->default_value;
+ bNodeSocketValueString *value = (bNodeSocketValueString *)sock->default_value;
const char *attribute_name = value->value;
if (attribute_name[0] == '\0') {
continue;
@@ -106,11 +108,11 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
const int size = CM_TABLE + 1;
float *data, layer;
if (use_blackbody) {
- data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
+ data = (float *)MEM_mallocN(sizeof(float) * size * 4, "blackbody texture");
blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f);
}
else {
- data = MEM_callocN(sizeof(float) * size * 4, "blackbody black");
+ data = (float *)MEM_callocN(sizeof(float) * size * 4, "blackbody black");
}
GPUNodeLink *spectrummap = GPU_color_band(mat, size, data, &layer);
@@ -126,17 +128,21 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
GPU_constant(&layer));
}
+} // namespace blender::nodes::node_shader_volume_principled_cc
+
/* node type definition */
-void register_node_type_sh_volume_principled(void)
+void register_node_type_sh_volume_principled()
{
+ namespace file_ns = blender::nodes::node_shader_volume_principled_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VOLUME_PRINCIPLED, "Principled Volume", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_volume_principled_in, sh_node_volume_principled_out);
+ sh_node_type_base(&ntype, SH_NODE_VOLUME_PRINCIPLED, "Principled Volume", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_volume_principled_in, file_ns::sh_node_volume_principled_out);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
- node_type_init(&ntype, node_shader_init_volume_principled);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_volume_principled);
+ node_type_init(&ntype, file_ns::node_shader_init_volume_principled);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_principled);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc
index f4cfe7729ca..e07087e8529 100644
--- a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_volume_scatter_cc {
/* **************** OUTPUT ******************** */
@@ -42,16 +44,19 @@ static int node_shader_gpu_volume_scatter(GPUMaterial *mat,
return GPU_stack_link(mat, node, "node_volume_scatter", in, out);
}
+} // namespace blender::nodes::node_shader_volume_scatter_cc
+
/* node type definition */
-void register_node_type_sh_volume_scatter(void)
+void register_node_type_sh_volume_scatter()
{
+ namespace file_ns = blender::nodes::node_shader_volume_scatter_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VOLUME_SCATTER, "Volume Scatter", NODE_CLASS_SHADER, 0);
- node_type_socket_templates(&ntype, sh_node_volume_scatter_in, sh_node_volume_scatter_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_volume_scatter);
+ sh_node_type_base(&ntype, SH_NODE_VOLUME_SCATTER, "Volume Scatter", NODE_CLASS_SHADER);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_volume_scatter_in, file_ns::sh_node_volume_scatter_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_scatter);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_wavelength.c b/source/blender/nodes/shader/nodes/node_shader_wavelength.cc
index f978537ee85..a67c7830edd 100644
--- a/source/blender/nodes/shader/nodes/node_shader_wavelength.c
+++ b/source/blender/nodes/shader/nodes/node_shader_wavelength.cc
@@ -17,18 +17,15 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
-/* **************** Wavelength ******************** */
-static bNodeSocketTemplate sh_node_wavelength_in[] = {
- {SOCK_FLOAT, N_("Wavelength"), 500.0f, 0.0f, 0.0f, 0.0f, 380.0f, 780.0f},
- {-1, ""},
-};
+namespace blender::nodes::node_shader_wavelength_cc {
-static bNodeSocketTemplate sh_node_wavelength_out[] = {
- {SOCK_RGBA, N_("Color")},
- {-1, ""},
-};
+static void node_declare(NodeDeclarationBuilder &b)
+{
+ b.add_input<decl::Float>(N_("Wavelength")).default_value(500.0f).min(380.0f).max(780.0f);
+ b.add_output<decl::Color>(N_("Color"));
+}
static int node_shader_gpu_wavelength(GPUMaterial *mat,
bNode *node,
@@ -37,7 +34,7 @@ static int node_shader_gpu_wavelength(GPUMaterial *mat,
GPUNodeStack *out)
{
const int size = CM_TABLE + 1;
- float *data = MEM_mallocN(sizeof(float) * size * 4, "cie_xyz texture");
+ float *data = static_cast<float *>(MEM_mallocN(sizeof(float) * size * 4, "cie_xyz texture"));
wavelength_to_xyz_table(data, size);
@@ -57,17 +54,19 @@ static int node_shader_gpu_wavelength(GPUMaterial *mat,
GPU_uniform(xyz_to_rgb.b));
}
+} // namespace blender::nodes::node_shader_wavelength_cc
+
/* node type definition */
-void register_node_type_sh_wavelength(void)
+void register_node_type_sh_wavelength()
{
+ namespace file_ns = blender::nodes::node_shader_wavelength_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_WAVELENGTH, "Wavelength", NODE_CLASS_CONVERTER, 0);
+ sh_node_type_base(&ntype, SH_NODE_WAVELENGTH, "Wavelength", NODE_CLASS_CONVERTER);
+ ntype.declare = file_ns::node_declare;
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_socket_templates(&ntype, sh_node_wavelength_in, sh_node_wavelength_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_wavelength);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_wavelength);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_wireframe.c b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc
index 37e60ddb205..1b38dd795cb 100644
--- a/source/blender/nodes/shader/nodes/node_shader_wireframe.c
+++ b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc
@@ -17,7 +17,9 @@
* All rights reserved.
*/
-#include "../node_shader_util.h"
+#include "node_shader_util.hh"
+
+namespace blender::nodes::node_shader_wireframe_cc {
/* **************** Wireframe ******************** */
static bNodeSocketTemplate sh_node_wireframe_in[] = {
@@ -52,16 +54,19 @@ static int node_shader_gpu_wireframe(GPUMaterial *mat,
GPU_builtin(GPU_BARYCENTRIC_DIST));
}
+} // namespace blender::nodes::node_shader_wireframe_cc
+
/* node type definition */
-void register_node_type_sh_wireframe(void)
+void register_node_type_sh_wireframe()
{
+ namespace file_ns = blender::nodes::node_shader_wireframe_cc;
+
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_WIREFRAME, "Wireframe", NODE_CLASS_INPUT, 0);
- node_type_socket_templates(&ntype, sh_node_wireframe_in, sh_node_wireframe_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_gpu(&ntype, node_shader_gpu_wireframe);
+ sh_node_type_base(&ntype, SH_NODE_WIREFRAME, "Wireframe", NODE_CLASS_INPUT);
+ node_type_socket_templates(
+ &ntype, file_ns::sh_node_wireframe_in, file_ns::sh_node_wireframe_out);
+ node_type_gpu(&ntype, file_ns::node_shader_gpu_wireframe);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 14597050524..3d914d486c3 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -50,6 +50,8 @@
#include "RE_texture.h"
+#include "UI_resources.h"
+
static void texture_get_from_context(const bContext *C,
bNodeTreeType *UNUSED(treetype),
bNodeTree **r_ntree,
@@ -132,24 +134,9 @@ static void localize(bNodeTree *UNUSED(localtree), bNodeTree *UNUSED(ntree))
}
#endif
-static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_sync_tree(ntree, localtree);
-}
-
-static void local_merge(Main *UNUSED(bmain), bNodeTree *localtree, bNodeTree *ntree)
-{
- BKE_node_preview_merge_tree(ntree, localtree, true);
-}
-
static void update(bNodeTree *ntree)
{
ntree_update_reroute_nodes(ntree);
-
- if (ntree->update & NTREE_UPDATE_NODES) {
- /* clean up preview cache, in case nodes have been removed */
- BKE_node_preview_remove_unused(ntree);
- }
}
static bool texture_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
@@ -169,14 +156,12 @@ void register_node_tree_type_tex(void)
tt->type = NTREE_TEXTURE;
strcpy(tt->idname, "TextureNodeTree");
strcpy(tt->ui_name, N_("Texture Node Editor"));
- tt->ui_icon = 0; /* Defined in `drawnode.c`. */
+ tt->ui_icon = ICON_NODE_TEXTURE; /* Defined in `drawnode.c`. */
strcpy(tt->ui_description, N_("Texture nodes"));
tt->foreach_nodeclass = foreach_nodeclass;
tt->update = update;
tt->localize = localize;
- tt->local_sync = local_sync;
- tt->local_merge = local_merge;
tt->get_from_context = texture_get_from_context;
tt->valid_socket_type = texture_node_tree_socket_type_valid;
diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c
index fe8e68bfc42..dc5e2bfcd6b 100644
--- a/source/blender/nodes/texture/node_texture_util.c
+++ b/source/blender/nodes/texture/node_texture_util.c
@@ -50,10 +50,9 @@ bool tex_node_poll_default(bNodeType *UNUSED(ntype),
return true;
}
-void tex_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void tex_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass)
{
- node_type_base(ntype, type, name, nclass, flag);
+ node_type_base(ntype, type, name, nclass);
ntype->poll = tex_node_poll_default;
ntype->insert_link = node_insert_link_default;
@@ -63,10 +62,6 @@ static void tex_call_delegate(TexDelegate *dg, float *out, TexParams *params, sh
{
if (dg->node->need_exec) {
dg->fn(out, params, dg->node, dg->in, thread);
-
- if (dg->cdata->do_preview) {
- tex_do_preview(dg->preview, params->previewco, out, dg->cdata->do_manage);
- }
}
}
@@ -123,19 +118,6 @@ void params_from_cdata(TexParams *out, TexCallData *in)
out->mtex = in->mtex;
}
-void tex_do_preview(bNodePreview *preview,
- const float coord[2],
- const float col[4],
- bool do_manage)
-{
- if (preview) {
- int xs = ((coord[0] + 1.0f) * 0.5f) * preview->xsize;
- int ys = ((coord[1] + 1.0f) * 0.5f) * preview->ysize;
-
- BKE_node_preview_set_pixel(preview, col, xs, ys, do_manage);
- }
-}
-
void tex_output(bNode *node,
bNodeExecData *execdata,
bNodeStack **in,
diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h
index 84d2c5c903a..d53000058a3 100644
--- a/source/blender/nodes/texture/node_texture_util.h
+++ b/source/blender/nodes/texture/node_texture_util.h
@@ -108,8 +108,7 @@ typedef struct TexDelegate {
bool tex_node_poll_default(struct bNodeType *ntype,
struct bNodeTree *ntree,
const char **r_disabled_hint);
-void tex_node_type_base(
- struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
+void tex_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass);
void tex_input_rgba(float *out, bNodeStack *in, TexParams *params, short thread);
void tex_input_vec(float *out, bNodeStack *in, TexParams *params, short thread);
@@ -121,10 +120,6 @@ void tex_output(bNode *node,
bNodeStack *out,
TexFn texfn,
TexCallData *data);
-void tex_do_preview(bNodePreview *preview,
- const float coord[2],
- const float col[4],
- bool do_manage);
void params_from_cdata(TexParams *out, TexCallData *in);
diff --git a/source/blender/nodes/texture/nodes/node_texture_at.c b/source/blender/nodes/texture/nodes/node_texture_at.c
index a6f8d28db75..41dea303ea2 100644
--- a/source/blender/nodes/texture/nodes/node_texture_at.c
+++ b/source/blender/nodes/texture/nodes/node_texture_at.c
@@ -58,7 +58,7 @@ void register_node_type_tex_at(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_AT, "At", NODE_CLASS_DISTORT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_AT, "At", NODE_CLASS_DISTORT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_size(&ntype, 140, 100, 320);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_bricks.c b/source/blender/nodes/texture/nodes/node_texture_bricks.c
index 72690d6ccfe..0dc92dc33d0 100644
--- a/source/blender/nodes/texture/nodes/node_texture_bricks.c
+++ b/source/blender/nodes/texture/nodes/node_texture_bricks.c
@@ -119,11 +119,12 @@ void register_node_type_tex_bricks(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_BRICKS, "Bricks", NODE_CLASS_PATTERN, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_BRICKS, "Bricks", NODE_CLASS_PATTERN);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, init);
node_type_exec(&ntype, NULL, NULL, exec);
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_checker.c b/source/blender/nodes/texture/nodes/node_texture_checker.c
index e3c4d44e7f5..62657cd7def 100644
--- a/source/blender/nodes/texture/nodes/node_texture_checker.c
+++ b/source/blender/nodes/texture/nodes/node_texture_checker.c
@@ -70,9 +70,10 @@ void register_node_type_tex_checker(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_CHECKER, "Checker", NODE_CLASS_PATTERN, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_CHECKER, "Checker", NODE_CLASS_PATTERN);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c
index f873ed5e457..b01353bcd21 100644
--- a/source/blender/nodes/texture/nodes/node_texture_common.c
+++ b/source/blender/nodes/texture/nodes/node_texture_common.c
@@ -161,7 +161,7 @@ void register_node_type_tex_group(void)
/* NOTE: Cannot use #sh_node_type_base for node group, because it would map the node type
* to the shared #NODE_GROUP integer type id. */
- node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP, 0);
+ node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP);
ntype.type = NODE_GROUP;
ntype.poll = tex_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
diff --git a/source/blender/nodes/texture/nodes/node_texture_compose.c b/source/blender/nodes/texture/nodes/node_texture_compose.c
index ffa0e9ae43e..cd918ca8314 100644
--- a/source/blender/nodes/texture/nodes/node_texture_compose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_compose.c
@@ -58,7 +58,7 @@ void register_node_type_tex_compose(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_COMPOSE, "Combine RGBA", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_COMPOSE, "Combine RGBA", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_coord.c b/source/blender/nodes/texture/nodes/node_texture_coord.c
index 5a0cf5eb497..e31fdcafbf2 100644
--- a/source/blender/nodes/texture/nodes/node_texture_coord.c
+++ b/source/blender/nodes/texture/nodes/node_texture_coord.c
@@ -49,9 +49,8 @@ void register_node_type_tex_coord(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_COORD, "Coordinates", NODE_CLASS_INPUT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_COORD, "Coordinates", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, NULL, outputs);
- node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/texture/nodes/node_texture_curves.c b/source/blender/nodes/texture/nodes/node_texture_curves.c
index f61e3f36db5..7fed45c5558 100644
--- a/source/blender/nodes/texture/nodes/node_texture_curves.c
+++ b/source/blender/nodes/texture/nodes/node_texture_curves.c
@@ -65,7 +65,7 @@ void register_node_type_tex_curve_time(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_CURVE_TIME, "Time", NODE_CLASS_INPUT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_CURVE_TIME, "Time", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, NULL, time_outputs);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, time_init);
@@ -114,7 +114,7 @@ void register_node_type_tex_curve_rgb(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, rgb_inputs, rgb_outputs);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, rgb_init);
diff --git a/source/blender/nodes/texture/nodes/node_texture_decompose.c b/source/blender/nodes/texture/nodes/node_texture_decompose.c
index 83922ea03ab..9c3cb6911e1 100644
--- a/source/blender/nodes/texture/nodes/node_texture_decompose.c
+++ b/source/blender/nodes/texture/nodes/node_texture_decompose.c
@@ -78,7 +78,7 @@ void register_node_type_tex_decompose(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE, "Separate RGBA", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE, "Separate RGBA", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_distance.c b/source/blender/nodes/texture/nodes/node_texture_distance.c
index c2241858737..2f8b28722bd 100644
--- a/source/blender/nodes/texture/nodes/node_texture_distance.c
+++ b/source/blender/nodes/texture/nodes/node_texture_distance.c
@@ -60,9 +60,8 @@ void register_node_type_tex_distance(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_DISTANCE, "Distance", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_DISTANCE, "Distance", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, inputs, outputs);
- node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c b/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c
index 759fb3d43d5..f405c3b0bec 100644
--- a/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c
+++ b/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c
@@ -107,7 +107,7 @@ void register_node_type_tex_hue_sat(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_image.c b/source/blender/nodes/texture/nodes/node_texture_image.c
index 9c61405ea23..18ae3609407 100644
--- a/source/blender/nodes/texture/nodes/node_texture_image.c
+++ b/source/blender/nodes/texture/nodes/node_texture_image.c
@@ -108,12 +108,13 @@ void register_node_type_tex_image(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_IMAGE, "Image", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, NULL, outputs);
node_type_init(&ntype, init);
node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage);
node_type_exec(&ntype, NULL, NULL, exec);
ntype.labelfunc = node_image_label;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_invert.c b/source/blender/nodes/texture/nodes/node_texture_invert.c
index 5d3f86c5c9c..7854ac4b5b8 100644
--- a/source/blender/nodes/texture/nodes/node_texture_invert.c
+++ b/source/blender/nodes/texture/nodes/node_texture_invert.c
@@ -63,7 +63,7 @@ void register_node_type_tex_invert(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c
index 9e37f4ee643..2f50f6aaae0 100644
--- a/source/blender/nodes/texture/nodes/node_texture_math.c
+++ b/source/blender/nodes/texture/nodes/node_texture_math.c
@@ -335,10 +335,9 @@ void register_node_type_tex_math(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_MATH, "Math", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, inputs, outputs);
ntype.labelfunc = node_math_label;
- node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL, NULL, exec);
node_type_update(&ntype, node_math_update);
diff --git a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
index 044875cce90..5599807d8b1 100644
--- a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
+++ b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c
@@ -69,7 +69,7 @@ void register_node_type_tex_mix_rgb(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0);
+ tex_node_type_base(&ntype, TEX_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR);
node_type_socket_templates(&ntype, inputs, outputs);
ntype.labelfunc = node_blend_label;
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c
index 19e24c9f82a..4911ab7ba9e 100644
--- a/source/blender/nodes/texture/nodes/node_texture_output.c
+++ b/source/blender/nodes/texture/nodes/node_texture_output.c
@@ -37,7 +37,7 @@ static bNodeSocketTemplate inputs[] = {
static void exec(void *data,
int UNUSED(thread),
bNode *node,
- bNodeExecData *execdata,
+ bNodeExecData *UNUSED(execdata),
bNodeStack **in,
bNodeStack **UNUSED(out))
{
@@ -54,7 +54,6 @@ static void exec(void *data,
else {
tex_input_rgba(&target->tr, in[0], &params, cdata->thread);
}
- tex_do_preview(execdata->preview, params.co, &target->tr, cdata->do_manage);
}
else {
/* 0 means don't care, so just use first */
@@ -167,13 +166,14 @@ void register_node_type_tex_output(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_OUTPUT, "Output", NODE_CLASS_OUTPUT, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_OUTPUT, "Output", NODE_CLASS_OUTPUT);
node_type_socket_templates(&ntype, inputs, NULL);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, init);
node_type_storage(&ntype, "TexNodeOutput", node_free_standard_storage, copy);
node_type_exec(&ntype, NULL, NULL, exec);
+ ntype.flag |= NODE_PREVIEW;
ntype.no_muting = true;
nodeRegisterType(&ntype);
diff --git a/source/blender/nodes/texture/nodes/node_texture_proc.c b/source/blender/nodes/texture/nodes/node_texture_proc.c
index a8a82153e58..8c294b5954d 100644
--- a/source/blender/nodes/texture/nodes/node_texture_proc.c
+++ b/source/blender/nodes/texture/nodes/node_texture_proc.c
@@ -294,12 +294,13 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node)
{ \
static bNodeType ntype; \
\
- tex_node_type_base(&ntype, TEX_NODE_PROC + TEXTYPE, Name, NODE_CLASS_TEXTURE, NODE_PREVIEW); \
+ tex_node_type_base(&ntype, TEX_NODE_PROC + TEXTYPE, Name, NODE_CLASS_TEXTURE); \
node_type_socket_templates(&ntype, name##_inputs, outputs); \
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); \
node_type_init(&ntype, init); \
node_type_storage(&ntype, "Tex", node_free_standard_storage, node_copy_standard_storage); \
node_type_exec(&ntype, NULL, NULL, name##_exec); \
+ ntype.flag |= NODE_PREVIEW; \
\
nodeRegisterType(&ntype); \
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_rotate.c b/source/blender/nodes/texture/nodes/node_texture_rotate.c
index 9985499772e..18024a4d41d 100644
--- a/source/blender/nodes/texture/nodes/node_texture_rotate.c
+++ b/source/blender/nodes/texture/nodes/node_texture_rotate.c
@@ -95,7 +95,7 @@ void register_node_type_tex_rotate(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_scale.c b/source/blender/nodes/texture/nodes/node_texture_scale.c
index d23b1b4d037..d570c73a67b 100644
--- a/source/blender/nodes/texture/nodes/node_texture_scale.c
+++ b/source/blender/nodes/texture/nodes/node_texture_scale.c
@@ -68,7 +68,7 @@ void register_node_type_tex_scale(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_SCALE, "Scale", NODE_CLASS_DISTORT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_texture.c b/source/blender/nodes/texture/nodes/node_texture_texture.c
index 59e2e9be581..083ae67ccb6 100644
--- a/source/blender/nodes/texture/nodes/node_texture_texture.c
+++ b/source/blender/nodes/texture/nodes/node_texture_texture.c
@@ -94,9 +94,10 @@ void register_node_type_tex_texture(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_translate.c b/source/blender/nodes/texture/nodes/node_texture_translate.c
index 2eef3132a18..732cd0a89a1 100644
--- a/source/blender/nodes/texture/nodes/node_texture_translate.c
+++ b/source/blender/nodes/texture/nodes/node_texture_translate.c
@@ -64,7 +64,7 @@ void register_node_type_tex_translate(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT, 0);
+ tex_node_type_base(&ntype, TEX_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_valToNor.c b/source/blender/nodes/texture/nodes/node_texture_valToNor.c
index 5ccd44b8bf0..3f0d4fb668e 100644
--- a/source/blender/nodes/texture/nodes/node_texture_valToNor.c
+++ b/source/blender/nodes/texture/nodes/node_texture_valToNor.c
@@ -80,7 +80,7 @@ void register_node_type_tex_valtonor(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_VALTONOR, "Value to Normal", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_VALTONOR, "Value to Normal", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
index 2446ef05e0c..844a4188663 100644
--- a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
+++ b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c
@@ -63,7 +63,7 @@ void register_node_type_tex_valtorgb(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, valtorgb_in, valtorgb_out);
node_type_size_preset(&ntype, NODE_SIZE_LARGE);
node_type_init(&ntype, valtorgb_init);
@@ -105,7 +105,7 @@ void register_node_type_tex_rgbtobw(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0);
+ tex_node_type_base(&ntype, TEX_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER);
node_type_socket_templates(&ntype, rgbtobw_in, rgbtobw_out);
node_type_exec(&ntype, NULL, NULL, rgbtobw_exec);
diff --git a/source/blender/nodes/texture/nodes/node_texture_viewer.c b/source/blender/nodes/texture/nodes/node_texture_viewer.c
index 18b11b86d6f..e40cdb66cb1 100644
--- a/source/blender/nodes/texture/nodes/node_texture_viewer.c
+++ b/source/blender/nodes/texture/nodes/node_texture_viewer.c
@@ -36,7 +36,7 @@ static bNodeSocketTemplate outputs[] = {
static void exec(void *data,
int UNUSED(thread),
bNode *UNUSED(node),
- bNodeExecData *execdata,
+ bNodeExecData *UNUSED(execdata),
bNodeStack **in,
bNodeStack **UNUSED(out))
{
@@ -48,7 +48,6 @@ static void exec(void *data,
params_from_cdata(&params, cdata);
tex_input_rgba(col, in[0], &params, cdata->thread);
- tex_do_preview(execdata->preview, params.previewco, col, cdata->do_manage);
}
}
@@ -56,11 +55,12 @@ void register_node_type_tex_viewer(void)
{
static bNodeType ntype;
- tex_node_type_base(&ntype, TEX_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW);
+ tex_node_type_base(&ntype, TEX_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT);
node_type_socket_templates(&ntype, inputs, outputs);
node_type_exec(&ntype, NULL, NULL, exec);
ntype.no_muting = true;
+ ntype.flag |= NODE_PREVIEW;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index 48fbe09f0ce..19013dc9ca3 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -65,6 +65,14 @@
/** \name GPUOffScreen Common Utilities
* \{ */
+static const struct PyC_StringEnumItems pygpu_framebuffer_color_texture_formats[] = {
+ {GPU_RGBA8, "RGBA8"},
+ {GPU_RGBA16, "RGBA16"},
+ {GPU_RGBA16F, "RGBA16F"},
+ {GPU_RGBA32F, "RGBA32F"},
+ {0, NULL},
+};
+
static int pygpu_offscreen_valid_check(BPyGPUOffScreen *py_ofs)
{
if (UNLIKELY(py_ofs->ofs == NULL)) {
@@ -219,16 +227,18 @@ static PyObject *pygpu_offscreen__tp_new(PyTypeObject *UNUSED(self),
GPUOffScreen *ofs = NULL;
int width, height;
+ struct PyC_StringEnum pygpu_textureformat = {pygpu_framebuffer_color_texture_formats, GPU_RGBA8};
char err_out[256];
- static const char *_keywords[] = {"width", "height", NULL};
- static _PyArg_Parser _parser = {"ii:GPUOffScreen.__new__", _keywords, 0};
- if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &width, &height)) {
+ static const char *_keywords[] = {"width", "height", "format", NULL};
+ static _PyArg_Parser _parser = {"ii|$O&:GPUOffScreen.__new__", _keywords, 0};
+ if (!_PyArg_ParseTupleAndKeywordsFast(
+ args, kwds, &_parser, &width, &height, PyC_ParseStringEnum, &pygpu_textureformat)) {
return NULL;
}
if (GPU_context_active_get()) {
- ofs = GPU_offscreen_create(width, height, true, GPU_RGBA8, err_out);
+ ofs = GPU_offscreen_create(width, height, true, pygpu_textureformat.value_found, err_out);
}
else {
STRNCPY(err_out, "No active GPU context found");
@@ -456,14 +466,21 @@ static struct PyMethodDef pygpu_offscreen__tp_methods[] = {
};
PyDoc_STRVAR(pygpu_offscreen__tp_doc,
- ".. class:: GPUOffScreen(width, height)\n"
+ ".. class:: GPUOffScreen(width, height, *, format='RGBA8')\n"
"\n"
" This object gives access to off screen buffers.\n"
"\n"
" :arg width: Horizontal dimension of the buffer.\n"
" :type width: int\n"
" :arg height: Vertical dimension of the buffer.\n"
- " :type height: int\n");
+ " :type height: int\n"
+ " :arg format: Internal data format inside GPU memory for color attachment "
+ "texture. Possible values are:\n"
+ " `RGBA8`,\n"
+ " `RGBA16`,\n"
+ " `RGBA16F`,\n"
+ " `RGBA32F`,\n"
+ " :type format: str\n");
PyTypeObject BPyGPUOffScreen_Type = {
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUOffScreen",
.tp_basicsize = sizeof(BPyGPUOffScreen),
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index a800361a41f..721abe45932 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -1131,7 +1131,7 @@ static void do_render_compositor_scenes(Render *re)
render_scene_has_layers_to_render(scene, false)) {
do_render_compositor_scene(re, scene, cfra);
BLI_gset_add(scenes_rendered, scene);
- nodeUpdate(restore_scene->nodetree, node);
+ node->typeinfo->updatefunc(restore_scene->nodetree, node);
}
}
}
@@ -1821,7 +1821,7 @@ void RE_RenderFrame(Render *re,
render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT);
/* Ugly global still...
- * is to prevent preview events and signal subsurfs etc to make full resol. */
+ * is to prevent preview events and signal subdivision-surface etc to make full resolution. */
G.is_rendering = true;
scene->r.cfra = frame;
@@ -2331,8 +2331,8 @@ void RE_RenderAnim(Render *re,
}
}
- /* Ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol
- * is also set by caller renderwin.c */
+ /* Ugly global still... is to prevent renderwin events and signal subdivision-surface etc
+ * to make full resolution is also set by caller renderwin.c */
G.is_rendering = true;
re->flag |= R_ANIMATION;
diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c
index a21351539f6..5455b2d883a 100644
--- a/source/blender/render/intern/render_result.c
+++ b/source/blender/render/intern/render_result.c
@@ -470,6 +470,12 @@ RenderResult *render_result_new(Render *re,
void render_result_passes_allocated_ensure(RenderResult *rr)
{
+ if (rr == NULL) {
+ /* Happens when the result was not yet allocated for the current scene or slot configuration.
+ */
+ return;
+ }
+
LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) {
LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) {
if (rl->exrhandle != NULL && !STREQ(rp->name, RE_PASSNAME_COMBINED)) {
diff --git a/source/blender/sequencer/SEQ_effects.h b/source/blender/sequencer/SEQ_effects.h
index 4bd5b54b36b..87a8288a593 100644
--- a/source/blender/sequencer/SEQ_effects.h
+++ b/source/blender/sequencer/SEQ_effects.h
@@ -68,10 +68,10 @@ struct SeqEffectHandle {
* 0: no early out,
* 1: out = ibuf1,
* 2: out = ibuf2 */
- int (*early_out)(struct Sequence *seq, float facf0, float facf1);
+ int (*early_out)(struct Sequence *seq, float fac);
- /* stores the default facf0 and facf1 if no IPO is present */
- void (*get_default_fac)(struct Sequence *seq, float timeline_frame, float *facf0, float *facf1);
+ /* sets the default `fac` value */
+ void (*get_default_fac)(struct Sequence *seq, float timeline_frame, float *fac);
/* execute the effect
* sequence effects are only required to either support
@@ -81,8 +81,7 @@ struct SeqEffectHandle {
struct ImBuf *(*execute)(const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
struct ImBuf *ibuf1,
struct ImBuf *ibuf2,
struct ImBuf *ibuf3);
@@ -95,8 +94,7 @@ struct SeqEffectHandle {
void (*execute_slice)(const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
struct ImBuf *ibuf1,
struct ImBuf *ibuf2,
struct ImBuf *ibuf3,
diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c
index 05ce35deeec..8776bc63cf0 100644
--- a/source/blender/sequencer/intern/effects.c
+++ b/source/blender/sequencer/intern/effects.c
@@ -206,69 +206,22 @@ static void init_alpha_over_or_under(Sequence *seq)
seq->seq1 = seq2;
}
-static void do_alphaover_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
-{
- float fac2, mfac, fac, fac4;
- int xo;
- unsigned char *cp1, *cp2, *rt;
- float tempc[4], rt1[4], rt2[4];
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac4 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
- /* rt = rt1 over rt2 (alpha from rt1) */
-
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
-
- fac = fac2;
- mfac = 1.0f - fac2 * rt1[3];
-
- if (fac <= 0.0f) {
- *((unsigned int *)rt) = *((unsigned int *)cp2);
- }
- else if (mfac <= 0.0f) {
- *((unsigned int *)rt) = *((unsigned int *)cp1);
- }
- else {
- tempc[0] = fac * rt1[0] + mfac * rt2[0];
- tempc[1] = fac * rt1[1] + mfac * rt2[1];
- tempc[2] = fac * rt1[2] + mfac * rt2[2];
- tempc[3] = fac * rt1[3] + mfac * rt2[3];
-
- premul_float_to_straight_uchar(rt, tempc);
- }
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
+static void do_alphaover_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+{
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- if (y == 0) {
- break;
- }
- y--;
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ /* rt = rt1 over rt2 (alpha from rt1) */
- x = xo;
- while (x--) {
+ float tempc[4], rt1[4], rt2[4];
straight_uchar_to_premul_float(rt1, cp1);
straight_uchar_to_premul_float(rt2, cp2);
- fac = fac4;
- mfac = 1.0f - (fac4 * rt1[3]);
+ float mfac = 1.0f - fac * rt1[3];
if (fac <= 0.0f) {
*((unsigned int *)rt) = *((unsigned int *)cp2);
@@ -292,27 +245,17 @@ static void do_alphaover_effect_byte(float facf0,
}
static void do_alphaover_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+ float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- float fac2, mfac, fac, fac4;
- int xo;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- fac2 = facf0;
- fac4 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
/* rt = rt1 over rt2 (alpha from rt1) */
- fac = fac2;
- mfac = 1.0f - (fac2 * rt1[3]);
+ float mfac = 1.0f - (fac * rt1[3]);
if (fac <= 0.0f) {
memcpy(rt, rt2, sizeof(float[4]));
@@ -330,41 +273,13 @@ static void do_alphaover_effect_float(
rt2 += 4;
rt += 4;
}
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- fac = fac4;
- mfac = 1.0f - (fac4 * rt1[3]);
-
- if (fac <= 0.0f) {
- memcpy(rt, rt2, sizeof(float[4]));
- }
- else if (mfac <= 0.0f) {
- memcpy(rt, rt1, sizeof(float[4]));
- }
- else {
- rt[0] = fac * rt1[0] + mfac * rt2[0];
- rt[1] = fac * rt1[1] + mfac * rt2[1];
- rt[2] = fac * rt1[2] + mfac * rt2[2];
- rt[3] = fac * rt1[3] + mfac * rt2[3];
- }
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
}
}
static void do_alphaover_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -378,7 +293,7 @@ static void do_alphaover_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_alphaover_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_alphaover_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -386,96 +301,47 @@ static void do_alphaover_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_alphaover_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_alphaover_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
/*********************** Alpha Under *************************/
-static void do_alphaunder_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
-{
- float fac2, fac, fac4;
- int xo;
- unsigned char *cp1, *cp2, *rt;
- float tempc[4], rt1[4], rt2[4];
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac4 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
+static void do_alphaunder_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+{
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
+
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
/* rt = rt1 under rt2 (alpha from rt2) */
+
+ float tempc[4], rt1[4], rt2[4];
straight_uchar_to_premul_float(rt1, cp1);
straight_uchar_to_premul_float(rt2, cp2);
/* this complex optimization is because the
* 'skybuf' can be crossed in
*/
- if (rt2[3] <= 0.0f && fac2 >= 1.0f) {
- *((unsigned int *)rt) = *((unsigned int *)cp1);
- }
- else if (rt2[3] >= 1.0f) {
- *((unsigned int *)rt) = *((unsigned int *)cp2);
- }
- else {
- fac = (fac2 * (1.0f - rt2[3]));
-
- if (fac <= 0) {
- *((unsigned int *)rt) = *((unsigned int *)cp2);
- }
- else {
- tempc[0] = (fac * rt1[0] + rt2[0]);
- tempc[1] = (fac * rt1[1] + rt2[1]);
- tempc[2] = (fac * rt1[2] + rt2[2]);
- tempc[3] = (fac * rt1[3] + rt2[3]);
-
- premul_float_to_straight_uchar(rt, tempc);
- }
- }
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
-
- if (rt2[3] <= 0.0f && fac4 >= 1.0f) {
+ if (rt2[3] <= 0.0f && fac >= 1.0f) {
*((unsigned int *)rt) = *((unsigned int *)cp1);
}
else if (rt2[3] >= 1.0f) {
*((unsigned int *)rt) = *((unsigned int *)cp2);
}
else {
- fac = (fac4 * (1.0f - rt2[3]));
+ float temp_fac = (fac * (1.0f - rt2[3]));
if (fac <= 0) {
*((unsigned int *)rt) = *((unsigned int *)cp2);
}
else {
- tempc[0] = (fac * rt1[0] + rt2[0]);
- tempc[1] = (fac * rt1[1] + rt2[1]);
- tempc[2] = (fac * rt1[2] + rt2[2]);
- tempc[3] = (fac * rt1[3] + rt2[3]);
+ tempc[0] = (temp_fac * rt1[0] + rt2[0]);
+ tempc[1] = (temp_fac * rt1[1] + rt2[1]);
+ tempc[2] = (temp_fac * rt1[2] + rt2[2]);
+ tempc[3] = (temp_fac * rt1[3] + rt2[3]);
premul_float_to_straight_uchar(rt, tempc);
}
@@ -488,76 +354,36 @@ static void do_alphaunder_effect_byte(float facf0,
}
static void do_alphaunder_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+ float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- float fac2, fac, fac4;
- int xo;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac4 = facf1;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- while (y--) {
- x = xo;
- while (x--) {
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
/* rt = rt1 under rt2 (alpha from rt2) */
/* this complex optimization is because the
* 'skybuf' can be crossed in
*/
- if (rt2[3] <= 0 && fac2 >= 1.0f) {
+ if (rt2[3] <= 0 && fac >= 1.0f) {
memcpy(rt, rt1, sizeof(float[4]));
}
else if (rt2[3] >= 1.0f) {
memcpy(rt, rt2, sizeof(float[4]));
}
else {
- fac = fac2 * (1.0f - rt2[3]);
+ float temp_fac = fac * (1.0f - rt2[3]);
if (fac == 0) {
memcpy(rt, rt2, sizeof(float[4]));
}
else {
- rt[0] = fac * rt1[0] + rt2[0];
- rt[1] = fac * rt1[1] + rt2[1];
- rt[2] = fac * rt1[2] + rt2[2];
- rt[3] = fac * rt1[3] + rt2[3];
- }
- }
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- if (rt2[3] <= 0 && fac4 >= 1.0f) {
- memcpy(rt, rt1, sizeof(float[4]));
- }
- else if (rt2[3] >= 1.0f) {
- memcpy(rt, rt2, sizeof(float[4]));
- }
- else {
- fac = fac4 * (1.0f - rt2[3]);
-
- if (fac == 0) {
- memcpy(rt, rt2, sizeof(float[4]));
- }
- else {
- rt[0] = fac * rt1[0] + rt2[0];
- rt[1] = fac * rt1[1] + rt2[1];
- rt[2] = fac * rt1[2] + rt2[2];
- rt[3] = fac * rt1[3] + rt2[3];
+ rt[0] = temp_fac * rt1[0] + rt2[0];
+ rt[1] = temp_fac * rt1[1] + rt2[1];
+ rt[2] = temp_fac * rt1[2] + rt2[2];
+ rt[3] = temp_fac * rt1[3] + rt2[3];
}
}
rt1 += 4;
@@ -570,8 +396,7 @@ static void do_alphaunder_effect_float(
static void do_alphaunder_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -585,7 +410,7 @@ static void do_alphaunder_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_alphaunder_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_alphaunder_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -593,58 +418,28 @@ static void do_alphaunder_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_alphaunder_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_alphaunder_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
/*********************** Cross *************************/
-static void do_cross_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
+static void do_cross_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
- int fac1, fac2, fac3, fac4;
- int xo;
- unsigned char *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac2 = (int)(256.0f * facf0);
- fac1 = 256 - fac2;
- fac4 = (int)(256.0f * facf1);
- fac3 = 256 - fac4;
-
- while (y--) {
- x = xo;
- while (x--) {
- rt[0] = (fac1 * rt1[0] + fac2 * rt2[0]) >> 8;
- rt[1] = (fac1 * rt1[1] + fac2 * rt2[1]) >> 8;
- rt[2] = (fac1 * rt1[2] + fac2 * rt2[2]) >> 8;
- rt[3] = (fac1 * rt1[3] + fac2 * rt2[3]) >> 8;
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
+ unsigned char *rt1 = rect1;
+ unsigned char *rt2 = rect2;
+ unsigned char *rt = out;
- if (y == 0) {
- break;
- }
- y--;
+ int temp_fac = (int)(256.0f * fac);
+ int temp_mfac = 256 - temp_fac;
- x = xo;
- while (x--) {
- rt[0] = (fac3 * rt1[0] + fac4 * rt2[0]) >> 8;
- rt[1] = (fac3 * rt1[1] + fac4 * rt2[1]) >> 8;
- rt[2] = (fac3 * rt1[2] + fac4 * rt2[2]) >> 8;
- rt[3] = (fac3 * rt1[3] + fac4 * rt2[3]) >> 8;
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rt[0] = (temp_mfac * rt1[0] + temp_fac * rt2[0]) >> 8;
+ rt[1] = (temp_mfac * rt1[1] + temp_fac * rt2[1]) >> 8;
+ rt[2] = (temp_mfac * rt1[2] + temp_fac * rt2[2]) >> 8;
+ rt[3] = (temp_mfac * rt1[3] + temp_fac * rt2[3]) >> 8;
rt1 += 4;
rt2 += 4;
@@ -653,47 +448,20 @@ static void do_cross_effect_byte(float facf0,
}
}
-static void do_cross_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_cross_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- float fac1, fac2, fac3, fac4;
- int xo;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac1 = 1.0f - fac2;
- fac4 = facf1;
- fac3 = 1.0f - fac4;
-
- while (y--) {
- x = xo;
- while (x--) {
- rt[0] = fac1 * rt1[0] + fac2 * rt2[0];
- rt[1] = fac1 * rt1[1] + fac2 * rt2[1];
- rt[2] = fac1 * rt1[2] + fac2 * rt2[2];
- rt[3] = fac1 * rt1[3] + fac2 * rt2[3];
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- if (y == 0) {
- break;
- }
- y--;
+ float mfac = 1.0f - fac;
- x = xo;
- while (x--) {
- rt[0] = fac3 * rt1[0] + fac4 * rt2[0];
- rt[1] = fac3 * rt1[1] + fac4 * rt2[1];
- rt[2] = fac3 * rt1[2] + fac4 * rt2[2];
- rt[3] = fac3 * rt1[3] + fac4 * rt2[3];
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rt[0] = mfac * rt1[0] + fac * rt2[0];
+ rt[1] = mfac * rt1[1] + fac * rt2[1];
+ rt[2] = mfac * rt1[2] + fac * rt2[2];
+ rt[3] = mfac * rt1[3] + fac * rt2[3];
rt1 += 4;
rt2 += 4;
@@ -705,8 +473,7 @@ static void do_cross_effect_float(
static void do_cross_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -720,7 +487,7 @@ static void do_cross_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_cross_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_cross_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -728,7 +495,7 @@ static void do_cross_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_cross_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_cross_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
@@ -888,58 +655,26 @@ static void free_gammacross(Sequence *UNUSED(seq), const bool UNUSED(do_id_user)
{
}
-static void do_gammacross_effect_byte(float facf0,
- float UNUSED(facf1),
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
+static void do_gammacross_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
- float fac1, fac2;
- int xo;
- unsigned char *cp1, *cp2, *rt;
- float rt1[4], rt2[4], tempc[4];
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac1 = 1.0f - fac2;
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- while (y--) {
- x = xo;
- while (x--) {
- straight_uchar_to_premul_float(rt1, cp1);
- straight_uchar_to_premul_float(rt2, cp2);
+ float mfac = 1.0f - fac;
- tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0]));
- tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1]));
- tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2]));
- tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3]));
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ float rt1[4], rt2[4], tempc[4];
- premul_float_to_straight_uchar(rt, tempc);
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
straight_uchar_to_premul_float(rt1, cp1);
straight_uchar_to_premul_float(rt2, cp2);
- tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0]));
- tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1]));
- tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2]));
- tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3]));
+ tempc[0] = gammaCorrect(mfac * invGammaCorrect(rt1[0]) + fac * invGammaCorrect(rt2[0]));
+ tempc[1] = gammaCorrect(mfac * invGammaCorrect(rt1[1]) + fac * invGammaCorrect(rt2[1]));
+ tempc[2] = gammaCorrect(mfac * invGammaCorrect(rt1[2]) + fac * invGammaCorrect(rt2[2]));
+ tempc[3] = gammaCorrect(mfac * invGammaCorrect(rt1[3]) + fac * invGammaCorrect(rt2[3]));
premul_float_to_straight_uchar(rt, tempc);
cp1 += 4;
@@ -950,38 +685,17 @@ static void do_gammacross_effect_byte(float facf0,
}
static void do_gammacross_effect_float(
- float facf0, float UNUSED(facf1), int x, int y, float *rect1, float *rect2, float *out)
+ float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- float fac1, fac2;
- int xo;
- float *rt1, *rt2, *rt;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac2 = facf0;
- fac1 = 1.0f - fac2;
-
- while (y--) {
- x = xo * 4;
- while (x--) {
- *rt = gammaCorrect(fac1 * invGammaCorrect(*rt1) + fac2 * invGammaCorrect(*rt2));
- rt1++;
- rt2++;
- rt++;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo * 4;
- while (x--) {
- *rt = gammaCorrect(fac1 * invGammaCorrect(*rt1) + fac2 * invGammaCorrect(*rt2));
+ float mfac = 1.0f - fac;
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ *rt = gammaCorrect(mfac * invGammaCorrect(*rt1) + fac * invGammaCorrect(*rt2));
rt1++;
rt2++;
rt++;
@@ -1003,8 +717,7 @@ static struct ImBuf *gammacross_init_execution(const SeqRenderData *context,
static void do_gammacross_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1018,7 +731,7 @@ static void do_gammacross_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_gammacross_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_gammacross_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -1026,57 +739,27 @@ static void do_gammacross_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_gammacross_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_gammacross_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
/*********************** Add *************************/
-static void do_add_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
-{
- int xo, fac1, fac3;
- unsigned char *cp1, *cp2, *rt;
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac1 = (int)(256.0f * facf0);
- fac3 = (int)(256.0f * facf1);
-
- while (y--) {
- x = xo;
-
- while (x--) {
- const int m = fac1 * (int)cp2[3];
- rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255);
- rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255);
- rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255);
- rt[3] = cp1[3];
+static void do_add_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+{
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
+ int temp_fac = (int)(256.0f * fac);
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- const int m = fac3 * (int)cp2[3];
- rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255);
- rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255);
- rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ const int temp_fac2 = temp_fac * (int)cp2[3];
+ rt[0] = min_ii(cp1[0] + ((temp_fac2 * cp2[0]) >> 16), 255);
+ rt[1] = min_ii(cp1[1] + ((temp_fac2 * cp2[1]) >> 16), 255);
+ rt[2] = min_ii(cp1[2] + ((temp_fac2 * cp2[2]) >> 16), 255);
rt[3] = cp1[3];
cp1 += 4;
@@ -1086,46 +769,18 @@ static void do_add_effect_byte(float facf0,
}
}
-static void do_add_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_add_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- int xo;
- float fac1, fac3;
- float *rt1, *rt2, *rt;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac1 = facf0;
- fac3 = facf1;
-
- while (y--) {
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * (1.0f - fac1))) * rt2[3];
- rt[0] = rt1[0] + m * rt2[0];
- rt[1] = rt1[1] + m * rt2[1];
- rt[2] = rt1[2] + m * rt2[2];
- rt[3] = rt1[3];
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * (1.0f - fac3))) * rt2[3];
- rt[0] = rt1[0] + m * rt2[0];
- rt[1] = rt1[1] + m * rt2[1];
- rt[2] = rt1[2] + m * rt2[2];
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ const float temp_fac = (1.0f - (rt1[3] * (1.0f - fac))) * rt2[3];
+ rt[0] = rt1[0] + temp_fac * rt2[0];
+ rt[1] = rt1[1] + temp_fac * rt2[1];
+ rt[2] = rt1[2] + temp_fac * rt2[2];
rt[3] = rt1[3];
rt1 += 4;
@@ -1138,8 +793,7 @@ static void do_add_effect_float(
static void do_add_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1153,7 +807,7 @@ static void do_add_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_add_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_add_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -1161,56 +815,27 @@ static void do_add_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_add_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_add_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
/*********************** Sub *************************/
-static void do_sub_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
-{
- int xo, fac1, fac3;
- unsigned char *cp1, *cp2, *rt;
-
- xo = x;
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
-
- fac1 = (int)(256.0f * facf0);
- fac3 = (int)(256.0f * facf1);
-
- while (y--) {
- x = xo;
- while (x--) {
- const int m = fac1 * (int)cp2[3];
- rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0);
- rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0);
- rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0);
- rt[3] = cp1[3];
+static void do_sub_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
+{
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- cp1 += 4;
- cp2 += 4;
- rt += 4;
- }
+ int temp_fac = (int)(256.0f * fac);
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- const int m = fac3 * (int)cp2[3];
- rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0);
- rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0);
- rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ const int temp_fac2 = temp_fac * (int)cp2[3];
+ rt[0] = max_ii(cp1[0] - ((temp_fac2 * cp2[0]) >> 16), 0);
+ rt[1] = max_ii(cp1[1] - ((temp_fac2 * cp2[1]) >> 16), 0);
+ rt[2] = max_ii(cp1[2] - ((temp_fac2 * cp2[2]) >> 16), 0);
rt[3] = cp1[3];
cp1 += 4;
@@ -1220,47 +845,20 @@ static void do_sub_effect_byte(float facf0,
}
}
-static void do_sub_effect_float(
- float UNUSED(facf0), float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_sub_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- int xo;
- float /* fac1, */ fac3_inv;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- /* UNUSED */
- // fac1 = facf0;
- fac3_inv = 1.0f - facf1;
+ float mfac = 1.0f - fac;
- while (y--) {
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3];
- rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f);
- rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f);
- rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f);
- rt[3] = rt1[3];
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3];
- rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f);
- rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f);
- rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ const float temp_fac = (1.0f - (rt1[3] * mfac)) * rt2[3];
+ rt[0] = max_ff(rt1[0] - temp_fac * rt2[0], 0.0f);
+ rt[1] = max_ff(rt1[1] - temp_fac * rt2[1], 0.0f);
+ rt[2] = max_ff(rt1[2] - temp_fac * rt2[2], 0.0f);
rt[3] = rt1[3];
rt1 += 4;
@@ -1273,8 +871,7 @@ static void do_sub_effect_float(
static void do_sub_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1288,7 +885,7 @@ static void do_sub_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_sub_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_sub_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -1296,7 +893,7 @@ static void do_sub_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_sub_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_sub_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
@@ -1306,161 +903,95 @@ static void do_sub_effect(const SeqRenderData *context,
#define XOFF 8
#define YOFF 8
-static void do_drop_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect2i,
- unsigned char *rect1i,
- unsigned char *outi)
-{
- int temp, fac, fac1, fac2;
- unsigned char *rt1, *rt2, *out;
- int field = 1;
-
- const int width = x;
- const int height = y;
- const int xoff = min_ii(XOFF, width);
- const int yoff = min_ii(YOFF, height);
-
- fac1 = (int)(70.0f * facf0);
- fac2 = (int)(70.0f * facf1);
-
- rt2 = rect2i + yoff * 4 * width;
- rt1 = rect1i;
- out = outi;
- for (y = 0; y < height - yoff; y++) {
- if (field) {
- fac = fac1;
- }
- else {
- fac = fac2;
- }
- field = !field;
+static void do_drop_effect_byte(
+ float fac, int x, int y, unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi)
+{
+ const int xoff = min_ii(XOFF, x);
+ const int yoff = min_ii(YOFF, y);
+
+ int temp_fac = (int)(70.0f * fac);
+ unsigned char *rt2 = rect2i + yoff * 4 * x;
+ unsigned char *rt1 = rect1i;
+ unsigned char *out = outi;
+ for (int i = 0; i < y - yoff; i++) {
memcpy(out, rt1, sizeof(*out) * xoff * 4);
rt1 += xoff * 4;
out += xoff * 4;
- for (x = xoff; x < width; x++) {
- temp = ((fac * rt2[3]) >> 8);
+ for (int j = xoff; j < x; j++) {
+ int temp_fac2 = ((temp_fac * rt2[3]) >> 8);
- *(out++) = MAX2(0, *rt1 - temp);
+ *(out++) = MAX2(0, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0, *rt1 - temp);
+ *(out++) = MAX2(0, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0, *rt1 - temp);
+ *(out++) = MAX2(0, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0, *rt1 - temp);
+ *(out++) = MAX2(0, *rt1 - temp_fac2);
rt1++;
rt2 += 4;
}
rt2 += xoff * 4;
}
- memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
+ memcpy(out, rt1, sizeof(*out) * yoff * 4 * x);
}
static void do_drop_effect_float(
- float facf0, float facf1, int x, int y, float *rect2i, float *rect1i, float *outi)
-{
- float temp, fac, fac1, fac2;
- float *rt1, *rt2, *out;
- int field = 1;
-
- const int width = x;
- const int height = y;
- const int xoff = min_ii(XOFF, width);
- const int yoff = min_ii(YOFF, height);
-
- fac1 = 70.0f * facf0;
- fac2 = 70.0f * facf1;
-
- rt2 = rect2i + yoff * 4 * width;
- rt1 = rect1i;
- out = outi;
- for (y = 0; y < height - yoff; y++) {
- if (field) {
- fac = fac1;
- }
- else {
- fac = fac2;
- }
- field = !field;
+ float fac, int x, int y, float *rect2i, float *rect1i, float *outi)
+{
+ const int xoff = min_ii(XOFF, x);
+ const int yoff = min_ii(YOFF, y);
+
+ float temp_fac = 70.0f * fac;
+ float *rt2 = rect2i + yoff * 4 * x;
+ float *rt1 = rect1i;
+ float *out = outi;
+ for (int i = 0; i < y - yoff; i++) {
memcpy(out, rt1, sizeof(*out) * xoff * 4);
rt1 += xoff * 4;
out += xoff * 4;
- for (x = xoff; x < width; x++) {
- temp = fac * rt2[3];
+ for (int j = xoff; j < x; j++) {
+ float temp_fac2 = temp_fac * rt2[3];
- *(out++) = MAX2(0.0f, *rt1 - temp);
+ *(out++) = MAX2(0.0f, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0.0f, *rt1 - temp);
+ *(out++) = MAX2(0.0f, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0.0f, *rt1 - temp);
+ *(out++) = MAX2(0.0f, *rt1 - temp_fac2);
rt1++;
- *(out++) = MAX2(0.0f, *rt1 - temp);
+ *(out++) = MAX2(0.0f, *rt1 - temp_fac2);
rt1++;
rt2 += 4;
}
rt2 += xoff * 4;
}
- memcpy(out, rt1, sizeof(*out) * yoff * 4 * width);
+ memcpy(out, rt1, sizeof(*out) * yoff * 4 * x);
}
/*********************** Mul *************************/
-static void do_mul_effect_byte(float facf0,
- float facf1,
- int x,
- int y,
- unsigned char *rect1,
- unsigned char *rect2,
- unsigned char *out)
+static void do_mul_effect_byte(
+ float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
- int xo, fac1, fac3;
- unsigned char *rt1, *rt2, *rt;
+ unsigned char *rt1 = rect1;
+ unsigned char *rt2 = rect2;
+ unsigned char *rt = out;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac1 = (int)(256.0f * facf0);
- fac3 = (int)(256.0f * facf1);
+ int temp_fac = (int)(256.0f * fac);
/* Formula:
* `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + axaux = c * px + py * s;` // + centx
* `yaux = -s * px + c * py;` // + centy */
- while (y--) {
-
- x = xo;
- while (x--) {
-
- rt[0] = rt1[0] + ((fac1 * rt1[0] * (rt2[0] - 255)) >> 16);
- rt[1] = rt1[1] + ((fac1 * rt1[1] * (rt2[1] - 255)) >> 16);
- rt[2] = rt1[2] + ((fac1 * rt1[2] * (rt2[2] - 255)) >> 16);
- rt[3] = rt1[3] + ((fac1 * rt1[3] * (rt2[3] - 255)) >> 16);
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
-
- rt[0] = rt1[0] + ((fac3 * rt1[0] * (rt2[0] - 255)) >> 16);
- rt[1] = rt1[1] + ((fac3 * rt1[1] * (rt2[1] - 255)) >> 16);
- rt[2] = rt1[2] + ((fac3 * rt1[2] * (rt2[2] - 255)) >> 16);
- rt[3] = rt1[3] + ((fac3 * rt1[3] * (rt2[3] - 255)) >> 16);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rt[0] = rt1[0] + ((temp_fac * rt1[0] * (rt2[0] - 255)) >> 16);
+ rt[1] = rt1[1] + ((temp_fac * rt1[1] * (rt2[1] - 255)) >> 16);
+ rt[2] = rt1[2] + ((temp_fac * rt1[2] * (rt2[2] - 255)) >> 16);
+ rt[3] = rt1[3] + ((temp_fac * rt1[3] * (rt2[3] - 255)) >> 16);
rt1 += 4;
rt2 += 4;
@@ -1469,48 +1000,21 @@ static void do_mul_effect_byte(float facf0,
}
}
-static void do_mul_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
+static void do_mul_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out)
{
- int xo;
- float fac1, fac3;
- float *rt1, *rt2, *rt;
-
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
-
- fac1 = facf0;
- fac3 = facf1;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
/* Formula:
* `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + a`. */
- while (y--) {
- x = xo;
- while (x--) {
- rt[0] = rt1[0] + fac1 * rt1[0] * (rt2[0] - 1.0f);
- rt[1] = rt1[1] + fac1 * rt1[1] * (rt2[1] - 1.0f);
- rt[2] = rt1[2] + fac1 * rt1[2] * (rt2[2] - 1.0f);
- rt[3] = rt1[3] + fac1 * rt1[3] * (rt2[3] - 1.0f);
-
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
-
- if (y == 0) {
- break;
- }
- y--;
-
- x = xo;
- while (x--) {
- rt[0] = rt1[0] + fac3 * rt1[0] * (rt2[0] - 1.0f);
- rt[1] = rt1[1] + fac3 * rt1[1] * (rt2[1] - 1.0f);
- rt[2] = rt1[2] + fac3 * rt1[2] * (rt2[2] - 1.0f);
- rt[3] = rt1[3] + fac3 * rt1[3] * (rt2[3] - 1.0f);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rt[0] = rt1[0] + fac * rt1[0] * (rt2[0] - 1.0f);
+ rt[1] = rt1[1] + fac * rt1[1] * (rt2[1] - 1.0f);
+ rt[2] = rt1[2] + fac * rt1[2] * (rt2[2] - 1.0f);
+ rt[3] = rt1[3] + fac * rt1[3] * (rt2[3] - 1.0f);
rt1 += 4;
rt2 += 4;
@@ -1522,8 +1026,7 @@ static void do_mul_effect_float(
static void do_mul_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1537,7 +1040,7 @@ static void do_mul_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_mul_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_mul_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -1545,7 +1048,7 @@ static void do_mul_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_mul_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out);
+ do_mul_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out);
}
}
@@ -1555,8 +1058,7 @@ typedef void (*IMB_blend_func_byte)(unsigned char *dst,
const unsigned char *src2);
typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2);
-BLI_INLINE void apply_blend_function_byte(float facf0,
- float facf1,
+BLI_INLINE void apply_blend_function_byte(float fac,
int x,
int y,
unsigned char *rect1,
@@ -1564,33 +1066,16 @@ BLI_INLINE void apply_blend_function_byte(float facf0,
unsigned char *out,
IMB_blend_func_byte blend_function)
{
- int xo;
- unsigned char *rt1, *rt2, *rt;
- unsigned int achannel;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
- while (y--) {
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = (unsigned int)achannel * facf0;
- blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
- rt[3] = rt1[3];
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
- if (y == 0) {
- break;
- }
- y--;
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = (unsigned int)achannel * facf1;
+ unsigned char *rt1 = rect1;
+ unsigned char *rt2 = rect2;
+ unsigned char *rt = out;
+
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ unsigned int achannel = rt2[3];
+ rt2[3] = (unsigned int)achannel * fac;
blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
+ rt2[3] = achannel;
rt[3] = rt1[3];
rt1 += 4;
rt2 += 4;
@@ -1599,8 +1084,7 @@ BLI_INLINE void apply_blend_function_byte(float facf0,
}
}
-BLI_INLINE void apply_blend_function_float(float facf0,
- float facf1,
+BLI_INLINE void apply_blend_function_float(float fac,
int x,
int y,
float *rect1,
@@ -1608,33 +1092,16 @@ BLI_INLINE void apply_blend_function_float(float facf0,
float *out,
IMB_blend_func_float blend_function)
{
- int xo;
- float *rt1, *rt2, *rt;
- float achannel;
- xo = x;
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
- while (y--) {
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = achannel * facf0;
- blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
- rt[3] = rt1[3];
- rt1 += 4;
- rt2 += 4;
- rt += 4;
- }
- if (y == 0) {
- break;
- }
- y--;
- for (x = xo; x > 0; x--) {
- achannel = rt1[3];
- rt1[3] = achannel * facf1;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
+
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ float achannel = rt2[3];
+ rt2[3] = achannel * fac;
blend_function(rt, rt1, rt2);
- rt1[3] = achannel;
+ rt2[3] = achannel;
rt[3] = rt1[3];
rt1 += 4;
rt2 += 4;
@@ -1644,89 +1111,78 @@ BLI_INLINE void apply_blend_function_float(float facf0,
}
static void do_blend_effect_float(
- float facf0, float facf1, int x, int y, float *rect1, float *rect2, int btype, float *out)
+ float fac, int x, int y, float *rect1, float *rect2, int btype, float *out)
{
switch (btype) {
case SEQ_TYPE_ADD:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_add_float);
break;
case SEQ_TYPE_SUB:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_sub_float);
break;
case SEQ_TYPE_MUL:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_mul_float);
break;
case SEQ_TYPE_DARKEN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_darken_float);
break;
case SEQ_TYPE_COLOR_BURN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_burn_float);
break;
case SEQ_TYPE_LINEAR_BURN:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_linearburn_float);
break;
case SEQ_TYPE_SCREEN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_screen_float);
break;
case SEQ_TYPE_LIGHTEN:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_lighten_float);
break;
case SEQ_TYPE_DODGE:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_dodge_float);
break;
case SEQ_TYPE_OVERLAY:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_overlay_float);
break;
case SEQ_TYPE_SOFT_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_softlight_float);
break;
case SEQ_TYPE_HARD_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_hardlight_float);
break;
case SEQ_TYPE_PIN_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_pinlight_float);
break;
case SEQ_TYPE_LIN_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_linearlight_float);
break;
case SEQ_TYPE_VIVID_LIGHT:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_vividlight_float);
break;
case SEQ_TYPE_BLEND_COLOR:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_color_float);
break;
case SEQ_TYPE_HUE:
- apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_hue_float);
break;
case SEQ_TYPE_SATURATION:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_saturation_float);
break;
case SEQ_TYPE_VALUE:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_luminosity_float);
break;
case SEQ_TYPE_DIFFERENCE:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_difference_float);
break;
case SEQ_TYPE_EXCLUSION:
- apply_blend_function_float(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_float);
+ apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_exclusion_float);
break;
default:
break;
}
}
-static void do_blend_effect_byte(float facf0,
- float facf1,
+static void do_blend_effect_byte(float fac,
int x,
int y,
unsigned char *rect1,
@@ -1736,73 +1192,67 @@ static void do_blend_effect_byte(float facf0,
{
switch (btype) {
case SEQ_TYPE_ADD:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_add_byte);
break;
case SEQ_TYPE_SUB:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_sub_byte);
break;
case SEQ_TYPE_MUL:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_mul_byte);
break;
case SEQ_TYPE_DARKEN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_darken_byte);
break;
case SEQ_TYPE_COLOR_BURN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_burn_byte);
break;
case SEQ_TYPE_LINEAR_BURN:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_linearburn_byte);
break;
case SEQ_TYPE_SCREEN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_screen_byte);
break;
case SEQ_TYPE_LIGHTEN:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_lighten_byte);
break;
case SEQ_TYPE_DODGE:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_dodge_byte);
break;
case SEQ_TYPE_OVERLAY:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_overlay_byte);
break;
case SEQ_TYPE_SOFT_LIGHT:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_softlight_byte);
break;
case SEQ_TYPE_HARD_LIGHT:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_hardlight_byte);
break;
case SEQ_TYPE_PIN_LIGHT:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_pinlight_byte);
break;
case SEQ_TYPE_LIN_LIGHT:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_linearlight_byte);
break;
case SEQ_TYPE_VIVID_LIGHT:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_vividlight_byte);
break;
case SEQ_TYPE_BLEND_COLOR:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_color_byte);
break;
case SEQ_TYPE_HUE:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_hue_byte);
break;
case SEQ_TYPE_SATURATION:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_saturation_byte);
break;
case SEQ_TYPE_VALUE:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_luminosity_byte);
break;
case SEQ_TYPE_DIFFERENCE:
- apply_blend_function_byte(
- facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_difference_byte);
break;
case SEQ_TYPE_EXCLUSION:
- apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_byte);
+ apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_exclusion_byte);
break;
default:
break;
@@ -1812,8 +1262,7 @@ static void do_blend_effect_byte(float facf0,
static void do_blend_mode_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1826,14 +1275,14 @@ static void do_blend_mode_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
do_blend_effect_float(
- facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
+ fac, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
do_blend_effect_byte(
- facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
+ fac, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out);
}
}
/*********************** Color Mix Effect *************************/
@@ -1853,8 +1302,7 @@ static void init_colormix_effect(Sequence *seq)
static void do_colormix_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -1862,24 +1310,24 @@ static void do_colormix_effect(const SeqRenderData *context,
int total_lines,
ImBuf *out)
{
- float facf;
+ float fac;
ColorMixVars *data = seq->effectdata;
- facf = data->factor;
+ fac = data->factor;
if (out->rect_float) {
float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
do_blend_effect_float(
- facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
+ fac, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
do_blend_effect_byte(
- facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
+ fac, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out);
}
}
@@ -1930,7 +1378,7 @@ static float in_band(float width, float dist, int side, int dir)
return alpha;
}
-static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float facf0)
+static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float fac)
{
float posx, posy, hyp, hyp2, angle, hwidth, b1, b2, b3, pointdist;
/* some future stuff */
@@ -1950,18 +1398,18 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
angle = wipezone->angle;
if (wipe->forward) {
- posx = facf0 * xo;
- posy = facf0 * yo;
+ posx = fac * xo;
+ posy = fac * yo;
}
else {
- posx = xo - facf0 * xo;
- posy = yo - facf0 * yo;
+ posx = xo - fac * xo;
+ posy = yo - fac * yo;
}
switch (wipe->wipetype) {
case DO_SINGLE_WIPE:
- width = min_ii(wipezone->width, facf0 * yo);
- width = min_ii(width, yo - facf0 * yo);
+ width = min_ii(wipezone->width, fac * yo);
+ width = min_ii(width, yo - fac * yo);
if (angle == 0.0f) {
b1 = posy;
@@ -2000,7 +1448,7 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
case DO_DOUBLE_WIPE:
if (!wipe->forward) {
- facf0 = 1.0f - facf0; /* Go the other direction */
+ fac = 1.0f - fac; /* Go the other direction */
}
width = wipezone->width; /* calculate the blur width */
@@ -2053,9 +1501,9 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
* temp3: angle of low side of blur
* temp4: angle of high side of blur
*/
- output = 1.0f - facf0;
+ output = 1.0f - fac;
widthf = wipe->edgeWidth * 2.0f * (float)M_PI;
- temp1 = 2.0f * (float)M_PI * facf0;
+ temp1 = 2.0f * (float)M_PI * fac;
if (wipe->forward) {
temp1 = 2.0f * (float)M_PI - temp1;
@@ -2076,12 +1524,12 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
}
if (wipe->forward) {
- temp3 = temp1 - (widthf * 0.5f) * facf0;
- temp4 = temp1 + (widthf * 0.5f) * (1 - facf0);
+ temp3 = temp1 - (widthf * 0.5f) * fac;
+ temp4 = temp1 + (widthf * 0.5f) * (1 - fac);
}
else {
- temp3 = temp1 - (widthf * 0.5f) * (1 - facf0);
- temp4 = temp1 + (widthf * 0.5f) * facf0;
+ temp3 = temp1 - (widthf * 0.5f) * (1 - fac);
+ temp4 = temp1 + (widthf * 0.5f) * fac;
}
if (temp3 < 0) {
temp3 = 0;
@@ -2118,13 +1566,13 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
}
if (!wipe->forward) {
- facf0 = 1 - facf0;
+ fac = 1 - fac;
}
width = wipezone->width;
hwidth = width * 0.5f;
- temp1 = (halfx - (halfx)*facf0);
+ temp1 = (halfx - (halfx)*fac);
pointdist = hypotf(temp1, temp1);
temp2 = hypotf(halfx - x, halfy - y);
@@ -2175,8 +1623,7 @@ static void copy_wipe_effect(Sequence *dst, Sequence *src, const int UNUSED(flag
}
static void do_wipe_effect_byte(Sequence *seq,
- float facf0,
- float UNUSED(facf1),
+ float fac,
int x,
int y,
unsigned char *rect1,
@@ -2185,20 +1632,15 @@ static void do_wipe_effect_byte(Sequence *seq,
{
WipeZone wipezone;
WipeVars *wipe = (WipeVars *)seq->effectdata;
- int xo, yo;
- unsigned char *cp1, *cp2, *rt;
-
precalc_wipe_zone(&wipezone, wipe, x, y);
- cp1 = rect1;
- cp2 = rect2;
- rt = out;
+ unsigned char *cp1 = rect1;
+ unsigned char *cp2 = rect2;
+ unsigned char *rt = out;
- xo = x;
- yo = y;
- for (y = 0; y < yo; y++) {
- for (x = 0; x < xo; x++) {
- float check = check_zone(&wipezone, x, y, seq, facf0);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ float check = check_zone(&wipezone, x, y, seq, fac);
if (check) {
if (cp1) {
float rt1[4], rt2[4], tempc[4];
@@ -2246,31 +1688,20 @@ static void do_wipe_effect_byte(Sequence *seq,
}
}
-static void do_wipe_effect_float(Sequence *seq,
- float facf0,
- float UNUSED(facf1),
- int x,
- int y,
- float *rect1,
- float *rect2,
- float *out)
+static void do_wipe_effect_float(
+ Sequence *seq, float fac, int x, int y, float *rect1, float *rect2, float *out)
{
WipeZone wipezone;
WipeVars *wipe = (WipeVars *)seq->effectdata;
- int xo, yo;
- float *rt1, *rt2, *rt;
-
precalc_wipe_zone(&wipezone, wipe, x, y);
- rt1 = rect1;
- rt2 = rect2;
- rt = out;
+ float *rt1 = rect1;
+ float *rt2 = rect2;
+ float *rt = out;
- xo = x;
- yo = y;
- for (y = 0; y < yo; y++) {
- for (x = 0; x < xo; x++) {
- float check = check_zone(&wipezone, x, y, seq, facf0);
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ float check = check_zone(&wipezone, x, y, seq, fac);
if (check) {
if (rt1) {
rt[0] = rt1[0] * check + rt2[0] * (1 - check);
@@ -2314,8 +1745,7 @@ static void do_wipe_effect_float(Sequence *seq,
static ImBuf *do_wipe_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -2324,8 +1754,7 @@ static ImBuf *do_wipe_effect(const SeqRenderData *context,
if (out->rect_float) {
do_wipe_effect_float(seq,
- facf0,
- facf1,
+ fac,
context->rectx,
context->recty,
ibuf1->rect_float,
@@ -2334,8 +1763,7 @@ static ImBuf *do_wipe_effect(const SeqRenderData *context,
}
else {
do_wipe_effect_byte(seq,
- facf0,
- facf1,
+ fac,
context->rectx,
context->recty,
(unsigned char *)ibuf1->rect,
@@ -2442,8 +1870,7 @@ static void transform_image(int x,
static void do_transform_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *UNUSED(ibuf2),
ImBuf *UNUSED(ibuf3),
@@ -2731,8 +2158,7 @@ static void copy_glow_effect(Sequence *dst, Sequence *src, const int UNUSED(flag
static void do_glow_effect_byte(Sequence *seq,
int render_size,
- float facf0,
- float UNUSED(facf1),
+ float fac,
int x,
int y,
unsigned char *rect1,
@@ -2749,7 +2175,7 @@ static void do_glow_effect_byte(Sequence *seq,
IMB_buffer_float_premultiply(inbuf, x, y);
RVIsolateHighlights_float(
- inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp);
+ inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * fac, glow->fClamp);
RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality);
if (!glow->bNoComp) {
RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y);
@@ -2765,8 +2191,7 @@ static void do_glow_effect_byte(Sequence *seq,
static void do_glow_effect_float(Sequence *seq,
int render_size,
- float facf0,
- float UNUSED(facf1),
+ float fac,
int x,
int y,
float *rect1,
@@ -2778,7 +2203,7 @@ static void do_glow_effect_float(Sequence *seq,
GlowVars *glow = (GlowVars *)seq->effectdata;
RVIsolateHighlights_float(
- inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp);
+ inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * fac, glow->fClamp);
RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality);
if (!glow->bNoComp) {
RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y);
@@ -2788,8 +2213,7 @@ static void do_glow_effect_float(Sequence *seq,
static ImBuf *do_glow_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -2801,8 +2225,7 @@ static ImBuf *do_glow_effect(const SeqRenderData *context,
if (out->rect_float) {
do_glow_effect_float(seq,
render_size,
- facf0,
- facf1,
+ fac,
context->rectx,
context->recty,
ibuf1->rect_float,
@@ -2812,8 +2235,7 @@ static ImBuf *do_glow_effect(const SeqRenderData *context,
else {
do_glow_effect_byte(seq,
render_size,
- facf0,
- facf1,
+ fac,
context->rectx,
context->recty,
(unsigned char *)ibuf1->rect,
@@ -2855,7 +2277,7 @@ static void copy_solid_color(Sequence *dst, Sequence *src, const int UNUSED(flag
dst->effectdata = MEM_dupallocN(src->effectdata);
}
-static int early_out_color(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_color(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_NO_INPUT;
}
@@ -2863,8 +2285,7 @@ static int early_out_color(Sequence *UNUSED(seq), float UNUSED(facf0), float UNU
static ImBuf *do_solid_color(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -2873,72 +2294,44 @@ static ImBuf *do_solid_color(const SeqRenderData *context,
SolidColorVars *cv = (SolidColorVars *)seq->effectdata;
- unsigned char *rect;
- float *rect_float;
- int x; /*= context->rectx;*/ /*UNUSED*/
- int y; /*= context->recty;*/ /*UNUSED*/
+ int x = out->x;
+ int y = out->y;
if (out->rect) {
- unsigned char col0[3];
- unsigned char col1[3];
-
- col0[0] = facf0 * cv->col[0] * 255;
- col0[1] = facf0 * cv->col[1] * 255;
- col0[2] = facf0 * cv->col[2] * 255;
+ unsigned char color[4];
+ color[0] = cv->col[0] * 255;
+ color[1] = cv->col[1] * 255;
+ color[2] = cv->col[2] * 255;
+ color[3] = 255;
- col1[0] = facf1 * cv->col[0] * 255;
- col1[1] = facf1 * cv->col[1] * 255;
- col1[2] = facf1 * cv->col[2] * 255;
+ unsigned char *rect = (unsigned char *)out->rect;
- rect = (unsigned char *)out->rect;
-
- for (y = 0; y < out->y; y++) {
- for (x = 0; x < out->x; x++, rect += 4) {
- rect[0] = col0[0];
- rect[1] = col0[1];
- rect[2] = col0[2];
- rect[3] = 255;
- }
- y++;
- if (y < out->y) {
- for (x = 0; x < out->x; x++, rect += 4) {
- rect[0] = col1[0];
- rect[1] = col1[1];
- rect[2] = col1[2];
- rect[3] = 255;
- }
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rect[0] = color[0];
+ rect[1] = color[1];
+ rect[2] = color[2];
+ rect[3] = color[3];
+ rect += 4;
}
}
}
else if (out->rect_float) {
- float col0[3];
- float col1[3];
-
- col0[0] = facf0 * cv->col[0];
- col0[1] = facf0 * cv->col[1];
- col0[2] = facf0 * cv->col[2];
+ float color[4];
+ color[0] = cv->col[0];
+ color[1] = cv->col[1];
+ color[2] = cv->col[2];
+ color[3] = 255;
- col1[0] = facf1 * cv->col[0];
- col1[1] = facf1 * cv->col[1];
- col1[2] = facf1 * cv->col[2];
+ float *rect_float = out->rect_float;
- rect_float = out->rect_float;
-
- for (y = 0; y < out->y; y++) {
- for (x = 0; x < out->x; x++, rect_float += 4) {
- rect_float[0] = col0[0];
- rect_float[1] = col0[1];
- rect_float[2] = col0[2];
- rect_float[3] = 1.0;
- }
- y++;
- if (y < out->y) {
- for (x = 0; x < out->x; x++, rect_float += 4) {
- rect_float[0] = col1[0];
- rect_float[1] = col1[1];
- rect_float[2] = col1[2];
- rect_float[3] = 1.0;
- }
+ for (int i = 0; i < y; i++) {
+ for (int j = 0; j < x; j++) {
+ rect_float[0] = color[0];
+ rect_float[1] = color[1];
+ rect_float[2] = color[2];
+ rect_float[3] = color[3];
+ rect_float += 4;
}
}
}
@@ -2956,7 +2349,7 @@ static int num_inputs_multicam(void)
return 0;
}
-static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_NO_INPUT;
}
@@ -2964,8 +2357,7 @@ static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(facf0), float
static ImBuf *do_multicam(const SeqRenderData *context,
Sequence *seq,
float timeline_frame,
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *UNUSED(ibuf1),
ImBuf *UNUSED(ibuf2),
ImBuf *UNUSED(ibuf3))
@@ -3000,7 +2392,7 @@ static int num_inputs_adjustment(void)
return 0;
}
-static int early_out_adjustment(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_adjustment(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_NO_INPUT;
}
@@ -3044,8 +2436,7 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl
static ImBuf *do_adjustment(const SeqRenderData *context,
Sequence *seq,
float timeline_frame,
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *UNUSED(ibuf1),
ImBuf *UNUSED(ibuf2),
ImBuf *UNUSED(ibuf3))
@@ -3111,7 +2502,7 @@ static void copy_speed_effect(Sequence *dst, Sequence *src, const int UNUSED(fla
v->frameMap = NULL;
}
-static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_DO_EFFECT;
}
@@ -3243,8 +2634,7 @@ static float speed_effect_interpolation_ratio_get(Scene *scene,
static ImBuf *do_speed_effect(const SeqRenderData *context,
Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -3255,10 +2645,10 @@ static ImBuf *do_speed_effect(const SeqRenderData *context,
if (s->flags & SEQ_SPEED_USE_INTERPOLATION) {
out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);
- facf0 = facf1 = speed_effect_interpolation_ratio_get(context->scene, seq, timeline_frame);
+ fac = speed_effect_interpolation_ratio_get(context->scene, seq, timeline_frame);
/* Current frame is ibuf1, next frame is ibuf2. */
out = seq_render_effect_execute_threaded(
- &cross_effect, context, NULL, timeline_frame, facf0, facf1, ibuf1, ibuf2, ibuf3);
+ &cross_effect, context, NULL, timeline_frame, fac, ibuf1, ibuf2, ibuf3);
return out;
}
@@ -3271,8 +2661,7 @@ static ImBuf *do_speed_effect(const SeqRenderData *context,
static void do_overdrop_effect(const SeqRenderData *context,
Sequence *UNUSED(seq),
float UNUSED(timeline_frame),
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *UNUSED(ibuf3),
@@ -3289,8 +2678,8 @@ static void do_overdrop_effect(const SeqRenderData *context,
slice_get_float_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_drop_effect_float(facf0, facf1, x, y, rect1, rect2, rect_out);
- do_alphaover_effect_float(facf0, facf1, x, y, rect1, rect2, rect_out);
+ do_drop_effect_float(fac, x, y, rect1, rect2, rect_out);
+ do_alphaover_effect_float(fac, x, y, rect1, rect2, rect_out);
}
else {
unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
@@ -3298,8 +2687,8 @@ static void do_overdrop_effect(const SeqRenderData *context,
slice_get_byte_buffers(
context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out);
- do_drop_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out);
- do_alphaover_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out);
+ do_drop_effect_byte(fac, x, y, rect1, rect2, rect_out);
+ do_alphaover_effect_byte(fac, x, y, rect1, rect2, rect_out);
}
}
@@ -3337,7 +2726,7 @@ static void copy_gaussian_blur_effect(Sequence *dst, Sequence *src, const int UN
dst->effectdata = MEM_dupallocN(src->effectdata);
}
-static int early_out_gaussian_blur(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_gaussian_blur(Sequence *seq, float UNUSED(fac))
{
GaussianBlurVars *data = seq->effectdata;
if (data->size_x == 0.0f && data->size_y == 0) {
@@ -3691,8 +3080,7 @@ static void *render_effect_execute_do_y_thread(void *thread_data_v)
static ImBuf *do_gaussian_blur_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *UNUSED(ibuf2),
ImBuf *UNUSED(ibuf3))
@@ -3839,7 +3227,7 @@ static int num_inputs_text(void)
return 0;
}
-static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_text(Sequence *seq, float UNUSED(fac))
{
TextVars *data = seq->effectdata;
if (data->text[0] == 0 || data->text_size < 1.0f ||
@@ -3853,8 +3241,7 @@ static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1
static ImBuf *do_text_effect(const SeqRenderData *context,
Sequence *seq,
float UNUSED(timeline_frame),
- float UNUSED(facf0),
- float UNUSED(facf1),
+ float UNUSED(fac),
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -4000,52 +3387,47 @@ static void free_effect_default(Sequence *seq, const bool UNUSED(do_id_user))
MEM_SAFE_FREE(seq->effectdata);
}
-static int early_out_noop(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1))
+static int early_out_noop(Sequence *UNUSED(seq), float UNUSED(fac))
{
return EARLY_DO_EFFECT;
}
-static int early_out_fade(Sequence *UNUSED(seq), float facf0, float facf1)
+static int early_out_fade(Sequence *UNUSED(seq), float fac)
{
- if (facf0 == 0.0f && facf1 == 0.0f) {
+ if (fac == 0.0f) {
return EARLY_USE_INPUT_1;
}
- if (facf0 == 1.0f && facf1 == 1.0f) {
+ if (fac == 1.0f) {
return EARLY_USE_INPUT_2;
}
return EARLY_DO_EFFECT;
}
-static int early_out_mul_input2(Sequence *UNUSED(seq), float facf0, float facf1)
+static int early_out_mul_input2(Sequence *UNUSED(seq), float fac)
{
- if (facf0 == 0.0f && facf1 == 0.0f) {
+ if (fac == 0.0f) {
return EARLY_USE_INPUT_1;
}
return EARLY_DO_EFFECT;
}
-static int early_out_mul_input1(Sequence *UNUSED(seq), float facf0, float facf1)
+static int early_out_mul_input1(Sequence *UNUSED(seq), float fac)
{
- if (facf0 == 0.0f && facf1 == 0.0f) {
+ if (fac == 0.0f) {
return EARLY_USE_INPUT_2;
}
return EARLY_DO_EFFECT;
}
-static void get_default_fac_noop(Sequence *UNUSED(seq),
- float UNUSED(timeline_frame),
- float *facf0,
- float *facf1)
+static void get_default_fac_noop(Sequence *UNUSED(seq), float UNUSED(timeline_frame), float *fac)
{
- *facf0 = *facf1 = 1.0;
+ *fac = 1.0f;
}
-static void get_default_fac_fade(Sequence *seq, float timeline_frame, float *facf0, float *facf1)
+static void get_default_fac_fade(Sequence *seq, float timeline_frame, float *fac)
{
- *facf0 = (float)(timeline_frame - seq->startdisp);
- *facf1 = (float)(*facf0 + 0.5f);
- *facf0 /= seq->len;
- *facf1 /= seq->len;
+ *fac = (float)(timeline_frame - seq->startdisp);
+ *fac /= seq->len;
}
static struct ImBuf *init_execution(const SeqRenderData *context,
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index a391deaccb4..371e4b7becd 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -683,7 +683,7 @@ typedef struct RenderEffectInitData {
struct SeqEffectHandle *sh;
const SeqRenderData *context;
Sequence *seq;
- float timeline_frame, facf0, facf1;
+ float timeline_frame, fac;
ImBuf *ibuf1, *ibuf2, *ibuf3;
ImBuf *out;
@@ -693,7 +693,7 @@ typedef struct RenderEffectThread {
struct SeqEffectHandle *sh;
const SeqRenderData *context;
Sequence *seq;
- float timeline_frame, facf0, facf1;
+ float timeline_frame, fac;
ImBuf *ibuf1, *ibuf2, *ibuf3;
ImBuf *out;
@@ -712,8 +712,7 @@ static void render_effect_execute_init_handle(void *handle_v,
handle->context = init_data->context;
handle->seq = init_data->seq;
handle->timeline_frame = init_data->timeline_frame;
- handle->facf0 = init_data->facf0;
- handle->facf1 = init_data->facf1;
+ handle->fac = init_data->fac;
handle->ibuf1 = init_data->ibuf1;
handle->ibuf2 = init_data->ibuf2;
handle->ibuf3 = init_data->ibuf3;
@@ -730,8 +729,7 @@ static void *render_effect_execute_do_thread(void *thread_data_v)
thread_data->sh->execute_slice(thread_data->context,
thread_data->seq,
thread_data->timeline_frame,
- thread_data->facf0,
- thread_data->facf1,
+ thread_data->fac,
thread_data->ibuf1,
thread_data->ibuf2,
thread_data->ibuf3,
@@ -746,8 +744,7 @@ ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
const SeqRenderData *context,
Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
ImBuf *ibuf1,
ImBuf *ibuf2,
ImBuf *ibuf3)
@@ -759,8 +756,7 @@ ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
init_data.context = context;
init_data.seq = seq;
init_data.timeline_frame = timeline_frame;
- init_data.facf0 = facf0;
- init_data.facf1 = facf1;
+ init_data.fac = fac;
init_data.ibuf1 = ibuf1;
init_data.ibuf2 = ibuf2;
init_data.ibuf3 = ibuf3;
@@ -781,7 +777,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
float timeline_frame)
{
Scene *scene = context->scene;
- float fac, facf;
+ float fac;
int early_out;
int i;
struct SeqEffectHandle sh = SEQ_effect_handle_get(seq);
@@ -803,24 +799,23 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
}
if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) {
- sh.get_default_fac(seq, timeline_frame, &fac, &facf);
- facf = fac;
+ sh.get_default_fac(seq, timeline_frame, &fac);
}
else {
fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL);
if (fcu) {
- fac = facf = evaluate_fcurve(fcu, timeline_frame);
+ fac = evaluate_fcurve(fcu, timeline_frame);
}
else {
- fac = facf = seq->effect_fader;
+ fac = seq->effect_fader;
}
}
- early_out = sh.early_out(seq, fac, facf);
+ early_out = sh.early_out(seq, fac);
switch (early_out) {
case EARLY_NO_INPUT:
- out = sh.execute(context, seq, timeline_frame, fac, facf, NULL, NULL, NULL);
+ out = sh.execute(context, seq, timeline_frame, fac, NULL, NULL, NULL);
break;
case EARLY_DO_EFFECT:
for (i = 0; i < 3; i++) {
@@ -839,10 +834,10 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context,
if (ibuf[0] && (ibuf[1] || SEQ_effect_get_num_inputs(seq->type) == 1)) {
if (sh.multithreaded) {
out = seq_render_effect_execute_threaded(
- &sh, context, seq, timeline_frame, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
+ &sh, context, seq, timeline_frame, fac, ibuf[0], ibuf[1], ibuf[2]);
}
else {
- out = sh.execute(context, seq, timeline_frame, fac, facf, ibuf[0], ibuf[1], ibuf[2]);
+ out = sh.execute(context, seq, timeline_frame, fac, ibuf[0], ibuf[1], ibuf[2]);
}
}
break;
@@ -1774,8 +1769,8 @@ static bool seq_must_swap_input_in_blend_mode(Sequence *seq)
static int seq_get_early_out_for_blend_mode(Sequence *seq)
{
struct SeqEffectHandle sh = seq_effect_get_sequence_blend(seq);
- float facf = seq->blend_opacity / 100.0f;
- int early_out = sh.early_out(seq, facf, facf);
+ float fac = seq->blend_opacity / 100.0f;
+ int early_out = sh.early_out(seq, fac);
if (ELEM(early_out, EARLY_DO_EFFECT, EARLY_NO_INPUT)) {
return early_out;
@@ -1797,25 +1792,25 @@ static ImBuf *seq_render_strip_stack_apply_effect(
{
ImBuf *out;
struct SeqEffectHandle sh = seq_effect_get_sequence_blend(seq);
- float facf = seq->blend_opacity / 100.0f;
+ float fac = seq->blend_opacity / 100.0f;
int swap_input = seq_must_swap_input_in_blend_mode(seq);
if (swap_input) {
if (sh.multithreaded) {
out = seq_render_effect_execute_threaded(
- &sh, context, seq, timeline_frame, facf, facf, ibuf2, ibuf1, NULL);
+ &sh, context, seq, timeline_frame, fac, ibuf2, ibuf1, NULL);
}
else {
- out = sh.execute(context, seq, timeline_frame, facf, facf, ibuf2, ibuf1, NULL);
+ out = sh.execute(context, seq, timeline_frame, fac, ibuf2, ibuf1, NULL);
}
}
else {
if (sh.multithreaded) {
out = seq_render_effect_execute_threaded(
- &sh, context, seq, timeline_frame, facf, facf, ibuf1, ibuf2, NULL);
+ &sh, context, seq, timeline_frame, fac, ibuf1, ibuf2, NULL);
}
else {
- out = sh.execute(context, seq, timeline_frame, facf, facf, ibuf1, ibuf2, NULL);
+ out = sh.execute(context, seq, timeline_frame, fac, ibuf1, ibuf2, NULL);
}
}
diff --git a/source/blender/sequencer/intern/render.h b/source/blender/sequencer/intern/render.h
index a0cdf24d84b..eb1f71769a6 100644
--- a/source/blender/sequencer/intern/render.h
+++ b/source/blender/sequencer/intern/render.h
@@ -54,8 +54,7 @@ struct ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh,
const struct SeqRenderData *context,
struct Sequence *seq,
float timeline_frame,
- float facf0,
- float facf1,
+ float fac,
struct ImBuf *ibuf1,
struct ImBuf *ibuf2,
struct ImBuf *ibuf3);
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index 908a5bd4f79..e4120a3cf95 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -140,6 +140,7 @@ Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int
seq->pitch = 1.0f;
seq->scene_sound = NULL;
seq->type = type;
+ seq->blend_mode = SEQ_TYPE_ALPHAOVER;
seq->strip = seq_strip_alloc(type);
seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format");
@@ -418,6 +419,10 @@ void SEQ_meta_stack_free(Editing *ed, MetaStack *ms)
MetaStack *SEQ_meta_stack_active_get(const Editing *ed)
{
+ if (ed == NULL) {
+ return NULL;
+ }
+
return ed->metastack.last;
}
diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c
index a4b537b9074..f342765eec9 100644
--- a/source/blender/sequencer/intern/strip_add.c
+++ b/source/blender/sequencer/intern/strip_add.c
@@ -141,7 +141,6 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SCENE);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
seq->scene = load_data->scene;
seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1;
id_us_ensure_real((ID *)load_data->scene);
@@ -154,7 +153,6 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MOVIECLIP);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
seq->clip = load_data->clip;
seq->len = BKE_movieclip_get_duration(load_data->clip);
id_us_ensure_real((ID *)load_data->clip);
@@ -167,7 +165,6 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MASK);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
seq->mask = load_data->mask;
seq->len = BKE_mask_get_duration(load_data->mask);
id_us_ensure_real((ID *)load_data->mask);
@@ -191,9 +188,6 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa
if (SEQ_effect_get_num_inputs(seq->type) == 1) {
seq->blend_mode = seq->seq1->blend_mode;
}
- else {
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
- }
if (!load_data->effect.seq1) {
seq->len = 1; /* Effect is generator, set non zero length. */
@@ -250,7 +244,6 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
{
Sequence *seq = SEQ_sequence_alloc(
seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_IMAGE);
- seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* so alpha adjustment fade to the strip below */
seq->len = load_data->image.len;
Strip *strip = seq->strip;
strip->stripdata = MEM_callocN(load_data->image.len * sizeof(StripElem), "stripelem");
@@ -482,8 +475,6 @@ Sequence *SEQ_add_movie_strip(
}
}
- seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* so alpha adjustment fade to the strip below */
-
if (anim_arr[0] != NULL) {
seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN);
diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c
index 912ba9d41db..cf303e5be4e 100644
--- a/source/blender/sequencer/intern/strip_edit.c
+++ b/source/blender/sequencer/intern/strip_edit.c
@@ -489,21 +489,27 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
ListBase right_strips = {NULL, NULL};
SEQ_sequence_base_dupli_recursive(scene, scene, &right_strips, &left_strips, SEQ_DUPE_ALL, 0);
- /* Split strips. */
Sequence *left_seq = left_strips.first;
Sequence *right_seq = right_strips.first;
- Sequence *return_seq = right_strips.first;
+ Sequence *return_seq = NULL;
- /* Strips can't be tagged while in detached `seqbase`. Collect all strips which needs to be
- * deleted and delay tagging until they are moved back to `seqbase` in `Editing`. */
- SeqCollection *strips_to_delete = SEQ_collection_create(__func__);
+ /* Move strips from detached `ListBase`, otherwise they can't be flagged for removal,
+ * SEQ_time_update_sequence can fail to update meta strips and they can't be renamed.
+ * This is because these functions check all strips in `Editing` to manage relationships. */
+ BLI_movelisttolist(seqbase, &left_strips);
+ BLI_movelisttolist(seqbase, &right_strips);
+ /* Split strips. */
while (left_seq && right_seq) {
if (left_seq->startdisp >= timeline_frame) {
- SEQ_collection_append_strip(left_seq, strips_to_delete);
+ SEQ_edit_flag_for_removal(scene, seqbase, left_seq);
}
if (right_seq->enddisp <= timeline_frame) {
- SEQ_collection_append_strip(right_seq, strips_to_delete);
+ SEQ_edit_flag_for_removal(scene, seqbase, right_seq);
+ }
+ else if (return_seq == NULL) {
+ /* Store return value - pointer to strip that will not be removed. */
+ return_seq = right_seq;
}
seq_edit_split_handle_strip_offsets(
@@ -512,20 +518,14 @@ Sequence *SEQ_edit_strip_split(Main *bmain,
right_seq = right_seq->next;
}
- seq = right_strips.first;
- BLI_movelisttolist(seqbase, &left_strips);
- BLI_movelisttolist(seqbase, &right_strips);
+ SEQ_edit_remove_flagged_sequences(scene, seqbase);
- for (; seq; seq = seq->next) {
- SEQ_ensure_unique_name(seq, scene);
+ /* Rename duplicated strips. */
+ Sequence *seq_rename = return_seq;
+ for (; seq_rename; seq_rename = seq_rename->next) {
+ SEQ_ensure_unique_name(seq_rename, scene);
}
- Sequence *seq_delete;
- SEQ_ITERATOR_FOREACH (seq_delete, strips_to_delete) {
- SEQ_edit_flag_for_removal(scene, seqbase, seq_delete);
- }
- SEQ_edit_remove_flagged_sequences(scene, seqbase);
- SEQ_collection_free(strips_to_delete);
return return_seq;
}
diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c
index 3228277ce72..31ee20cb6ca 100644
--- a/source/blender/sequencer/intern/strip_time.c
+++ b/source/blender/sequencer/intern/strip_time.c
@@ -193,6 +193,10 @@ static void seq_time_update_meta_strip(Scene *scene, Sequence *seq_meta)
void SEQ_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta)
{
+ if (seq_meta == NULL) {
+ return;
+ }
+
seq_time_update_meta_strip(scene, seq_meta);
/* Prevent meta-strip to move in timeline. */
diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c
index cd779b0b0c7..156c6ac4cb9 100644
--- a/source/blender/sequencer/intern/utils.c
+++ b/source/blender/sequencer/intern/utils.c
@@ -446,7 +446,7 @@ Sequence *SEQ_get_meta_by_seqbase(ListBase *seqbase_main, ListBase *meta_seqbase
{
SeqCollection *strips = SEQ_query_all_strips_recursive(seqbase_main);
- Sequence *seq;
+ Sequence *seq = NULL;
SEQ_ITERATOR_FOREACH (seq, strips) {
if (seq->type == SEQ_TYPE_META && &seq->seqbase == meta_seqbase) {
break;
diff --git a/source/blender/simulation/intern/SIM_mass_spring.cpp b/source/blender/simulation/intern/SIM_mass_spring.cpp
index f9a22276363..36513690584 100644
--- a/source/blender/simulation/intern/SIM_mass_spring.cpp
+++ b/source/blender/simulation/intern/SIM_mass_spring.cpp
@@ -1295,8 +1295,7 @@ int SIM_cloth_solve(
BKE_sim_debug_data_clear_category("collision");
if (!clmd->solver_result) {
- clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult),
- "cloth solver result");
+ clmd->solver_result = MEM_cnew<ClothSolverResult>("cloth solver result");
}
cloth_clear_result(clmd);
diff --git a/source/blender/simulation/intern/hair_volume.cpp b/source/blender/simulation/intern/hair_volume.cpp
index e47593eda05..d4550eec5d6 100644
--- a/source/blender/simulation/intern/hair_volume.cpp
+++ b/source/blender/simulation/intern/hair_volume.cpp
@@ -1160,7 +1160,7 @@ HairGrid *SIM_hair_volume_create_vertex_grid(float cellsize,
}
size = hair_grid_size(res);
- grid = (HairGrid *)MEM_callocN(sizeof(HairGrid), "hair grid");
+ grid = MEM_cnew<HairGrid>("hair grid");
grid->res[0] = res[0];
grid->res[1] = res[1];
grid->res[2] = res[2];
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index e1017c4236e..f2459b7fdc9 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -884,7 +884,7 @@ void wm_drags_draw(bContext *C, wmWindow *win)
bScreen *screen = CTX_wm_screen(C);
/* To start with, use the area and region under the mouse cursor, just like event handling. The
* operator context may still override it. */
- ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, UNPACK2(xy));
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, xy);
ARegion *region = ED_area_find_region_xy_visual(area, RGN_TYPE_ANY, xy);
/* Will be overridden and unset eventually. */
BLI_assert(!CTX_wm_area(C) && !CTX_wm_region(C));
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 1b6df9fb0db..ef644da5578 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -1861,8 +1861,7 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const
CTX_wm_area_set(C, area);
if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) {
- region = BKE_area_find_region_xy(
- area, handler->context.region_type, event->xy[0], event->xy[1]);
+ region = BKE_area_find_region_xy(area, handler->context.region_type, event->xy);
if (region) {
handler->context.region = region;
}
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 2f87e5789fe..957ec7d800d 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -562,6 +562,13 @@ void WM_exit_ex(bContext *C, const bool do_python)
BKE_blender_free(); /* blender.c, does entire library and spacetypes */
// BKE_material_copybuf_free();
+
+ /* Free the GPU subdivision data after the database to ensure that subdivision structs used by
+ * the modifiers were garbage collected. */
+ if (opengl_is_init) {
+ DRW_subdiv_free();
+ }
+
ANIM_fcurves_copybuf_free();
ANIM_drivers_copybuf_free();
ANIM_driver_vars_copybuf_free();
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index a5887fc07b3..ebd6719d54d 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -184,6 +184,9 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
prop = RNA_def_boolean(
ot->srna, "filter_usd", (filter & FILE_TYPE_USD) != 0, "Filter USD files", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(
+ ot->srna, "filter_obj", (filter & FILE_TYPE_OBJECT_IO) != 0, "Filter OBJ files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"filter_volume",
(filter & FILE_TYPE_VOLUME) != 0,
diff --git a/source/tools b/source/tools
-Subproject b22d19e47f4d0353082f3d9f30ee8d244c5266d
+Subproject 26bc78162ec89f21453ce3ded7b999bc6649f32